void ReuseTpetraPreconditioner(const Teuchos::RCP<Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >& inA,
                                 MueLu::TpetraOperator<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Op) {
    typedef Scalar          SC;
    typedef LocalOrdinal    LO;
    typedef GlobalOrdinal   GO;
    typedef Node            NO;

    typedef Xpetra::Matrix<SC,LO,GO,NO>     Matrix;
    typedef Xpetra::Operator<SC,LO,GO,NO>   Operator;
    typedef MueLu ::Hierarchy<SC,LO,GO,NO>  Hierarchy;

    RCP<Hierarchy> H = Op.GetHierarchy();

    TEUCHOS_TEST_FOR_EXCEPTION(!H->GetNumLevels(), Exceptions::RuntimeError,
                               "ReuseTpetraPreconditioner: Hierarchy has no levels in it");
    TEUCHOS_TEST_FOR_EXCEPTION(!H->GetLevel(0)->IsAvailable("A"), Exceptions::RuntimeError,
                               "ReuseTpetraPreconditioner: Hierarchy has no fine level operator");
    RCP<Level> level0 = H->GetLevel(0);

    RCP<Operator> O0 = level0->Get<RCP<Operator> >("A");
    RCP<Matrix>   A0 = Teuchos::rcp_dynamic_cast<Matrix>(O0);

    RCP<Matrix> A = TpetraCrs_To_XpetraMatrix<SC,LO,GO,NO>(inA);
    if (!A0.is_null()) {
      // If a user provided a "number of equations" argument in a parameter list
      // during the initial setup, we must honor that settings and reuse it for
      // all consequent setups.
      A->SetFixedBlockSize(A0->GetFixedBlockSize());
    }
    level0->Set("A", A);

    H->SetupRe();
  }
