TEUCHOS_UNIT_TEST( EpetraLinearOp, rectangular )
{
  using Teuchos::null;
  using Teuchos::inOutArg;
  using Teuchos::updateSuccess;

  const RCP<const Epetra_Comm> comm = getEpetraComm();
  const int numProcs = comm->NumProc();

  const int numLocalRows = g_localDim;
  const int numRows = numLocalRows * comm->NumProc();
  const int numCols = numLocalRows / 2;

  const RCP<Epetra_CrsMatrix> epetraCrsM = getEpetraMatrix(numRows, numCols);

  const RCP<const LinearOpBase<double> > epetraOp = epetraLinearOp(epetraCrsM);

  LinearOpTester<double> linearOpTester;
  linearOpTester.check_adjoint(numProcs == 1);
  linearOpTester.show_all_tests(g_show_all_tests);
  linearOpTester.dump_all(g_dumpAll);
  updateSuccess(linearOpTester.check(*epetraOp, inOutArg(out)), success);

  // NOTE: Above, it would seem the Epetra_CrsMatrix::Apply(...) does not work
  // when doing and adjoint where the RowMap has empty processes.

}
bool Thyra::test_single_belos_thyra_solver(
  const std::string                       matrixFile
  ,const bool                             testTranspose
  ,const bool                             usePreconditioner
  ,const int                              numRhs
  ,const int                              numRandomVectors
  ,const double                           maxFwdError
  ,const double                           maxResid
  ,const double                           maxSolutionError
  ,const bool                             showAllTests
  ,const bool                             dumpAll
  ,Teuchos::ParameterList                 *belosLOWSFPL
  ,Teuchos::ParameterList                 *precPL
  ,Teuchos::FancyOStream                  *out_arg
  )
{
  using Teuchos::rcp;
  using Teuchos::OSTab;
  bool result, success = true;

  Teuchos::RCP<Teuchos::FancyOStream> out = Teuchos::rcp(out_arg,false);

  try {

#ifndef SUN_CXX

    if(out.get()) {
      *out << "\n***"
           << "\n*** Testing Thyra::BelosLinearOpWithSolveFactory (and Thyra::BelosLinearOpWithSolve)"
           << "\n***\n"
           << "\nEchoing input options:"
           << "\n  matrixFile             = " << matrixFile
           << "\n  testTranspose          = " << testTranspose
           << "\n  usePreconditioner      = " << usePreconditioner
           << "\n  numRhs                 = " << numRhs
           << "\n  numRandomVectors       = " << numRandomVectors
           << "\n  maxFwdError            = " << maxFwdError
           << "\n  maxResid               = " << maxResid
           << "\n  showAllTests           = " << showAllTests
           << "\n  dumpAll                = " << dumpAll
           << std::endl;
    }

    if(out.get()) *out << "\nA) Reading in an epetra matrix A from the file \'"<<matrixFile<<"\' ...\n";
  
    Epetra_SerialComm comm;
    Teuchos::RCP<Epetra_CrsMatrix> epetra_A;
    EpetraExt::readEpetraLinearSystem( matrixFile, comm, &epetra_A );

    Teuchos::RCP<const LinearOpBase<double> > A = epetraLinearOp(epetra_A);

    if(out.get() && dumpAll) *out << "\ndescribe(A) =\n" << describe(*A,Teuchos::VERB_EXTREME);

    if(out.get()) *out << "\nB) Creating a BelosLinearOpWithSolveFactory object opFactory ...\n";

    Teuchos::RCP<LinearOpWithSolveFactoryBase<double> >
      lowsFactory;
    {
      Teuchos::RCP<BelosLinearOpWithSolveFactory<double> >
        belosLowsFactory = Teuchos::rcp(new BelosLinearOpWithSolveFactory<double>());
      lowsFactory = belosLowsFactory;
    }

    if(out.get()) {
      *out << "\nlowsFactory.getValidParameters() before setting preconditioner factory:\n";
      lowsFactory->getValidParameters()->print(OSTab(out).o(),0,true,false);
    }

    if(usePreconditioner) {
#ifdef HAVE_BELOS_IFPACK
      if(out.get()) {
        *out << "\nSetting an Ifpack preconditioner factory ...\n";
      }
      RCP<PreconditionerFactoryBase<double> >
        precFactory = Teuchos::rcp(new IfpackPreconditionerFactory());
      if (precPL)
        precFactory->setParameterList(rcp(precPL,false));
      lowsFactory->setPreconditionerFactory(precFactory,"Ifpack");
#else
      TEUCHOS_TEST_FOR_EXCEPT(usePreconditioner);
#endif
    }
    
    if(out.get()) {
      *out << "\nlowsFactory.getValidParameters() after setting preconditioner factory:\n";
      lowsFactory->getValidParameters()->print(OSTab(out).o(),0,true,false);
      *out << "\nbelosLOWSFPL before setting parameters:\n";
      belosLOWSFPL->print(OSTab(out).o(),0,true);
    }

    lowsFactory->setParameterList(Teuchos::rcp(belosLOWSFPL,false));

    if(out.get()) {
      *out << "\nbelosLOWSFPL after setting parameters:\n";
      belosLOWSFPL->print(OSTab(out).o(),0,true);
    }

    if(out.get()) *out << "\nC) Creating a BelosLinearOpWithSolve object nsA from A ...\n";

    Teuchos::RCP<LinearOpWithSolveBase<double> > nsA = lowsFactory->createOp();
    Thyra::initializeOp<double>(*lowsFactory,  A, nsA.ptr());

    if(out.get()) *out << "\nD) Testing the LinearOpBase interface of nsA ...\n";

    LinearOpTester<double> linearOpTester;
    linearOpTester.check_adjoint(testTranspose);
    linearOpTester.num_rhs(numRhs);
    linearOpTester.num_random_vectors(numRandomVectors);
    linearOpTester.set_all_error_tol(maxFwdError);
    linearOpTester.set_all_warning_tol(1e-2*maxFwdError);
    linearOpTester.show_all_tests(showAllTests);
    linearOpTester.dump_all(dumpAll);
    Thyra::seed_randomize<double>(0);
    result = linearOpTester.check(*nsA,Teuchos::Ptr<Teuchos::FancyOStream>(out.get()));
    if(!result) success = false;

    if(out.get()) *out << "\nE) Testing the LinearOpWithSolveBase interface of nsA ...\n";
    
    LinearOpWithSolveTester<double> linearOpWithSolveTester;
    linearOpWithSolveTester.num_rhs(numRhs);
    linearOpWithSolveTester.turn_off_all_tests();
    linearOpWithSolveTester.check_forward_default(true);
    linearOpWithSolveTester.check_forward_residual(true);
    if(testTranspose) {
      linearOpWithSolveTester.check_adjoint_default(true);
      linearOpWithSolveTester.check_adjoint_residual(true);
    }
    else {
      linearOpWithSolveTester.check_adjoint_default(false);
      linearOpWithSolveTester.check_adjoint_residual(false);
    }
    linearOpWithSolveTester.set_all_solve_tol(maxResid);
    linearOpWithSolveTester.set_all_slack_error_tol(maxResid);
    linearOpWithSolveTester.set_all_slack_warning_tol(1e+1*maxResid);
    linearOpWithSolveTester.forward_default_residual_error_tol(2*maxResid);
    linearOpWithSolveTester.forward_default_solution_error_error_tol(maxSolutionError);
    linearOpWithSolveTester.adjoint_default_residual_error_tol(2*maxResid);
    linearOpWithSolveTester.adjoint_default_solution_error_error_tol(maxSolutionError);
    linearOpWithSolveTester.show_all_tests(showAllTests);
    linearOpWithSolveTester.dump_all(dumpAll);
    Thyra::seed_randomize<double>(0);
    result = linearOpWithSolveTester.check(*nsA,out.get());
    if(!result) success = false;

    if(out.get()) {
      *out << "\nbelosLOWSFPL after solving:\n";
      belosLOWSFPL->print(OSTab(out).o(),0,true);
    }
    
#else // SUN_CXX
    
    if(out.get()) *out << "\nTest failed since is was not even compiled since SUN_CXX was defined!\n";
    success = false;

#endif // SUN_CXX

  }
  catch( const std::exception &excpt ) {
    if(out.get()) *out << std::flush;
    std::cerr << "*** Caught standard exception : " << excpt.what() << std::endl;
    success = false;
  }
   
  return success;
    
}
Exemple #3
0
bool Thyra::test_single_aztecoo_thyra_solver(
    const std::string                       matrixFile
    ,const bool                             testTranspose
    ,const int                              numRandomVectors
    ,const double                           maxFwdError
    ,const double                           maxResid
    ,const double                           maxSolutionError
    ,const bool                             showAllTests
    ,const bool                             dumpAll
    ,Teuchos::ParameterList                 *aztecooLOWSFPL
    ,Teuchos::FancyOStream                  *out_arg
)
{
    using Teuchos::rcp;
    using Teuchos::RCP;
    using Teuchos::OSTab;
    typedef Teuchos::ParameterList::PrintOptions PLPrintOptions;
    bool result, success = true;

    RCP<Teuchos::FancyOStream>
    out = Teuchos::rcp(out_arg,false);

    try {

#ifndef SUN_CXX

        if(out.get()) {
            *out
                    << "\n***"
                    << "\n*** Testing Thyra::AztecOOLinearOpWithSolveFactory (and Thyra::AztecOOLinearOpWithSolve)"
                    << "\n***\n"
                    << "\nEchoing input options:"
                    << "\n  matrixFile             = " << matrixFile
                    << "\n  testTranspose          = " << testTranspose
                    << "\n  numRandomVectors       = " << numRandomVectors
                    << "\n  maxFwdError            = " << maxFwdError
                    << "\n  maxResid               = " << maxResid
                    << "\n  showAllTests           = " << showAllTests
                    << "\n  dumpAll                = " << dumpAll
                    << std::endl;
        }

        const bool useAztecPrec = (
                                      aztecooLOWSFPL
                                      &&
                                      aztecooLOWSFPL->sublist("Forward Solve")
                                      .sublist("AztecOO Settings")
                                      .get("Aztec Preconditioner","none")!="none"
                                  );

        if(out.get()) {
            if(useAztecPrec)
                *out << "\nUsing aztec preconditioning so we will not test adjoint solves using internal preconditioning ...\n";
        }

        if(out.get()) *out << "\nA) Reading in an epetra matrix A from the file \'"<<matrixFile<<"\' ...\n";

#ifdef HAVE_MPI
        Epetra_MpiComm comm(MPI_COMM_WORLD);
#else
        Epetra_SerialComm comm;
#endif
        RCP<Epetra_CrsMatrix> epetra_A;
        EpetraExt::readEpetraLinearSystem( matrixFile, comm, &epetra_A );

        RCP<const LinearOpBase<double> > A = Thyra::epetraLinearOp(epetra_A);

        if(out.get() && dumpAll) *out << "\ndescribe(A) =\n" << describe(*A,Teuchos::VERB_EXTREME);

        if(out.get()) *out << "\nB) Creating a AztecOOLinearOpWithSolveFactory object opFactory ...\n";

        RCP<LinearOpWithSolveFactoryBase<double> >
        lowsFactory = Teuchos::rcp(new AztecOOLinearOpWithSolveFactory());
        if(out.get()) {
            *out << "\nlowsFactory.getValidParameters() initially:\n";
            lowsFactory->getValidParameters()->print(OSTab(out).o(),PLPrintOptions().showTypes(true).showDoc(true));
        }
        aztecooLOWSFPL->sublist("Forward Solve").set("Tolerance",maxResid);
        aztecooLOWSFPL->sublist("Adjoint Solve").set("Tolerance",maxResid);
        if(showAllTests) {
            aztecooLOWSFPL->set("Output Every RHS",bool(true));
        }
        if(out.get()) {
            *out << "\naztecooLOWSFPL before setting parameters:\n";
            aztecooLOWSFPL->print(OSTab(out).o(),0,true);
        }
        if(aztecooLOWSFPL) lowsFactory->setParameterList(Teuchos::rcp(aztecooLOWSFPL,false));

        if(out.get()) *out << "\nC) Creating a AztecOOLinearOpWithSolve object nsA from A ...\n";

        RCP<LinearOpWithSolveBase<double> >
        nsA = lowsFactory->createOp();

        Thyra::initializeOp<double>(*lowsFactory, A, nsA.ptr());

        if(out.get()) *out << "\nD) Testing the LinearOpBase interface of nsA ...\n";

        LinearOpTester<double> linearOpTester;
        linearOpTester.check_adjoint(testTranspose);
        linearOpTester.num_random_vectors(numRandomVectors);
        linearOpTester.set_all_error_tol(maxFwdError);
        linearOpTester.set_all_warning_tol(1e-2*maxFwdError);
        linearOpTester.show_all_tests(showAllTests);
        linearOpTester.dump_all(dumpAll);
        Thyra::seed_randomize<double>(0);
        result = linearOpTester.check(*nsA,out());
        if(!result) success = false;

        if(out.get()) *out << "\nE) Testing the LinearOpWithSolveBase interface of nsA ...\n";

        LinearOpWithSolveTester<double> linearOpWithSolveTester;
        linearOpWithSolveTester.turn_off_all_tests();
        linearOpWithSolveTester.check_forward_default(true);
        linearOpWithSolveTester.check_forward_residual(true);
        if(testTranspose && useAztecPrec) {
            linearOpWithSolveTester.check_adjoint_default(true);
            linearOpWithSolveTester.check_adjoint_residual(true);
        }
        else {
            linearOpWithSolveTester.check_adjoint_default(false);
            linearOpWithSolveTester.check_adjoint_residual(false);
        }
        linearOpWithSolveTester.set_all_solve_tol(maxResid);
        linearOpWithSolveTester.set_all_slack_error_tol(maxResid);
        linearOpWithSolveTester.set_all_slack_warning_tol(10.0*maxResid);
        linearOpWithSolveTester.forward_default_residual_error_tol(2.5*maxResid);
        linearOpWithSolveTester.forward_default_solution_error_error_tol(maxSolutionError);
        linearOpWithSolveTester.adjoint_default_residual_error_tol(2.5*maxResid);
        linearOpWithSolveTester.adjoint_default_solution_error_error_tol(maxSolutionError);
        linearOpWithSolveTester.show_all_tests(showAllTests);
        linearOpWithSolveTester.dump_all(dumpAll);
        Thyra::seed_randomize<double>(0);
        result = linearOpWithSolveTester.check(*nsA,out.get());
        if(!result) success = false;

        if(out.get()) *out << "\nF) Uninitialize nsA, create preconditioner for diagonal scaled by 0.99 and then reinitialize nsA reusing the old preconditioner ...\n";

        // Scale the diagonal of the matrix and then create the preconditioner for it
        Thyra::uninitializeOp<double>(*lowsFactory, nsA.ptr());
        // Above is not required but a good idea since we are changing the matrix
        {
            Epetra_Vector diag(epetra_A->RowMap());
            epetra_A->ExtractDiagonalCopy(diag);
            diag.Scale(0.5);
            epetra_A->ReplaceDiagonalValues(diag);
        }
        Thyra::initializeOp<double>(*lowsFactory, A, nsA.ptr());

        // Scale the matrix back again and then reuse the preconditioner
        Thyra::uninitializeOp<double>(*lowsFactory, nsA.ptr());
        // Above is not required but a good idea since we are changing the matrix
        {
            Epetra_Vector diag(epetra_A->RowMap());
            epetra_A->ExtractDiagonalCopy(diag);
            diag.Scale(1.0/0.5);
            epetra_A->ReplaceDiagonalValues(diag);
        }
        initializeAndReuseOp<double>(*lowsFactory, A, nsA.ptr());

        if(out.get()) *out << "\nG) Testing the LinearOpWithSolveBase interface of nsA ...\n";

        Thyra::seed_randomize<double>(0);
        result = linearOpWithSolveTester.check(*nsA,out.get());
        if(!result) success = false;

        if(useAztecPrec) {

            if(out.get()) *out << "\nH) Reinitialize (A,A,PRECONDITIONER_INPUT_TYPE_AS_MATRIX) => nsA ...\n";

            initializeApproxPreconditionedOp<double>(*lowsFactory, A, A, nsA.ptr());

            if(out.get()) *out << "\nI) Testing the LinearOpWithSolveBase interface of nsA ...\n";

            Thyra::seed_randomize<double>(0);
            result = linearOpWithSolveTester.check(*nsA,out.get());
            if(!result) success = false;

            if(testTranspose && useAztecPrec) {
                linearOpWithSolveTester.check_adjoint_default(true);
                linearOpWithSolveTester.check_adjoint_residual(true);
            }
            else {
                linearOpWithSolveTester.check_adjoint_default(false);
                linearOpWithSolveTester.check_adjoint_residual(false);
            }

        }
        else {

            if(out.get()) *out << "\nSkipping testing steps H and I since we are not using aztec preconditioning and therefore will not test with an external preconditioner matrix!\n";

        }


        RCP<PreconditionerFactoryBase<double> >
        precFactory;

#ifdef HAVE_AZTECOO_IFPACK

        if(useAztecPrec) {

            if(testTranspose) {
                linearOpWithSolveTester.check_adjoint_default(true);
                linearOpWithSolveTester.check_adjoint_residual(true);
            }

            if(out.get()) *out << "\nJ) Create an ifpack preconditioner precA for A ...\n";

            precFactory = Teuchos::rcp(new IfpackPreconditionerFactory());

            if(out.get()) {
                *out << "\nprecFactory.description() = " << precFactory->description() << std::endl;
                *out << "\nprecFactory.getValidParameters() =\n";
                precFactory->getValidParameters()->print(OSTab(out).o(),0,true,false);
            }

            RCP<Teuchos::ParameterList>
            ifpackPFPL = Teuchos::rcp(new Teuchos::ParameterList("IfpackPreconditionerFactory"));
            ifpackPFPL->set("Prec Type","ILUT");
            ifpackPFPL->set("Overlap",int(1));
            if(out.get()) {
                *out << "\nifpackPFPL before setting parameters =\n";
                ifpackPFPL->print(OSTab(out).o(),0,true);
            }

            precFactory->setParameterList(ifpackPFPL);

            RCP<PreconditionerBase<double> >
            precA = precFactory->createPrec();
            Thyra::initializePrec<double>(*precFactory,A,&*precA);

            if(out.get()) {
                *out << "\nifpackPFPL after setting parameters =\n";
                ifpackPFPL->print(OSTab(out).o(),0,true);
                *out << "\nprecFactory.description() = " << precFactory->description() << std::endl;
            }

            if(out.get()) *out << "\nprecA.description() = " << precA->description() << std::endl;
            if(out.get() && dumpAll) *out << "\ndescribe(precA) =\n" << describe(*precA,Teuchos::VERB_EXTREME);

            if(out.get()) *out << "\nK) Reinitialize (A,precA->getUnspecifiedPrecOp(),PRECONDITIONER_INPUT_TYPE_AS_OPERATOR) => nsA ...\n";

            Thyra::initializePreconditionedOp<double>(*lowsFactory,A,precA,&*nsA);

            if(out.get()) *out << "\nL) Testing the LinearOpWithSolveBase interface of nsA ...\n";

            Thyra::seed_randomize<double>(0);
            result = linearOpWithSolveTester.check(*nsA,out.get());
            if(!result) success = false;

            if(testTranspose && useAztecPrec) {
                linearOpWithSolveTester.check_adjoint_default(true);
                linearOpWithSolveTester.check_adjoint_residual(true);
            }
            else {
                linearOpWithSolveTester.check_adjoint_default(false);
                linearOpWithSolveTester.check_adjoint_residual(false);
            }

        }
        else {

            if(out.get()) *out << "\nSkipping testing steps J, K, and L since we are not using aztec preconditioning and therefore will not test with an ifpack preconditioner!\n";

        }

#else // HAVE_AZTECOO_IFPACK

        if(out.get()) *out << "\nSkipping testing steps J, K, and L since they require ifpack and ifpack has not been enabled!\n";

#endif // HAVE_AZTECOO_IFPACK


        if(out.get()) *out << "\nM) Scale the epetra_A object by 2.5, and then reinitialize nsA with epetra_A ...\n";

        Thyra::uninitializeOp<double>(*lowsFactory, nsA.ptr());
        // Not required but a good idea since we are changing the matrix
        epetra_A->Scale(2.5);
        initializeOp<double>(*lowsFactory, A, nsA.ptr());

        if(out.get()) *out << "\nN) Testing the LinearOpWithSolveBase interface of nsA ...\n";

        Thyra::seed_randomize<double>(0);
        result = linearOpWithSolveTester.check(*nsA,out.get());
        if(!result) success = false;

        if(out.get()) *out << "\nO) Create a scaled (by 2.5) copy epetra_A2 of epetra_A, and then reinitialize nsA with epetra_A2 ...\n";

        RCP<Epetra_CrsMatrix>
        epetra_A2 = Teuchos::rcp(new Epetra_CrsMatrix(*epetra_A));
        epetra_A2->Scale(2.5);
        RCP<const LinearOpBase<double> >
        A2 = Thyra::epetraLinearOp(epetra_A2);
        initializeOp<double>(*lowsFactory, A2, nsA.ptr());
        // Note that it was okay not to uninitialize nsA first here since A, which
        // was used to initialize nsA last, was not changed and therefore the
        // state of nsA was fine throughout

        if(out.get()) *out << "\nP) Testing the LinearOpWithSolveBase interface of nsA ...\n";

        Thyra::seed_randomize<double>(0);
        result = linearOpWithSolveTester.check(*nsA,out.get());
        if(!result) success = false;

        if(!useAztecPrec) {

            if(out.get()) *out << "\nQ) Create an implicitly scaled (by 2.5) and transposed matrix A3 = scale(2.5,transpose(A)) and initialize nsA2 ...\n";

            RCP<const LinearOpBase<double> >
            A3 = scale<double>(2.5,transpose<double>(A));
            RCP<LinearOpWithSolveBase<double> >
            nsA2 = linearOpWithSolve(*lowsFactory,A3);

            if(out.get()) *out << "\nR) Testing the LinearOpWithSolveBase interface of nsA2 ...\n";

            Thyra::seed_randomize<double>(0);
            result = linearOpWithSolveTester.check(*nsA2,out.get());
            if(!result) success = false;

            if(out.get()) *out << "\nS) Testing that LinearOpBase interfaces of transpose(nsA) == nsA2 ...\n";

            result = linearOpTester.compare(
                         *transpose(Teuchos::rcp_implicit_cast<const LinearOpBase<double> >(nsA)),*nsA2
                         ,out()
                     );
            if(!result) success = false;

        }
        else {

            if(out.get()) *out << "\nSkipping testing steps Q, R, and S because we are using internal AztecOO preconditioners!\n";

        }

        if(out.get()) *out << "\nT) Running example use cases ...\n";

        nonExternallyPreconditionedLinearSolveUseCases(
            *A,*lowsFactory,testTranspose,*out
        );

        if(precFactory.get()) {
            externallyPreconditionedLinearSolveUseCases(
                *A,*lowsFactory,*precFactory,false,true,*out
            );
        }

#else // SUN_CXX

        if(out.get()) *out << "\nTest failed since is was not even compiled since SUN_CXX was defined!\n";
        success = false;

#endif // SUN_CXX

    }
    catch( const std::exception &excpt ) {
        std::cerr << "\n*** Caught standard exception : " << excpt.what() << std::endl;
        success = false;
    }

    return success;

}
bool tBlockJacobiPreconditionerFactory::test_initializePrec(int verbosity,std::ostream & os)
{
   using Thyra::zero;

   bool status = false;
   bool allPassed = true;

   std::string constrType[3] = {
       std::string("Static"),
       std::string("2x2 Static Strategy"),
       std::string("3x3 Static Strategy") };

   // three by three bloock diagonal 
   std::vector<RCP<const Thyra::LinearOpBase<double> > > invD;
   invD.push_back(invF_); invD.push_back(invC_); invD.push_back(invF_);

   // allocate new linear operator
   const RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blkOp
        = Thyra::defaultBlockedLinearOp<double>();
   blkOp->beginBlockFill(3,3);
   blkOp->setBlock(0,0,F_);  blkOp->setBlock(0,1,Bt_);
   blkOp->setBlock(1,0,B_);  blkOp->setBlock(1,1,C_);  blkOp->setBlock(1,2,B_);
   blkOp->setBlock(2,1,Bt_); blkOp->setBlock(2,2,F_);
   blkOp->endBlockFill();

   const RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > invBlkOp
        = Thyra::defaultBlockedLinearOp<double>();
   invBlkOp->beginBlockFill(3,3);
   invBlkOp->setBlock(0,0,invF_);  
   invBlkOp->setBlock(1,1,invC_);
   invBlkOp->setBlock(2,2,invF_);
   invBlkOp->endBlockFill();

   // build factory array
   RCP<JacobiPreconditionerFactory> fact_array[3] 
         = { rcp(new JacobiPreconditionerFactory(invF_,invC_)),
             rcp(new JacobiPreconditionerFactory(rcp(new StaticInvDiagStrategy(invF_,invC_)))),
             rcp(new JacobiPreconditionerFactory(rcp(new StaticInvDiagStrategy(invD)))) };

   RCP<const Thyra::LinearOpBase<double> > A[3] = { 
       block2x2(F_,Bt_,B_,C_),
       block2x2(F_,Bt_,B_,C_), 
       blkOp };

   // this is what the factory should build
   RCP<const Thyra::LinearOpBase<double> > invA[3] = { 
       block2x2(invF_,zero(Bt_->range(),Bt_->domain()),zero(B_->range(),B_->domain()),invC_),
       block2x2(invF_,zero(Bt_->range(),Bt_->domain()),zero(B_->range(),B_->domain()),invC_),
       invBlkOp };

   // test both constructors
   for(int i=0;i<3;i++) {
      RCP<const Thyra::LinearOpBase<double> > op;

      RCP<Thyra::PreconditionerFactoryBase<double> > fact = fact_array[i];
      RCP<Thyra::PreconditionerBase<double> > prec = fact->createPrec();

      // initialize the preconditioner
      fact->initializePrec(Thyra::defaultLinearOpSource(A[i]), &*prec);

      op = prec->getRightPrecOp();
      TEST_EQUALITY(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getRightPrecOp\" is not null (it should be!)");

      op = prec->getLeftPrecOp();
      TEST_EQUALITY(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getLeftPrecOp\" is not null (it should be!)");

      op = prec->getUnspecifiedPrecOp();
      TEST_NOT_EQUAL(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getUnspecifiedPrecOp\" is null (it should not be!)");

     LinearOpTester<double> tester;
     tester.show_all_tests(true);
     std::stringstream ss;
     Teuchos::FancyOStream fos(rcpFromRef(ss),"      |||");
     const bool result = tester.compare( *invA[i], *op, &fos );
     TEST_ASSERT(result,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << ": Comparing factory generated operator to correct operator");
     if(not result || verbosity>=10) 
        os << ss.str(); 
   }

   return allPassed;
}
TEUCHOS_UNIT_TEST( EpetraOperatorWrapper, basic )
{

#ifdef HAVE_MPI
   Epetra_MpiComm comm(MPI_COMM_WORLD);
#else
   Epetra_SerialComm comm;
#endif

   out << "\nRunning on " << comm.NumProc() << " processors\n";

   int nx = 39; // essentially random values
   int ny = 53;

   out << "Using Trilinos_Util to create test matrices\n";

   // create some big blocks to play with
   Trilinos_Util::CrsMatrixGallery FGallery("recirc_2d",comm,false); // CJ TODO FIXME: change for Epetra64
   FGallery.Set("nx",nx);
   FGallery.Set("ny",ny);
   RCP<Epetra_CrsMatrix> F = rcp(FGallery.GetMatrix(),false);

   Trilinos_Util::CrsMatrixGallery CGallery("laplace_2d",comm,false); // CJ TODO FIXME: change for Epetra64
   CGallery.Set("nx",nx);
   CGallery.Set("ny",ny);
   RCP<Epetra_CrsMatrix> C = rcp(CGallery.GetMatrix(),false);

   Trilinos_Util::CrsMatrixGallery BGallery("diag",comm,false); // CJ TODO FIXME: change for Epetra64
   BGallery.Set("nx",nx*ny);
   BGallery.Set("a",5.0);
   RCP<Epetra_CrsMatrix> B = rcp(BGallery.GetMatrix(),false);

   Trilinos_Util::CrsMatrixGallery BtGallery("diag",comm,false); // CJ TODO FIXME: change for Epetra64
   BtGallery.Set("nx",nx*ny);
   BtGallery.Set("a",3.0);
   RCP<Epetra_CrsMatrix> Bt = rcp(BtGallery.GetMatrix(),false);

   // load'em up in a thyra operator
   out << "Building block2x2 Thyra matrix ... wrapping in EpetraOperatorWrapper\n";
   const RCP<const LinearOpBase<double> > A =
     Thyra::block2x2<double>(
       Thyra::epetraLinearOp(F),
       Thyra::epetraLinearOp(Bt),
       Thyra::epetraLinearOp(B),
       Thyra::epetraLinearOp(C),
       "A"
       );

   const RCP<Thyra::EpetraOperatorWrapper> epetra_A =
     rcp(new Thyra::EpetraOperatorWrapper(A));

   // begin the tests!
   const Epetra_Map & rangeMap  = epetra_A->OperatorRangeMap();
   const Epetra_Map & domainMap = epetra_A->OperatorDomainMap();

   // check to see that the number of global elements is correct
   TEST_EQUALITY(rangeMap.NumGlobalElements(), 2*nx*ny);
   TEST_EQUALITY(domainMap.NumGlobalElements(), 2*nx*ny);

   // largest global ID should be one less then the # of elements
   TEST_EQUALITY(rangeMap.NumGlobalElements()-1, rangeMap.MaxAllGID());
   TEST_EQUALITY(domainMap.NumGlobalElements()-1, domainMap.MaxAllGID());

   // create a vector to test: copyThyraIntoEpetra
   {
      const RCP<VectorBase<double> > tv = Thyra::createMember(A->domain());
      Thyra::randomize(-100.0, 100.0, tv.ptr());
      const RCP<const VectorBase<double> > tv_0 =
        Thyra::productVectorBase<double>(tv)->getVectorBlock(0);
      const RCP<const VectorBase<double> > tv_1 =
        Thyra::productVectorBase<double>(tv)->getVectorBlock(1);
      const Thyra::ConstDetachedSpmdVectorView<double> vv_0(tv_0);
      const Thyra::ConstDetachedSpmdVectorView<double> vv_1(tv_1);

      int off_0 = vv_0.globalOffset();
      int off_1 = vv_1.globalOffset();
      
      // create its Epetra counter part
      Epetra_Vector ev(epetra_A->OperatorDomainMap());
      epetra_A->copyThyraIntoEpetra(*tv, ev);

      // compare handle_tv to ev!
      TEST_EQUALITY(tv->space()->dim(), as<Ordinal>(ev.GlobalLength()));
      const int numMyElements = domainMap.NumMyElements();
      double tval = 0.0;
      for(int i=0; i < numMyElements; i++) {
         int gid = domainMap.GID(i);
         if(gid<nx*ny)
            tval = vv_0[gid-off_0];
         else
            tval = vv_1[gid-off_1-nx*ny];
         TEST_EQUALITY(ev[i], tval);
      }
   }

   // create a vector to test: copyEpetraIntoThyra
   {
      // create an Epetra vector
     Epetra_Vector ev(epetra_A->OperatorDomainMap());
     ev.Random();

      // create its thyra counterpart
      const RCP<VectorBase<double> > tv = Thyra::createMember(A->domain());
      const RCP<const VectorBase<double> > tv_0 =
        Thyra::productVectorBase<double>(tv)->getVectorBlock(0);
      const RCP<const VectorBase<double> > tv_1 =
        Thyra::productVectorBase<double>(tv)->getVectorBlock(1);
      const Thyra::ConstDetachedSpmdVectorView<double> vv_0(tv_0);
      const Thyra::ConstDetachedSpmdVectorView<double> vv_1(tv_1);

      int off_0 = rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<double> >(
        tv_0->space())->localOffset();
      int off_1 = rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<double> >(
        tv_1->space())->localOffset();

      epetra_A->copyEpetraIntoThyra(ev, tv.ptr());
   
      // compare tv to ev!
      TEST_EQUALITY(tv->space()->dim(), as<Ordinal>(ev.GlobalLength()));
      int numMyElements = domainMap.NumMyElements();
      double tval = 0.0;
      for(int i=0;i<numMyElements;i++) {
         int gid = domainMap.GID(i);
         if(gid<nx*ny)
            tval = vv_0[gid-off_0];
         else
            tval = vv_1[gid-off_1-nx*ny];
         TEST_EQUALITY(ev[i], tval);
      }
   }

   // Test using Thyra::LinearOpTester
   const RCP<const LinearOpBase<double> > thyraEpetraOp = epetraLinearOp(epetra_A);
   LinearOpTester<double> linearOpTester;
   linearOpTester.show_all_tests(true);
   const bool checkResult = linearOpTester.check(*thyraEpetraOp, inOutArg(out));
   TEST_ASSERT(checkResult);

}
TEUCHOS_UNIT_TEST( EpetraLinearOp, Blocked_ScalingWithMultiVectors)
{
  using Teuchos::null;
  using Teuchos::inOutArg;
  using Teuchos::updateSuccess;
  using Teuchos::rcp_dynamic_cast;
  typedef ScalarTraits<double> ST;

  // Set up the EpetraLinearOp

  const RCP<const Epetra_Comm> comm = getEpetraComm();
  const RCP<const Teuchos::Comm<Ordinal> > tComm =
      Teuchos::DefaultComm<Ordinal>::getComm();
  const int numLocalRows = 4;
  const int numRows = numLocalRows * comm->NumProc();
  const int numCols = numLocalRows / 2;

  out << "numRows = " << numRows << ", numCols = " << numCols << std::endl;

  const RCP<Epetra_CrsMatrix> epetraCrsM00 = getMyEpetraMatrix(numRows, numRows);
  const RCP<Epetra_CrsMatrix> epetraCrsM00_base = getMyEpetraMatrix(numRows, numRows);
  epetraCrsM00->PutScalar(2.0);
  epetraCrsM00_base->PutScalar(2.0);

  const RCP<LinearOpBase<double> > op00 = nonconstEpetraLinearOp(epetraCrsM00);
  const RCP<const LinearOpBase<double> > op00_base = epetraLinearOp(epetraCrsM00_base);

  RCP<const Thyra::VectorSpaceBase<double> > vs_0 = op00->range();
  RCP<const Thyra::VectorSpaceBase<double> > vs_1 = Thyra::locallyReplicatedDefaultSpmdVectorSpace<double>(tComm,numCols);

  RCP<Thyra::MultiVectorBase<double> > vec_01  = Thyra::createMembers(vs_0,numCols);
  RCP<Thyra::MultiVectorBase<double> > vec_10t = Thyra::createMembers(op00->domain(),numCols); // tranposed
  RCP<Thyra::MultiVectorBase<double> > vec_01_base  = Thyra::createMembers(vs_0,numCols);
  RCP<Thyra::MultiVectorBase<double> > vec_10t_base = Thyra::createMembers(op00->domain(),numCols); // tranposed
  const RCP<LinearOpBase<double> > op10t = vec_10t;
  const RCP<const LinearOpBase<double> > op10t_base = vec_10t_base;
  assign(vec_01.ptr(),-8.0);
  assign(vec_10t.ptr(),-9.0);
  assign(vec_01_base.ptr(),-8.0);
  assign(vec_10t_base.ptr(),-9.0);

  const RCP<LinearOpBase<double> > op01 = vec_01;
  const RCP<LinearOpBase<double> > op10 = nonconstAdjoint(op10t);
  const RCP<LinearOpBase<double> > op11 = nonconstZero(vec_01->domain(),vec_01->domain());

  const RCP<const LinearOpBase<double> > op01_base = vec_01_base;
  const RCP<const LinearOpBase<double> > op10_base = adjoint(op10t_base);
  const RCP<const LinearOpBase<double> > op11_base = zero(vec_01->domain(),vec_01->domain());

  out << "FIRST" << std::endl;
  const RCP<LinearOpBase<double> > blocked = nonconstBlock2x2(op00,op01,op10,op11);
  out << "SECOND" << Teuchos::describe(*blocked,Teuchos::VERB_EXTREME) << std::endl;
  const RCP<const LinearOpBase<double> > blocked_base = block2x2(op00_base,op01_base,op10_base,op11_base);

  const RCP<const RowStatLinearOpBase<double> > rowStatOp =
    rcp_dynamic_cast<const RowStatLinearOpBase<double> >(blocked, true);

  // Get the inverse row sums

  const RCP<VectorBase<double> > inv_row_sums =
    createMember<double>(blocked->range());
  const RCP<VectorBase<double> > row_sums =
    createMember<double>(blocked->range());

  rowStatOp->getRowStat(RowStatLinearOpBaseUtils::ROW_STAT_INV_ROW_SUM,
    inv_row_sums.ptr());
  rowStatOp->getRowStat(RowStatLinearOpBaseUtils::ROW_STAT_ROW_SUM,
    row_sums.ptr());

  TEST_FLOATING_EQUALITY(
    sum<double>(*inv_row_sums),
    as<double>((1.0/(numRows*2.0+numCols*8.0))*numRows + (1.0/(numRows*9.0+numCols*0.0))*numCols),
    as<double>(10.0 * ST::eps())
    );
  TEST_FLOATING_EQUALITY(
    sum<double>(*row_sums),
    as<double>((numRows*2.0+numCols*8.0)*numRows + (numRows*9.0+numCols*0.0)*numCols),
    as<double>(10.0 * ST::eps())
    );

  {
    const RCP<VectorBase<double> > left_scale  = createMember<double>(blocked_base->range());
    const RCP<VectorBase<double> > right_scale = createMember<double>(blocked_base->domain());

    put_scalar(7.0,left_scale.ptr());
    put_scalar(-4.0,right_scale.ptr());

    rcp_dynamic_cast<ScaledLinearOpBase<double> >(blocked)->scaleLeft(*left_scale);

    {
      LinearOpTester<double> tester;
      tester.set_all_error_tol(1e-10);
      tester.show_all_tests(true);
      tester.dump_all(false);
      tester.num_random_vectors(2);
      const RCP<const LinearOpBase<double> > left_op = Thyra::diagonal(left_scale);
      const RCP<const LinearOpBase<double> > ref_op = multiply(left_op,blocked_base);

      updateSuccess(tester.compare(*ref_op, *blocked, ptrFromRef(out)), success);
    }

    rcp_dynamic_cast<ScaledLinearOpBase<double> >(blocked)->scaleRight(*right_scale);

    {
      LinearOpTester<double> tester;
      tester.set_all_error_tol(1e-10);
      tester.show_all_tests(true);
      tester.dump_all(false);
      tester.num_random_vectors(5);
      const RCP<const LinearOpBase<double> > left_op = Thyra::diagonal(left_scale);
      const RCP<const LinearOpBase<double> > right_op = Thyra::diagonal(right_scale);
      const RCP<const LinearOpBase<double> > ref_op = multiply(left_op,blocked_base,right_op);

      updateSuccess(tester.compare(*ref_op, *blocked, ptrFromRef(out)), success);
    }
  }
}
TEUCHOS_UNIT_TEST( EpetraLinearOp, Blocked_ScaledLinearOpBase)
{
  using Teuchos::null;
  using Teuchos::inOutArg;
  using Teuchos::updateSuccess;
  using Teuchos::rcp_dynamic_cast;
  // typedef ScalarTraits<double> ST; // unused

  // Set up the EpetraLinearOp

  const RCP<const Epetra_Comm> comm = getEpetraComm();
  const int numLocalRows = g_localDim;
  const int numRows = numLocalRows * comm->NumProc();
  const int numCols = numLocalRows ;

  out << "numRows = " << numRows << ", numCols = " << numCols << std::endl;

  const RCP<Epetra_CrsMatrix> epetraCrsM00_base = getMyEpetraMatrix(numRows, numRows);
  const RCP<Epetra_CrsMatrix> epetraCrsM01_base = getMyEpetraMatrix(numRows, numCols);
  const RCP<Epetra_CrsMatrix> epetraCrsM10_base = getMyEpetraMatrix(numCols, numRows);
  const RCP<Epetra_CrsMatrix> epetraCrsM11_base = getMyEpetraMatrix(numCols, numCols);
  epetraCrsM00_base->PutScalar(2.0);
  epetraCrsM01_base->PutScalar(-8.0);
  epetraCrsM10_base->PutScalar(-9.0);
  epetraCrsM11_base->PutScalar(3.0);
  const RCP<Epetra_CrsMatrix> epetraCrsM00 = getMyEpetraMatrix(numRows, numRows);
  const RCP<Epetra_CrsMatrix> epetraCrsM01 = getMyEpetraMatrix(numRows, numCols);
  const RCP<Epetra_CrsMatrix> epetraCrsM10 = getMyEpetraMatrix(numCols, numRows);
  const RCP<Epetra_CrsMatrix> epetraCrsM11 = getMyEpetraMatrix(numCols, numCols);
  epetraCrsM00->PutScalar(2.0);
  epetraCrsM01->PutScalar(-8.0);
  epetraCrsM10->PutScalar(-9.0);
  epetraCrsM11->PutScalar(3.0);

  const RCP<const LinearOpBase<double> > op00_base = epetraLinearOp(epetraCrsM00_base);
  const RCP<const LinearOpBase<double> > op01_base = epetraLinearOp(epetraCrsM01_base);
  const RCP<const LinearOpBase<double> > op10_base = epetraLinearOp(epetraCrsM10_base);
  const RCP<const LinearOpBase<double> > op11_base = epetraLinearOp(epetraCrsM11_base);

  const RCP<LinearOpBase<double> > op00 = nonconstEpetraLinearOp(epetraCrsM00);
  const RCP<LinearOpBase<double> > op01 = nonconstEpetraLinearOp(epetraCrsM01);
  const RCP<LinearOpBase<double> > op10 = nonconstEpetraLinearOp(epetraCrsM10);
  const RCP<LinearOpBase<double> > op11 = nonconstEpetraLinearOp(epetraCrsM11);

  const RCP<const LinearOpBase<double> > blocked_base = block2x2(op00_base,op01_base,op10_base,op11_base);
  const RCP<LinearOpBase<double> > blocked = nonconstBlock2x2(op00,op01,op10,op11);

  const RCP<VectorBase<double> > left_scale  = createMember<double>(blocked_base->range());
  const RCP<VectorBase<double> > right_scale = createMember<double>(blocked_base->domain());

  put_scalar(7.0,left_scale.ptr());
  put_scalar(-4.0,right_scale.ptr());

  rcp_dynamic_cast<ScaledLinearOpBase<double> >(blocked)->scaleLeft(*left_scale);

  {
    LinearOpTester<double> tester;
    tester.set_all_error_tol(1e-10);
    tester.show_all_tests(true);
    tester.dump_all(true);
    tester.num_random_vectors(5);
    const RCP<const LinearOpBase<double> > left_op = Thyra::diagonal(left_scale);
    const RCP<const LinearOpBase<double> > ref_op = multiply(left_op,blocked_base);

    updateSuccess(tester.compare(*ref_op, *blocked, ptrFromRef(out)), success);
  }

  rcp_dynamic_cast<ScaledLinearOpBase<double> >(blocked)->scaleRight(*right_scale);

  {
    LinearOpTester<double> tester;
    tester.set_all_error_tol(1e-10);
    tester.show_all_tests(true);
    tester.dump_all(true);
    tester.num_random_vectors(5);
    const RCP<const LinearOpBase<double> > left_op = Thyra::diagonal(left_scale);
    const RCP<const LinearOpBase<double> > right_op = Thyra::diagonal(right_scale);
    const RCP<const LinearOpBase<double> > ref_op = multiply(left_op,blocked_base,right_op);

    updateSuccess(tester.compare(*ref_op, *blocked, ptrFromRef(out)), success);
  }
}