int main(int argc, char *argv[]) {
#include "MueLu_UseShortNames.hpp"

  using Teuchos::RCP;
  using namespace MueLuExamples;

  Teuchos::oblackholestream blackhole;
  Teuchos::GlobalMPISession mpiSession(&argc,&argv,&blackhole);

  RCP<const Teuchos::Comm<int> > comm = Teuchos::DefaultComm<int>::getComm();
  RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
  out->setOutputToRootOnly(0);
  *out << MueLu::MemUtils::PrintMemoryUsage() << std::endl;

  // Timing
  Teuchos::Time myTime("global");
  Teuchos::TimeMonitor Monitor(myTime);


#ifndef HAVE_TEUCHOS_LONG_LONG_INT
  *out << "Warning: scaling test was not compiled with long long int support" << std::endl;
#endif

  // custom parameters
  LO maxLevels = 4;

  int maxCoarseSize=1; //FIXME clp doesn't like long long int
  std::string aggOrdering = "natural";
  int minPerAgg=3;
  int maxNbrAlreadySelected=0;

  // read in problem
  Epetra_Map emap(10201,0,*Xpetra::toEpetra(comm));
  Epetra_CrsMatrix * ptrA = 0;
  Epetra_Vector * ptrf = 0;

  std::cout << "Reading matrix market file" << std::endl;
  EpetraExt::MatrixMarketFileToCrsMatrix("Condif2Mat.mat",emap,emap,emap,ptrA);
  EpetraExt::MatrixMarketFileToVector("Condif2Rhs.mat",emap,ptrf);
  RCP<Epetra_CrsMatrix> epA = Teuchos::rcp(ptrA);
  RCP<Epetra_Vector> epv = Teuchos::rcp(ptrf);

  // Epetra_CrsMatrix -> Xpetra::Matrix
  RCP<Xpetra::CrsMatrix<double, int, int> > exA = Teuchos::rcp(new Xpetra::EpetraCrsMatrix(epA));
  RCP<Xpetra::CrsMatrixWrap<double, int, int> > crsOp = Teuchos::rcp(new Xpetra::CrsMatrixWrap<double, int, int>(exA));
  RCP<Xpetra::Matrix<double, int, int> > Op = Teuchos::rcp_dynamic_cast<Xpetra::Matrix<double, int, int> >(crsOp);

  // Epetra_Vector -> Xpetra::Vector
  RCP<Xpetra::Vector<double,int,int> > xRhs = Teuchos::rcp(new Xpetra::EpetraVector(epv));

  // Epetra_Map -> Xpetra::Map
  const RCP< const Xpetra::Map<int, int> > map = Xpetra::toXpetra(emap);

  // build nullspace
  RCP<MultiVector> nullSpace = MultiVectorFactory::Build(map,1);
  nullSpace->putScalar( (SC) 1.0);

  RCP<MueLu::Hierarchy<SC,LO,GO,NO,LMO> > H = rcp ( new Hierarchy() );
  H->setDefaultVerbLevel(Teuchos::VERB_HIGH);
  H->SetMaxCoarseSize((GO) maxCoarseSize);;

  // build finest Level
  RCP<MueLu::Level> Finest = H->GetLevel();
  Finest->setDefaultVerbLevel(Teuchos::VERB_HIGH);
  Finest->Set("A",Op);
  Finest->Set("Nullspace",nullSpace);

  RCP<CoupledAggregationFactory> CoupledAggFact = rcp(new CoupledAggregationFactory());
  *out << "========================= Aggregate option summary  =========================" << std::endl;
  *out << "min DOFs per aggregate :                " << minPerAgg << std::endl;
  *out << "min # of root nbrs already aggregated : " << maxNbrAlreadySelected << std::endl;
  CoupledAggFact->SetMinNodesPerAggregate(minPerAgg); //TODO should increase if run anything other than 1D
  CoupledAggFact->SetMaxNeighAlreadySelected(maxNbrAlreadySelected);
  std::transform(aggOrdering.begin(), aggOrdering.end(), aggOrdering.begin(), ::tolower);
  if (aggOrdering == "natural" || aggOrdering == "graph" || aggOrdering == "random") {
    *out << "aggregate ordering :                    " << aggOrdering << std::endl;
    CoupledAggFact->SetOrdering(aggOrdering);
  } else {
    std::string msg = "main: bad aggregation option """ + aggOrdering + """.";
    throw(MueLu::Exceptions::RuntimeError(msg));
  }
  CoupledAggFact->SetPhase3AggCreation(0.5);
  Finest->Keep("Aggregates",CoupledAggFact.get());
  *out << "=============================================================================" << std::endl;

  // build transfer operators
//   RCP<NullspaceFactory> nspFact = rcp(new NullspaceFactory()); // make sure that we can keep nullspace!!!
//   RCP<TentativePFactory> TentPFact = rcp(new TentativePFactory(CoupledAggFact,nspFact));
//   //RCP<PgPFactory> Pfact = rcp( new PgPFactory(TentPFact) );
//   //RCP<FactoryBase2> Rfact  = rcp( new GenericRFactory(Pfact));
//   RCP<SaPFactory> Pfact  = rcp( new SaPFactory(TentPFact) );
//   RCP<FactoryBase2>   Rfact  = rcp( new TransPFactory(Pfact) );
//   RCP<RAPFactory> Acfact = rcp( new RAPFactory(Pfact, Rfact) );
//   Acfact->setVerbLevel(Teuchos::VERB_HIGH);

//   Finest->Keep("Aggregates",CoupledAggFact.get());
//   Finest->Keep("Nullspace",nspFact.get());

  // build level smoothers
  RCP<SmootherPrototype> smooProto;
  std::string ifpackType;
  Teuchos::ParameterList ifpackList;
  ifpackList.set("relaxation: sweeps", (LO) 1);
  ifpackList.set("relaxation: damping factor", (SC) 0.9); // 0.7
  ifpackType = "RELAXATION";
  ifpackList.set("relaxation: type", "Gauss-Seidel");

  smooProto = Teuchos::rcp( new TrilinosSmoother(ifpackType, ifpackList) );
  RCP<SmootherFactory> SmooFact;
  if (maxLevels > 1)
    SmooFact = rcp( new SmootherFactory(smooProto) );

  RCP<FactoryManager> M = rcp(new FactoryManager());
  M->SetFactory("Aggregates", CoupledAggFact);
  M->SetFactory("Smoother", SmooFact);

  H->Setup(*M,0,maxLevels);

  // print out aggregation information
  for(LocalOrdinal l=0; l<H->GetNumLevels()-1;l++) {
    RCP<Level> level = H->GetLevel((int)l);
    ExportAggregates(level, CoupledAggFact.get(),comm);
  }

  return EXIT_SUCCESS;
}
  void MueLuPreconditionerFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::
  initializePrec(const RCP<const LinearOpSourceBase<Scalar> >& fwdOpSrc, PreconditionerBase<Scalar>* prec, const ESupportSolveUse supportSolveUse) const {
    using Teuchos::rcp_dynamic_cast;

    // we are using typedefs here, since we are using objects from different packages (Xpetra, Thyra,...)
    typedef Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node>                     XpMap;
    typedef Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>      XpOp;
    typedef Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>       XpThyUtils;
    typedef Xpetra::CrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>        XpCrsMat;
    typedef Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> XpBlockedCrsMat;
    typedef Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>           XpMat;
    typedef Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node>      XpMultVec;
    typedef Xpetra::MultiVector<double,LocalOrdinal,GlobalOrdinal,Node>      XpMultVecDouble;
    typedef Thyra::LinearOpBase<Scalar>                                      ThyLinOpBase;
#ifdef HAVE_MUELU_TPETRA
    typedef MueLu::TpetraOperator<Scalar,LocalOrdinal,GlobalOrdinal,Node> MueTpOp;
    typedef Tpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node>      TpOp;
    typedef Thyra::TpetraLinearOp<Scalar,LocalOrdinal,GlobalOrdinal,Node> ThyTpLinOp;
#endif

    // Check precondition
    TEUCHOS_ASSERT(Teuchos::nonnull(fwdOpSrc));
    TEUCHOS_ASSERT(this->isCompatible(*fwdOpSrc));
    TEUCHOS_ASSERT(prec);

    // Create a copy, as we may remove some things from the list
    ParameterList paramList = *paramList_;

    // Retrieve wrapped concrete Xpetra matrix from FwdOp
    const RCP<const ThyLinOpBase> fwdOp = fwdOpSrc->getOp();
    TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(fwdOp));

    // Check whether it is Epetra/Tpetra
    bool bIsEpetra  = XpThyUtils::isEpetra(fwdOp);
    bool bIsTpetra  = XpThyUtils::isTpetra(fwdOp);
    bool bIsBlocked = XpThyUtils::isBlockedOperator(fwdOp);
    TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra == true  && bIsTpetra == true));
    TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra == bIsTpetra) && bIsBlocked == false);
    TEUCHOS_TEST_FOR_EXCEPT((bIsEpetra != bIsTpetra) && bIsBlocked == true);

    RCP<XpMat> A = Teuchos::null;
    if(bIsBlocked) {
      Teuchos::RCP<const Thyra::BlockedLinearOpBase<Scalar> > ThyBlockedOp =
          Teuchos::rcp_dynamic_cast<const Thyra::BlockedLinearOpBase<Scalar> >(fwdOp);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(ThyBlockedOp));

      TEUCHOS_TEST_FOR_EXCEPT(ThyBlockedOp->blockExists(0,0)==false);

      Teuchos::RCP<const LinearOpBase<Scalar> > b00 = ThyBlockedOp->getBlock(0,0);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(b00));

      RCP<const XpCrsMat > xpetraFwdCrsMat00 = XpThyUtils::toXpetra(b00);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(xpetraFwdCrsMat00));

      // MueLu needs a non-const object as input
      RCP<XpCrsMat> xpetraFwdCrsMatNonConst00 = Teuchos::rcp_const_cast<XpCrsMat>(xpetraFwdCrsMat00);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(xpetraFwdCrsMatNonConst00));

      // wrap the forward operator as an Xpetra::Matrix that MueLu can work with
      RCP<XpMat> A00 = rcp(new Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node>(xpetraFwdCrsMatNonConst00));
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(A00));

      RCP<const XpMap> rowmap00 = A00->getRowMap();
      RCP< const Teuchos::Comm< int > > comm = rowmap00->getComm();

      // create a Xpetra::BlockedCrsMatrix which derives from Xpetra::Matrix that MueLu can work with
      RCP<XpBlockedCrsMat> bMat = Teuchos::rcp(new XpBlockedCrsMat(ThyBlockedOp, comm));
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(bMat));

      // save blocked matrix
      A = bMat;
    } else {
      RCP<const XpCrsMat > xpetraFwdCrsMat = XpThyUtils::toXpetra(fwdOp);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(xpetraFwdCrsMat));

      // MueLu needs a non-const object as input
      RCP<XpCrsMat> xpetraFwdCrsMatNonConst = Teuchos::rcp_const_cast<XpCrsMat>(xpetraFwdCrsMat);
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(xpetraFwdCrsMatNonConst));

      // wrap the forward operator as an Xpetra::Matrix that MueLu can work with
      A = rcp(new Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node>(xpetraFwdCrsMatNonConst));
    }
    TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(A));

    // Retrieve concrete preconditioner object
    const Teuchos::Ptr<DefaultPreconditioner<Scalar> > defaultPrec = Teuchos::ptr(dynamic_cast<DefaultPreconditioner<Scalar> *>(prec));
    TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(defaultPrec));

    // extract preconditioner operator
    RCP<ThyLinOpBase> thyra_precOp = Teuchos::null;
    thyra_precOp = rcp_dynamic_cast<Thyra::LinearOpBase<Scalar> >(defaultPrec->getNonconstUnspecifiedPrecOp(), true);

    // Variable for multigrid hierarchy: either build a new one or reuse the existing hierarchy
    RCP<MueLu::Hierarchy<Scalar,LocalOrdinal,GlobalOrdinal,Node> > H = Teuchos::null;

    // make a decision whether to (re)build the multigrid preconditioner or reuse the old one
    // rebuild preconditioner if startingOver == true
    // reuse preconditioner if startingOver == false
    const bool startingOver = (thyra_precOp.is_null() || !paramList.isParameter("reuse: type") || paramList.get<std::string>("reuse: type") == "none");

    if (startingOver == true) {
      // extract coordinates from parameter list
      Teuchos::RCP<XpMultVecDouble> coordinates = Teuchos::null;
      coordinates = MueLu::Utilities<Scalar,LocalOrdinal,GlobalOrdinal,Node>::ExtractCoordinatesFromParameterList(paramList);

      // TODO check for Xpetra or Thyra vectors?
      RCP<XpMultVec> nullspace = Teuchos::null;
#ifdef HAVE_MUELU_TPETRA
      if (bIsTpetra) {
        typedef Tpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> tMV;
        RCP<tMV> tpetra_nullspace = Teuchos::null;
        if (paramList.isType<Teuchos::RCP<tMV> >("Nullspace")) {
          tpetra_nullspace = paramList.get<RCP<tMV> >("Nullspace");
          paramList.remove("Nullspace");
          nullspace = MueLu::TpetraMultiVector_To_XpetraMultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node>(tpetra_nullspace);
          TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(nullspace));
        }
      }
#endif
      // build a new MueLu hierarchy
      H = MueLu::CreateXpetraPreconditioner(A, paramList, coordinates, nullspace);

    } else {
      // reuse old MueLu hierarchy stored in MueLu Tpetra/Epetra operator and put in new matrix

      // get old MueLu hierarchy
#if defined(HAVE_MUELU_TPETRA)
      if (bIsTpetra) {

        RCP<ThyTpLinOp> tpetr_precOp = rcp_dynamic_cast<ThyTpLinOp>(thyra_precOp);
        RCP<MueTpOp>    muelu_precOp = rcp_dynamic_cast<MueTpOp>(tpetr_precOp->getTpetraOperator(),true);

        H = muelu_precOp->GetHierarchy();
      }
#endif
      // TODO add the blocked matrix case here...

      TEUCHOS_TEST_FOR_EXCEPTION(!H->GetNumLevels(), MueLu::Exceptions::RuntimeError,
                                 "Thyra::MueLuPreconditionerFactory: Hierarchy has no levels in it");
      TEUCHOS_TEST_FOR_EXCEPTION(!H->GetLevel(0)->IsAvailable("A"), MueLu::Exceptions::RuntimeError,
                                 "Thyra::MueLuPreconditionerFactory: Hierarchy has no fine level operator");
      RCP<MueLu::Level> level0 = H->GetLevel(0);
      RCP<XpOp>    O0 = level0->Get<RCP<XpOp> >("A");
      RCP<XpMat>   A0 = rcp_dynamic_cast<XpMat>(O0);

      if (!A0.is_null()) {
        // If a user provided a "number of equations" argument in a parameter list
        // during the initial setup, we must honor that settings and reuse it for
        // all consequent setups.
        A->SetFixedBlockSize(A0->GetFixedBlockSize());
      }

      // set new matrix
      level0->Set("A", A);

      H->SetupRe();
    }

    // wrap hierarchy H in thyraPrecOp
    RCP<ThyLinOpBase > thyraPrecOp = Teuchos::null;
#if defined(HAVE_MUELU_TPETRA)
    if (bIsTpetra) {
      RCP<MueTpOp> muelu_tpetraOp = rcp(new MueTpOp(H));
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(muelu_tpetraOp));
      RCP<TpOp> tpOp = Teuchos::rcp_dynamic_cast<TpOp>(muelu_tpetraOp);
      thyraPrecOp = Thyra::createLinearOp<Scalar, LocalOrdinal, GlobalOrdinal, Node>(tpOp);
    }
#endif

    if(bIsBlocked) {
      TEUCHOS_TEST_FOR_EXCEPT(Teuchos::nonnull(thyraPrecOp));

      typedef MueLu::XpetraOperator<Scalar,LocalOrdinal,GlobalOrdinal,Node>    MueXpOp;
      //typedef Thyra::XpetraLinearOp<Scalar,LocalOrdinal,GlobalOrdinal,Node>    ThyXpLinOp; // unused
      const RCP<MueXpOp> muelu_xpetraOp = rcp(new MueXpOp(H));

      RCP<const VectorSpaceBase<Scalar> > thyraRangeSpace  = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyra(muelu_xpetraOp->getRangeMap());
      RCP<const VectorSpaceBase<Scalar> > thyraDomainSpace = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyra(muelu_xpetraOp->getDomainMap());

      RCP <Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > xpOp = Teuchos::rcp_dynamic_cast<Xpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(muelu_xpetraOp);
      thyraPrecOp = Thyra::xpetraLinearOp(thyraRangeSpace, thyraDomainSpace,xpOp);
    }

    TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(thyraPrecOp));

    defaultPrec->initializeUnspecified(thyraPrecOp);

  }
Example #4
0
int main(int argc, char *argv[]) {

  // RCPs
  using Teuchos::RCP;
  using Teuchos::rcp;

  // MPI initialization using Teuchos
  Teuchos::GlobalMPISession mpiSession(&argc, &argv, NULL);
  RCP< const Teuchos::Comm<int> > comm = Teuchos::DefaultComm<int>::getComm();

  // predetermined DOF and parameter info
  // for case 1
  int nAcousticDOFs = 126;
  int nPaddedDOFs   = 3*nAcousticDOFs;
  int nElasticDOFs  = 243;
  int nTotalDOFs    = nPaddedDOFs+nElasticDOFs;
  int nDOFsPerNode  = 3;
  int nTotalNodes   = nTotalDOFs/nDOFsPerNode;
  int nnzeros_stiff = 12869;
  int nnzeros_damp  = 98;
  int nnzeros_mass  = 5635;
  int maxDOFsPerRow = 100;
  double freq = 11.0;
  double h=0.5;
  int nx=3;
  int ny=3;
  int nz=23;
  // for case 2
  /*int nAcousticDOFs = 600;
  int nPaddedDOFs   = 3*nAcousticDOFs;
  int nElasticDOFs  = 1425;
  int nTotalDOFs    = nPaddedDOFs+nElasticDOFs;
  int nDOFsPerNode  = 3;
  int nTotalNodes   = nTotalDOFs/nDOFsPerNode;
  int nnzeros_stiff = 94557;
  int nnzeros_damp  = 338;
  int nnzeros_mass  = 39715;
  int maxDOFsPerRow = 100;
  double freq = 22.0;
  double h=0.25;
  int nx=5;
  int ny=5;
  int nz=43;*/
  // for case 3
  /*int nAcousticDOFs = 3564;
  int nPaddedDOFs   = 3*nAcousticDOFs;
  int nElasticDOFs  = 9477;
  int nTotalDOFs    = nPaddedDOFs+nElasticDOFs;
  int nDOFsPerNode  = 3;
  int nTotalNodes   = nTotalDOFs/nDOFsPerNode;
  int nnzeros_stiff = 719287;
  int nnzeros_damp  = 1250;
  int nnzeros_mass  = 296875;
  int maxDOFsPerRow = 100;
  double freq = 44.0;
  double h=0.125;
  int nx=9;
  int ny=9;
  int nz=83;*/

  // Some constants
  SC omega  = (SC) 2.0*M_PI*freq;
  SC omega2 = omega*omega;
  SC one(1.0,0.0);
  SC ii(0.0,1.0);

  // Construct a Map that puts approximately the same number of mesh nodes per processor
  RCP<const Tpetra::Map<LO, GO, NO> > map = Tpetra::createUniformContigMap<LO, GO>(nTotalNodes, comm);
  // Tpetra map into Xpetra map
  RCP<const Map> xmap = Xpetra::toXpetra(map);
  // Map takes constant number of DOFs per node
  xmap = MapFactory::Build(xmap,nDOFsPerNode);
  map = Xpetra::toTpetra(xmap);

  // Create a CrsMatrix using the map
  // K - only stiffness matrix
  // M - only mass matrix
  // A - original Helmholtz operator
  // S - shifted Helmholtz operator
  RCP<TCRS> K = rcp(new TCRS(map,maxDOFsPerRow));
  RCP<TCRS> M = rcp(new TCRS(map,maxDOFsPerRow));
  RCP<TCRS> A = rcp(new TCRS(map,maxDOFsPerRow));
  RCP<TCRS> S = rcp(new TCRS(map,maxDOFsPerRow));

  // Read data from .txt files and put into appropriate matrices
  // Note: must pad acoustic DOFs with identity matrix
  // stiffness matrix
  std::ifstream matfile_stiff;
  matfile_stiff.open("coupled_stiff.txt");
  for (int i = 0; i < nnzeros_stiff; i++) {
    int current_row, current_column;
    double current_value;
    matfile_stiff >> current_row >> current_column >> current_value ;
    SC cpx_current_value(current_value,0.0);
    if(current_row < nAcousticDOFs)    { current_row    = current_row*3;                             }
    else                               { current_row    = current_row-nAcousticDOFs+nPaddedDOFs;     }
    if(current_column < nAcousticDOFs) { current_column = current_column*3;                          }
    else                               { current_column = current_column-nAcousticDOFs+nPaddedDOFs;  }
    if(map->isNodeGlobalElement(current_row)==true) {
      K->insertGlobalValues(current_row,
			    Teuchos::tuple<GO> (current_column),
			    Teuchos::tuple<SC> (cpx_current_value));
    }
  }
  // pad with identity
  for(int i = 0; i < nAcousticDOFs; i++) {
    if(map->isNodeGlobalElement(3*i+1)==true) {
      K->insertGlobalValues(3*i+1,
			    Teuchos::tuple<GO> (3*i+1),
			    Teuchos::tuple<SC> (one));
    }
    if(map->isNodeGlobalElement(3*i+2)==true) {
      K->insertGlobalValues(3*i+2,
			    Teuchos::tuple<GO> (3*i+2),
			    Teuchos::tuple<SC> (one));
    }
  }
  // damping matrix - lump into stiffness matrix
  std::ifstream matfile_damp;
  matfile_damp.open("coupled_damp.txt");
  for (int i = 0; i < nnzeros_damp; i++) {
    int current_row, current_column;
    double current_value;
    matfile_damp >> current_row >> current_column >> current_value ;
    SC cpx_current_value(current_value,0.0);
    if(current_row < nAcousticDOFs)    { current_row    = current_row*3;                             }
    else                               { current_row    = current_row-nAcousticDOFs+nPaddedDOFs;     }
    if(current_column < nAcousticDOFs) { current_column = current_column*3;                          }
    else                               { current_column = current_column-nAcousticDOFs+nPaddedDOFs;  }
    if(map->isNodeGlobalElement(current_row)==true) {
      K->insertGlobalValues(current_row,
			    Teuchos::tuple<GO> (current_column),
			    Teuchos::tuple<SC> (ii*omega*cpx_current_value));
    }
  }
  // mass matrix
  std::ifstream matfile_mass;
  matfile_mass.open("coupled_mass.txt");
  for (int i = 0; i < nnzeros_mass; i++) {
    int current_row, current_column;
    double current_value;
    matfile_mass >> current_row >> current_column >> current_value ;
    SC cpx_current_value(current_value,0.0);
    if(current_row < nAcousticDOFs)    { current_row    = current_row*3;                             }
    else                               { current_row    = current_row-nAcousticDOFs+nPaddedDOFs;     }
    if(current_column < nAcousticDOFs) { current_column = current_column*3;                          }
    else                               { current_column = current_column-nAcousticDOFs+nPaddedDOFs;  }
    if(map->isNodeGlobalElement(current_row)==true) {
      M->insertGlobalValues(current_row,
			     Teuchos::tuple<GO> (current_column),
			     Teuchos::tuple<SC> (cpx_current_value));
    }
  }
  // pad with identity
  for(int i = 0; i < nAcousticDOFs; i++) {
    if(map->isNodeGlobalElement(3*i+1)==true) {
      M->insertGlobalValues(3*i+1,
			    Teuchos::tuple<GO> (3*i+1),
			    Teuchos::tuple<SC> (one));
    }
    if(map->isNodeGlobalElement(3*i+2)==true) {
      M->insertGlobalValues(3*i+2,
			    Teuchos::tuple<GO> (3*i+2),
			    Teuchos::tuple<SC> (one));
    }
  }
  // Complete fill
  K->fillComplete();
  M->fillComplete();

  // Turn Tpetra::CrsMatrix into MueLu::Matrix
  RCP<XCRS> mueluK_ = rcp(new XTCRS(K));
  RCP<XMAT> mueluK  = rcp(new XWRAP(mueluK_));
  RCP<XCRS> mueluM_ = rcp(new XTCRS(M));
  RCP<XMAT> mueluM  = rcp(new XWRAP(mueluM_));
  mueluK->SetFixedBlockSize(nDOFsPerNode);
  mueluM->SetFixedBlockSize(nDOFsPerNode);
  // combine to make Helmholtz and shifted Laplace operators
  RCP<XMAT> mueluA, mueluS;
  SC shift1(1.0,0.5);
  MueLu::Utils2<SC,LO,GO,NO,LMO>::TwoMatrixAdd(mueluK, false, (SC) 1.0, mueluM, false, -omega2, mueluA);
  MueLu::Utils2<SC,LO,GO,NO,LMO>::TwoMatrixAdd(mueluK, false, (SC) 1.0, mueluM, false, -shift1*omega2, mueluS);
  mueluA->fillComplete();
  mueluS->fillComplete();
  xmap=mueluA->getDomainMap();
  map=Xpetra::toTpetra(xmap);

  // MultiVector of coordinates
  // NOTE: must be of size equal to the number of DOFs!
  RCP<XMV> coordinates;
  coordinates = MultiVectorFactory::Build(xmap, 3);
  for(int k=0; k<nz; k++) {
    for(int j=0; j<ny; j++) {
      for(int i=0; i<nx; i++) {
	int curidx = i+nx*j+nx*ny*k;
        int curidx0 = curidx*3+0;
        int curidx1 = curidx*3+1;
        int curidx2 = curidx*3+2;
	SC ih = (SC) (i*h);
	SC jh = (SC) (j*h);
	SC kh = (SC) (k*h);
	if(xmap->isNodeGlobalElement(curidx0)==true) {
	  coordinates->replaceGlobalValue(curidx0,0,ih);
	  coordinates->replaceGlobalValue(curidx0,1,jh);
	  coordinates->replaceGlobalValue(curidx0,2,kh);
	}
	if(xmap->isNodeGlobalElement(curidx1)==true) {
	  coordinates->replaceGlobalValue(curidx1,0,ih);
	  coordinates->replaceGlobalValue(curidx1,1,jh);
	  coordinates->replaceGlobalValue(curidx1,2,kh);
	}
	if(xmap->isNodeGlobalElement(curidx2)==true) {
	  coordinates->replaceGlobalValue(curidx2,0,ih);
	  coordinates->replaceGlobalValue(curidx2,1,jh);
	  coordinates->replaceGlobalValue(curidx2,2,kh);
	}
      }
    }
  }

  // Multigrid Hierarchy
  RCP<Hierarchy> H = rcp(new Hierarchy(mueluK));
  FactoryManager Manager;

  // Prolongation/Restriction
  RCP<TPFactory>  TentPFact    = rcp(  new TPFactory       );
  RCP<SaPFactory> Pfact        = rcp(  new SaPFactory      );
  RCP<GRFactory>  Rfact        = rcp(  new GRFactory       );
  RCP<RAPShiftFactory> Acfact  = rcp(  new RAPShiftFactory );
  RCP<RBMFactory> RBMfact      = rcp(  new RBMFactory(3)   );
  RBMfact->setLastAcousticDOF(nPaddedDOFs);

  // Smoothers
  RCP<SmootherPrototype> smooProto;
  std::string ifpack2Type;
  Teuchos::ParameterList ifpack2List;
  // Krylov smoother
  /*ifpack2Type = "KRYLOV";
  ifpack2List.set("krylov: iteration type",1);
  ifpack2List.set("krylov: number of iterations",4);
  ifpack2List.set("krylov: residual tolerance",1e-6);
  ifpack2List.set("krylov: block size",1);
  ifpack2List.set("krylov: zero starting solution",true);
  ifpack2List.set("krylov: preconditioner type",1);*/
  // Additive Schwarz smoother
  //ifpack2Type = "SCHWARZ";
  //ifpack2List.set("schwarz: compute condest", false);
  //ifpack2List.set("schwarz: combine mode", "Add"); // use string mode for this
  //ifpack2List.set("schwarz: reordering type", "none");
  //ifpack2List.set("schwarz: filter singletons", false);
  //ifpack2List.set("schwarz: overlap level", 0);
  // ILUT smoother
  //ifpack2Type = "ILUT";
  //ifpack2List.set("fact: ilut level-of-fill", (double)1.0);
  //ifpack2List.set("fact: absolute threshold", (double)0.0);
  //ifpack2List.set("fact: relative threshold", (double)1.0);
  //ifpack2List.set("fact: relax value", (double)0.0);
  // Gauss-Seidel smoother
  ifpack2Type = "RELAXATION";
  ifpack2List.set("relaxation: sweeps", (LO) 4);
  ifpack2List.set("relaxation: damping factor", (SC) 1.0); // 0.7
  ifpack2List.set("relaxation: type", "Gauss-Seidel");

  smooProto = Teuchos::rcp( new Ifpack2Smoother(ifpack2Type,ifpack2List) );
  RCP<SmootherFactory> SmooFact;
  LO maxLevels = 6;
  if (maxLevels > 1)
    SmooFact = rcp( new SmootherFactory(smooProto) );

  // create coarsest smoother
  RCP<SmootherPrototype> coarsestSmooProto;
  // Direct Solver
  std::string type = "";
  Teuchos::ParameterList coarsestSmooList;
#if defined(HAVE_AMESOS_SUPERLU)
  coarsestSmooProto = rcp( new DirectSolver("Superlu",coarsestSmooList) );
#else
  coarsestSmooProto = rcp( new DirectSolver("Klu",coarsestSmooList) );
#endif
  RCP<SmootherFactory> coarsestSmooFact = rcp(new SmootherFactory(coarsestSmooProto, Teuchos::null));

  RCP<XMV> nullspace;
  RBMfact->BuildRBM(mueluA,coordinates,nullspace);

  // determine shifts for RAPShiftFactory
  std::vector<SC> shifts;
  for(int i=0; i<maxLevels; i++) {
    double alpha=1.0;
    double beta=0.5+((double) i)*0.2;
    SC shift(alpha,beta);
    shifts.push_back(-shift*omega2);
  }
  Acfact->SetShifts(shifts);

  // Set factory managers for prolongation/restriction
  Manager.SetFactory("P", Pfact);
  Manager.SetFactory("R", Rfact);
  Manager.SetFactory("Ptent", TentPFact);
  H->Keep("P", Pfact.get());
  H->Keep("R", Rfact.get());
  H->Keep("Ptent", TentPFact.get());
  H->GetLevel(0)->Set("Nullspace",nullspace);
  H->SetImplicitTranspose(true);
  H->Setup(Manager, 0, maxLevels);
  H->Delete("Smoother");
  H->Delete("CoarseSolver");
  H->print(*getFancyOStream(Teuchos::rcpFromRef(std::cout)), MueLu::High);

  // Set factories for smoothing and coarse grid
  Manager.SetFactory("Smoother", SmooFact);
  Manager.SetFactory("CoarseSolver", coarsestSmooFact);
  Manager.SetFactory("A", Acfact);
  Manager.SetFactory("K", Acfact);
  Manager.SetFactory("M", Acfact);
  H->GetLevel(0)->Set("A",mueluS);
  H->GetLevel(0)->Set("K",mueluK);
  H->GetLevel(0)->Set("M",mueluM);
  H->Setup(Manager, 0, H->GetNumLevels());

  // right hand side and left hand side vectors
  RCP<TVEC> X = Tpetra::createVector<SC,LO,GO,NO>(map);
  RCP<TVEC> B = Tpetra::createVector<SC,LO,GO,NO>(map);
  X->putScalar((SC) 0.0);
  if(comm->getRank()==0)
    B->replaceGlobalValue(0, 1.0);

  // Define Operator and Preconditioner
  RCP<OP> belosOp   = rcp(new Belos::XpetraOp<SC,LO,GO,NO,LMO>(mueluA));   // Turns a Xpetra::Matrix object into a Belos operator
  RCP<OP> belosPrec = rcp(new Belos::MueLuOp<SC,LO,GO,NO,LMO>(H));         // Turns a MueLu::Hierarchy object into a Belos operator

  // Construct a Belos LinearProblem object
  RCP<Problem> belosProblem = rcp(new Problem(belosOp,X,B));
  belosProblem->setRightPrec(belosPrec);
  bool set = belosProblem->setProblem();
  if (set == false) {
    if(comm->getRank()==0) {
      std::cout << std::endl << "ERROR:  Belos::LinearProblem failed to set up correctly!" << std::endl;
    }
    return EXIT_FAILURE;
  }

  // Belos parameter list
  int maxIts = 100;
  double tol = 1e-6;
  Teuchos::ParameterList belosList;
  belosList.set("Maximum Iterations",    maxIts); // Maximum number of iterations allowed
  belosList.set("Convergence Tolerance", tol);    // Relative convergence tolerance requested
  belosList.set("Flexible Gmres", false);         // set flexible GMRES on

  // Create a FGMRES solver manager
  RCP<BelosSolver> solver = rcp( new BelosGMRES(belosProblem, rcp(&belosList, false)) );

  // Perform solve
  Belos::ReturnType ret = solver->solve();

  // print solution entries
  //using Teuchos::VERB_EXTREME;
  //Teuchos::RCP<Teuchos::FancyOStream> out = Teuchos::getFancyOStream( Teuchos::rcpFromRef(std::cerr) );
  //X->describe(*out,VERB_EXTREME);

  // Get the number of iterations for this solve.
  if(comm->getRank()==0) {
    std::cout << "Number of iterations performed for this solve: " << solver->getNumIters() << std::endl;
  }
  // Compute actual residuals.
  int numrhs=1;
  bool badRes = false;
  std::vector<double> actual_resids(numrhs);
  std::vector<double> rhs_norm(numrhs);
  RCP<TMV> resid = Tpetra::createMultiVector<SC,LO,GO,NO>(map, numrhs);
  OPT::Apply(*belosOp, *X, *resid);
  MVT::MvAddMv(-1.0, *resid, 1.0, *B, *resid);
  MVT::MvNorm(*resid, actual_resids);
  MVT::MvNorm(*B, rhs_norm);
  if(comm->getRank()==0) {
    std::cout<< "---------- Actual Residuals (normalized) ----------"<<std::endl<<std::endl;
  }
  for (int i = 0; i < numrhs; i++) {
    double actRes = abs(actual_resids[i])/rhs_norm[i];
    if(comm->getRank()==0) {
      std::cout <<"Problem " << i << " : \t" << actRes <<std::endl;
    }
    if (actRes > tol) { badRes = true; }
  }

  // Check convergence
  if (ret != Belos::Converged || badRes) {
    if(comm->getRank()==0) {
      std::cout << std::endl << "ERROR:  Belos did not converge! " << std::endl;
    }
    return EXIT_FAILURE;
  }
  if(comm->getRank()==0) {
    std::cout << std::endl << "SUCCESS:  Belos converged!" << std::endl;
  }

  return EXIT_SUCCESS;
}