Teko ships four worked examples under packages/teko/examples/. This page summarizes what each demonstrates and how to run it. The full sources are included in the API documentation via the Doxygen \include directives at the bottom of each section.
Data files. The drivers read Matrix-Market files from examples/data/, which ships nslhs_test.mm and nsrhs_test.mm. All three example programs (both BuildPreconditioner drivers and StridedSolve) additionally read ../data/nsjac.mm, which is not currently in examples/data/ — supply your own Navier–Stokes Jacobian there before running them.
All examples are built by the package's CMake when Teko's tests/examples are enabled; the binaries land next to their source directories in the build tree.
BuildPreconditioner — the canonical driver
examples/BuildPreconditioner/ contains two drivers that read a strided Navier–Stokes matrix, build a block preconditioner, and solve with Belos.
- **
example-driver.cpp** — the native Tpetra path. It splits the monolithic matrix with a StridedTpetraOperator ({2, 1} = 2 velocity + 1 pressure per node), builds an LSC preconditioner via InvLSCStrategy, wraps it in a TpetraBlockPreconditioner, and hands it to Belos::BlockGmresSolMgr as a right preconditioner.
- **
example-driver-belos.cpp** — the Thyra/Stratimikos path. It assembles a 2×2 block operator with Thyra::block2x2, builds an InverseLibrary from a hand-built parameter list (a "Gauss-Seidel" entry over Ifpack2 block solves), calls Teko::buildInverse, and solves with Belos. This is the driver dissected in Getting Started.
Run (from the example's build directory):
$ mpirun -np 2 ./Teko_example-driver-belos.exe
Full source (Thyra/Stratimikos path):
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_GlobalMPISession.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_XMLParameterListHelpers.hpp"
#include "Teuchos_DefaultComm.hpp"
#include "Teuchos_AbstractFactoryStd.hpp"
#include "mpi.h"
#include "Tpetra_CrsMatrix.hpp"
#include "Tpetra_Core.hpp"
#include "MatrixMarket_Tpetra.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_InverseLibrary.hpp"
#include "Teko_LSCPreconditionerFactory.hpp"
#include "Teko_InvLSCStrategy.hpp"
#include "Teko_SIMPLEPreconditionerFactory.hpp"
#include "Thyra_TpetraLinearOp.hpp"
#include "Thyra_TpetraVector.hpp"
#include "Thyra_TpetraVectorSpace.hpp"
#include "Stratimikos_DefaultLinearSolverBuilder.hpp"
#include "BelosConfigDefs.hpp"
#include "BelosLinearProblem.hpp"
#include "BelosBlockGmresSolMgr.hpp"
#include "BelosThyraAdapter.hpp"
#include <iostream>
using Teuchos::RCP;
using Teuchos::rcp;
using Teuchos::rcpFromRef;
RCP<Teuchos::ParameterList> buildLibPL();
int main(int argc, char* argv[]) {
typedef double ST;
typedef Thyra::MultiVectorBase<ST> MV;
typedef Thyra::LinearOpBase<ST> OP;
typedef Tpetra::Vector<ST> TP_Vec;
typedef Tpetra::CrsMatrix<ST> TP_Crs;
typedef Tpetra::Operator<ST> TP_Op;
typedef TP_Vec::local_ordinal_type LO;
typedef TP_Vec::global_ordinal_type GO;
typedef TP_Vec::node_type NT;
Teuchos::GlobalMPISession mpiSession(&argc, &argv);
RCP<Stratimikos::DefaultLinearSolverBuilder> linearSolverBuilder =
Teuchos::rcp(new Stratimikos::DefaultLinearSolverBuilder);
RCP<TP_Crs> crsMat = Tpetra::MatrixMarket::Reader<TP_Crs>::readSparseFile(
"../data/nsjac.mm", Tpetra::getDefaultComm());
RCP<TP_Crs> zeroCrsMat = rcp(new TP_Crs(*crsMat, Teuchos::Copy));
zeroCrsMat->setAllToScalar(0.0);
RCP<TP_Op> Mat = crsMat;
RCP<TP_Op> zeroMat = zeroCrsMat;
RCP<TP_Vec> x0_tp = rcp(new TP_Vec(Mat->getDomainMap()));
RCP<TP_Vec> x1_tp = rcp(new TP_Vec(Mat->getDomainMap()));
RCP<TP_Vec> b0_tp = rcp(new TP_Vec(Mat->getRangeMap()));
RCP<TP_Vec> b1_tp = rcp(new TP_Vec(Mat->getRangeMap()));
b0_tp->randomize();
b1_tp->randomize();
RCP<const Thyra::TpetraVectorSpace<ST, LO, GO, NT> > domain =
Thyra::tpetraVectorSpace<ST>(Mat->getDomainMap());
RCP<const Thyra::TpetraVectorSpace<ST, LO, GO, NT> > range =
Thyra::tpetraVectorSpace<ST>(Mat->getRangeMap());
Teko::MultiVector x0_th = Thyra::tpetraVector(domain, x0_tp);
Teko::MultiVector x1_th = Thyra::tpetraVector(domain, x1_tp);
Teko::MultiVector b0_th = Thyra::tpetraVector(range, b0_tp);
Teko::MultiVector b1_th = Thyra::tpetraVector(range, b1_tp);
std::vector<Teko::MultiVector> x_vec;
x_vec.push_back(x0_th);
x_vec.push_back(x1_th);
std::vector<Teko::MultiVector> b_vec;
b_vec.push_back(b0_th);
b_vec.push_back(b1_th);
Teko::MultiVector x =
Teko::buildBlockedMultiVector(x_vec);
Teko::MultiVector b = Teko::buildBlockedMultiVector(b_vec);
Teko::LinearOp thMat = Thyra::tpetraLinearOp<double>(range, domain, Mat);
Teko::LinearOp thZero = Thyra::tpetraLinearOp<double>(range, domain, zeroMat);
Teko::LinearOp A =
Thyra::block2x2(thMat, thZero, thZero, thMat);
RCP<Teko::InverseLibrary> invLib =
Teko::InverseLibrary::buildFromParameterList(*buildLibPL(), linearSolverBuilder);
RCP<Teko::InverseFactory> inverse = invLib->getInverseFactory("Gauss-Seidel");
Teko::LinearOp prec = Teko::buildInverse(*inverse, A);
Teuchos::ParameterList belosList;
belosList.set("Num Blocks", 200);
belosList.set("Block Size", 1);
belosList.set("Maximum Iterations", 200);
belosList.set("Maximum Restarts", 1);
belosList.set("Convergence Tolerance", 1e-5);
belosList.set(
"Verbosity",
33);
belosList.set("Output Frequency", 1);
belosList.set("Output Style", 1);
RCP<Belos::LinearProblem<double, MV, OP> > problem =
rcp(new Belos::LinearProblem<double, MV, OP>(A, x, b));
problem->setLeftPrec(prec);
problem->setProblem();
RCP<Belos::SolverManager<double, MV, OP> > solver =
rcp(new Belos::BlockGmresSolMgr<double, MV, OP>(problem, rcpFromRef(belosList)));
Belos::ReturnType ret = solver->solve();
if (ret != Belos::Converged) {
std::cout << std::endl << "ERROR: Belos did not converge!" << std::endl;
return -1;
}
return 0;
}
RCP<Teuchos::ParameterList> buildLibPL() {
RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList());
{
Teuchos::ParameterList& sub_jac = pl->sublist("Jacobi");
sub_jac.set("Type", "Block Jacobi");
sub_jac.set("Inverse Type", "Ifpack2");
Teuchos::ParameterList& sub_gs = pl->sublist("Gauss-Seidel");
sub_gs.set("Type", "Block Gauss-Seidel");
sub_gs.set("Use Upper Triangle", true);
sub_gs.set("Inverse Type", "Ifpack2");
}
return pl;
}
Full source (native Tpetra path):
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_RCP.hpp"
#include "Tpetra_Core.hpp"
#include "Tpetra_CrsMatrix.hpp"
#include "Tpetra_Vector.hpp"
#include "Tpetra_MultiVector.hpp"
#include "MatrixMarket_Tpetra.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_InverseLibrary.hpp"
#include "Teko_StridedTpetraOperator.hpp"
#include "Teko_TpetraBlockPreconditioner.hpp"
#include "Teko_LSCPreconditionerFactory.hpp"
#include "Teko_InvLSCStrategy.hpp"
#include "Teko_SIMPLEPreconditionerFactory.hpp"
#include "Teko_ConfigDefs.hpp"
#include "BelosConfigDefs.hpp"
#include "BelosLinearProblem.hpp"
#include "BelosBlockGmresSolMgr.hpp"
#include "BelosTpetraAdapter.hpp"
#include <iostream>
#include <vector>
using Teuchos::RCP;
using Teuchos::rcp;
void run_driver() {
using ST = double;
using LO = Teko::LO;
using GO = Teko::GO;
using NT = Teko::NT;
using map_t = Tpetra::Map<LO, GO, NT>;
using crs_t = Tpetra::CrsMatrix<ST, LO, GO, NT>;
using vec_t = Tpetra::Vector<ST, LO, GO, NT>;
using mv_t = Tpetra::MultiVector<ST, LO, GO, NT>;
using op_t = Tpetra::Operator<ST, LO, GO, NT>;
auto comm = Tpetra::getDefaultComm();
RCP<crs_t> A = Tpetra::MatrixMarket::Reader<crs_t>::readSparseFile("../data/nsjac.mm", comm);
RCP<const map_t> rangeMap = A->getRangeMap();
RCP<const map_t> domainMap = A->getDomainMap();
RCP<vec_t> b = Tpetra::MatrixMarket::Reader<crs_t>::readVectorFile("../data/nsrhs_test.mm", comm,
rangeMap, false, false);
RCP<vec_t> x = rcp(new vec_t(domainMap));
std::vector<int> vec(2);
vec[0] = 2;
vec[1] = 1;
Teuchos::RCP<Teko::TpetraHelpers::StridedTpetraOperator> sA =
Teuchos::rcp(new Teko::TpetraHelpers::StridedTpetraOperator(vec, A));
RCP<Teko::InverseLibrary> invLib =
Teko::InverseLibrary::buildFromStratimikos();
RCP<Teko::InverseFactory> inverse
= invLib->getInverseFactory("Amesos2");
RCP<Teko::NS::LSCStrategy> strategy =
RCP<Teko::BlockPreconditionerFactory> precFact =
precFact);
prec.buildPreconditioner(sA);
RCP<mv_t> X = x;
RCP<mv_t> B = b;
using problem_t = Belos::LinearProblem<ST, mv_t, op_t>;
RCP<problem_t> problem = rcp(new problem_t(A, X, B));
RCP<op_t> precOp = Teuchos::rcp(&prec, false);
problem->setRightPrec(precOp);
const bool set = problem->setProblem();
TEUCHOS_TEST_FOR_EXCEPTION(!set, std::runtime_error,
"Belos::LinearProblem::setProblem() failed.");
using solver_t = Belos::BlockGmresSolMgr<ST, mv_t, op_t>;
Teuchos::ParameterList belosList;
belosList.set("Maximum Iterations", 1000);
belosList.set("Convergence Tolerance", 1e-5);
belosList.set("Num Blocks", 1000);
belosList.set("Verbosity",
Belos::Errors + Belos::Warnings + Belos::IterationDetails + Belos::FinalSummary);
belosList.set("Output Frequency", 10);
solver_t solver(problem, rcpFromRef(belosList));
Belos::ReturnType result = solver.solve();
TEUCHOS_TEST_FOR_EXCEPTION(result != Belos::Converged, std::runtime_error,
"Belos solver failed to converge.");
}
int main(int argc, char* argv[]) {
Tpetra::ScopeGuard tpetraScope(&argc, &argv);
{ run_driver(); }
return 0;
}
A strategy that takes a single inverse factory and uses that for all inverses. If no mass matrix is p...
Least-Squares Commutator (LSC) block preconditioner factory for incompressible Navier-Stokes saddle-p...
A single Tpetra wrapper for all the BlockPreconditioners.
StridedSolve — SIMPLE on a strided operator, solver chosen at runtime
examples/StridedSolve/strided_solve.cpp reads ../data/nsjac.mm, splits it with a strided operator, and builds a SIMPLE preconditioner (Teko::NS::SIMPLEPreconditionerFactory(inverse, alpha)). The inner solver name is read from solverparams.xml (an ordinary Stratimikos solver list), so you can swap Amesos2/Belos/… without recompiling. A good template for "drive the inner solver from XML while building the
block structure in code."
Full source:
#include <sys/types.h>
#include <unistd.h>
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_FancyOStream.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_XMLParameterListHelpers.hpp"
#include "Teuchos_CommHelpers.hpp"
#include "Thyra_LinearOpBase.hpp"
#include "Thyra_TpetraLinearOp.hpp"
#include "Thyra_TpetraThyraWrappers.hpp"
#include "Tpetra_Core.hpp"
#include "Tpetra_Map.hpp"
#include "Tpetra_CrsMatrix.hpp"
#include "Tpetra_Vector.hpp"
#include "Tpetra_MultiVector.hpp"
#include "MatrixMarket_Tpetra.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_SIMPLEPreconditionerFactory.hpp"
#include "Teko_LSCPreconditionerFactory.hpp"
#include "Teko_StridedTpetraOperator.hpp"
#include "Teko_TpetraBlockPreconditioner.hpp"
#include "Teko_ConfigDefs.hpp"
#include "BelosConfigDefs.hpp"
#include "BelosLinearProblem.hpp"
#include "BelosBlockGmresSolMgr.hpp"
#include "BelosTpetraAdapter.hpp"
#include <iostream>
#include <fstream>
#include <cmath>
#include <string>
#include <vector>
using Teuchos::FancyOStream;
using Teuchos::ParameterList;
using Teuchos::RCP;
using Teuchos::rcp;
void run_driver(std::string solveName) {
RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
using ST = double;
using LO = Teko::LO;
using GO = Teko::GO;
using NT = Teko::NT;
using map_t = Tpetra::Map<LO, GO, NT>;
using crs_t = Tpetra::CrsMatrix<ST, LO, GO, NT>;
using vec_t = Tpetra::Vector<ST, LO, GO, NT>;
using mv_t = Tpetra::MultiVector<ST, LO, GO, NT>;
using op_t = Tpetra::Operator<ST, LO, GO, NT>;
auto comm = Tpetra::getDefaultComm();
RCP<FancyOStream> fos = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
fos->setOutputToRootOnly(0);
*fos << "Using \"" << solveName << "\" for approximate solve" << std::endl;
const int numProc = comm->getSize();
const int myPID = comm->getRank();
std::cout << "MPI_PID = " << myPID << ", UNIX_PID = " << getpid() << std::endl;
*out << "Approaching Barrier: proc = " << numProc << ", pid = " << myPID << std::endl;
Teuchos::barrier(*comm);
RCP<Teuchos::ParameterList> paramList = Teuchos::getParametersFromXmlFile("solverparams.xml");
*fos << "Reading matrix market file" << std::endl;
RCP<crs_t> A = Tpetra::MatrixMarket::Reader<crs_t>::readSparseFile("../data/nsjac.mm", comm);
RCP<const map_t> rangeMap = A->getRangeMap();
RCP<const map_t> domainMap = A->getDomainMap();
RCP<vec_t> b = Tpetra::MatrixMarket::Reader<crs_t>::readVectorFile("../data/nsrhs_test.mm", comm,
rangeMap, false, false);
RCP<vec_t> x = Tpetra::MatrixMarket::Reader<crs_t>::readVectorFile("../data/nslhs_test.mm", comm,
domainMap, false, false);
*fos << "Building strided operator" << std::endl;
std::vector<int> vars(2);
vars[0] = 2;
vars[1] = 1;
Teuchos::RCP<Teko::TpetraHelpers::StridedTpetraOperator> sA =
Teuchos::rcp(new Teko::TpetraHelpers::StridedTpetraOperator(vars, A));
double alpha = 0.9;
RCP<Teko::InverseFactory> inverse = Teko::invFactoryFromParamList(*paramList, solveName);
RCP<Teko::BlockPreconditionerFactory> precFact =
*fos << "Preconditioner factory built" << std::endl;
prec.buildPreconditioner(sA);
*fos << "Preconditioner built" << std::endl;
RCP<mv_t> X = x;
RCP<mv_t> B = b;
using problem_t = Belos::LinearProblem<ST, mv_t, op_t>;
RCP<problem_t> problem = rcp(new problem_t(A, X, B));
RCP<op_t> precOp = Teuchos::rcp(&prec, false);
problem->setRightPrec(precOp);
const bool set = problem->setProblem();
TEUCHOS_TEST_FOR_EXCEPTION(!set, std::runtime_error,
"Belos::LinearProblem::setProblem() failed.");
*fos << "Setting solver parameters" << std::endl;
Teuchos::ParameterList belosList;
belosList.set("Maximum Iterations", 1000);
belosList.set("Convergence Tolerance", 1e-5);
belosList.set("Num Blocks", 50);
belosList.set("Verbosity",
Belos::Errors + Belos::Warnings + Belos::IterationDetails + Belos::FinalSummary);
belosList.set("Output Frequency", 10);
using solver_t = Belos::BlockGmresSolMgr<ST, mv_t, op_t>;
solver_t solver(problem, rcpFromRef(belosList));
*fos << "Solving" << std::endl;
Belos::ReturnType result = solver.solve();
TEUCHOS_TEST_FOR_EXCEPTION(result != Belos::Converged, std::runtime_error,
"Belos solver failed to converge.");
*fos << "Solve converged" << std::endl;
}
int main(int argc, char* argv[]) {
Tpetra::ScopeGuard tpetraScope(&argc, &argv);
{
std::string solveName = "Amesos2";
if (argc > 1) solveName = argv[1];
run_driver(solveName);
}
return 0;
}
Arbitrary Tpetra blocking — field blocks from monolithic GIDs
The strided examples assume a regular nodal ordering such as [u v p] at every mesh node. For application orderings that are not regular strides, use Teko::TpetraHelpers::BlockedTpetraOperator. It takes an explicit list of monolithic global IDs for each Teko block:
#include "Teko_BlockedTpetraOperator.hpp"
std::vector<std::vector<Teko::GO>> blockGIDs(3);
const auto baseMap = A->getDomainMap();
for (size_t lid = 0; lid < baseMap->getLocalNumElements(); ++lid) {
const Teko::GO gid = baseMap->getGlobalElement(static_cast<Teko::LO>(lid));
if (gidBelongsToVelocity(gid)) {
blockGIDs[0].push_back(gid);
} else if (gidBelongsToPressure(gid)) {
blockGIDs[1].push_back(gid);
} else {
blockGIDs[2].push_back(gid);
}
}
auto blockedA = Teuchos::rcp(
Tear about a user specified Tpetra::Operator<ST,LO,GO,NT> (CrsMatrix) using a vector of vectors of GI...
The outer vector entry is the Teko block number (blockGIDs[0] becomes block 0, and so on). Each inner vector is this MPI rank's owned monolithic GID list for that block. The wrapped operator is assumed to be square, with matching domain and range maps. The unit test tests/src/Tpetra/tBlockedTpetraOperator.cpp is the current in-tree reference for constructing these lists, checking BlockedTpetraOperator::testAgainstFullOperator, rebuilding after matrix value changes, and applying reorder managers. A small runnable example built from that test would be a useful addition to examples/.
AddMultiplyPrecs — composing preconditioners
examples/AddMultiplyPrecs/Driver.cpp builds a block Gauss–Seidel factory and a block Jacobi factory over the same diagonal strategy, then composes them:
RCP<Teko::InverseFactory> inverse =
Teko::invFactoryFromParamList(*paramList, "Amesos2");
RCP<Teko::BlockInvDiagonalStrategy> strategy =
RCP<Teko::BlockPreconditionerFactory> GSFactory =
RCP<Teko::BlockPreconditionerFactory> JacobiFactory =
RCP<Teko::BlockPreconditionerFactory> MasterFactory =
A factory that creates a block Gauss Seidel preconditioner. The user must specify the solvers (or pre...
The equivalent parameter-driven form uses the "Block Add" / "Block Multiply" block types with "Preconditioner A" / "Preconditioner B".
Full source:
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_FancyOStream.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_XMLParameterListHelpers.hpp"
#include "Teuchos_DefaultComm.hpp"
#include "Teuchos_ParameterList.hpp"
#include "Teuchos_CommHelpers.hpp"
#include "Thyra_LinearOpBase.hpp"
#include "Thyra_TpetraLinearOp.hpp"
#include "Thyra_TpetraThyraWrappers.hpp"
#include "Tpetra_Core.hpp"
#include "Tpetra_Map.hpp"
#include "Tpetra_CrsMatrix.hpp"
#include "Tpetra_Vector.hpp"
#include "Tpetra_MultiVector.hpp"
#include "MatrixMarket_Tpetra.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_JacobiPreconditionerFactory.hpp"
#include "Teko_GaussSeidelPreconditionerFactory.hpp"
#include "Teko_BlockInvDiagonalStrategy.hpp"
#include "Teko_StridedTpetraOperator.hpp"
#include "Teko_TpetraBlockPreconditioner.hpp"
#include "Teko_AddPreconditionerFactory.hpp"
#include "Teko_MultPreconditionerFactory.hpp"
#include "Teko_ConfigDefs.hpp"
#include "BelosConfigDefs.hpp"
#include "BelosLinearProblem.hpp"
#include "BelosBlockGmresSolMgr.hpp"
#include "BelosTpetraAdapter.hpp"
#include <iostream>
#include <vector>
using Teuchos::FancyOStream;
using Teuchos::ParameterList;
using Teuchos::RCP;
using Teuchos::rcp;
void run_driver() {
RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
using ST = double;
using LO = Teko::LO;
using GO = Teko::GO;
using NT = Teko::NT;
using map_t = Tpetra::Map<LO, GO, NT>;
using crs_t = Tpetra::CrsMatrix<ST, LO, GO, NT>;
using vec_t = Tpetra::Vector<ST, LO, GO, NT>;
using mv_t = Tpetra::MultiVector<ST, LO, GO, NT>;
using op_t = Tpetra::Operator<ST, LO, GO, NT>;
auto comm = Tpetra::getDefaultComm();
RCP<FancyOStream> fos = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
fos->setOutputToRootOnly(0);
const int numProc = comm->getSize();
const int myPID = comm->getRank();
*out << "Approaching Barrier: proc = " << numProc << ", pid = " << myPID << std::endl;
Teuchos::barrier(*comm);
RCP<Teuchos::ParameterList> paramList = Teuchos::getParametersFromXmlFile("solverparams.xml");
*fos << "Reading matrix market files" << std::endl;
RCP<crs_t> A = Tpetra::MatrixMarket::Reader<crs_t>::readSparseFile("./modified.mm", comm);
RCP<const map_t> rangeMap = A->getRangeMap();
RCP<const map_t> domainMap = A->getDomainMap();
RCP<vec_t> b = Tpetra::MatrixMarket::Reader<crs_t>::readVectorFile("./rhs_test.mm", comm,
rangeMap, false, false);
RCP<vec_t> x = Tpetra::MatrixMarket::Reader<crs_t>::readVectorFile("./lhs_test.mm", comm,
domainMap, false, false);
*fos << "Building strided operator" << std::endl;
std::vector<int> vars(2);
vars[0] = 2;
vars[1] = 1;
Teuchos::RCP<Teko::TpetraHelpers::StridedTpetraOperator> sA =
Teuchos::rcp(new Teko::TpetraHelpers::StridedTpetraOperator(vars, A));
RCP<Teko::InverseFactory> inverse = Teko::invFactoryFromParamList(*paramList, "Amesos2");
RCP<Teko::BlockPreconditionerFactory> GSFactory =
RCP<Teko::BlockPreconditionerFactory> JacobiFactory =
#ifdef ADD_PREC
RCP<Teko::BlockPreconditionerFactory> MasterFactory =
#else
RCP<Teko::BlockPreconditionerFactory> MasterFactory =
#endif
MyPreconditioner.buildPreconditioner(sA);
RCP<mv_t> X = x;
RCP<mv_t> B = rcp(new mv_t(b->getMap(), 1));
using problem_t = Belos::LinearProblem<ST, mv_t, op_t>;
RCP<problem_t> problem = rcp(new problem_t(A, X, B));
RCP<op_t> precOp = Teuchos::rcp(&MyPreconditioner, false);
problem->setRightPrec(precOp);
const bool set = problem->setProblem();
TEUCHOS_TEST_FOR_EXCEPTION(!set, std::runtime_error,
"Belos::LinearProblem::setProblem() failed.");
Teuchos::ParameterList belosList;
belosList.set("Maximum Iterations", 100);
belosList.set("Convergence Tolerance", 1e-5);
belosList.set("Num Blocks", 50);
belosList.set("Verbosity",
Belos::Errors + Belos::Warnings + Belos::IterationDetails + Belos::FinalSummary);
belosList.set("Output Frequency", 10);
using solver_t = Belos::BlockGmresSolMgr<ST, mv_t, op_t>;
solver_t solver(problem, rcpFromRef(belosList));
*fos << "Starting Belos solve" << std::endl;
Belos::ReturnType result = solver.solve();
TEUCHOS_TEST_FOR_EXCEPTION(result != Belos::Converged, std::runtime_error,
"Belos solver failed to converge.");
*fos << "Solve converged" << std::endl;
}
int main(int argc, char* argv[]) {
Tpetra::ScopeGuard tpetraScope(&argc, &argv);
{ run_driver(); }
return 0;
}
step1 — writing your own BlockPreconditionerFactory
examples/BuildPreconditioner/step1/ is the tutorial for extending Teko. To create a custom block preconditioner you subclass Teko::BlockPreconditionerFactory and override one method, buildPreconditionerOperator, using the block-operator utilities in Teko_Utilities.hpp:
Teko::LinearOp ExamplePreconditionerFactory::buildPreconditionerOperator(
const Teko::LinearOp A_00 = Teko::getBlock(0, 0, blockOp);
const Teko::LinearOp A_01 = Teko::getBlock(0, 1, blockOp);
const Teko::LinearOp A_10 = Teko::getBlock(1, 0, blockOp);
const Teko::LinearOp A_11 = Teko::getBlock(1, 1, blockOp);
const Teko::LinearOp invH = Teko::getInvDiagonalOp(A_11);
const Teko::LinearOp P = Teko::explicitAdd(A_00, Teko::scale(alpha_, A_01));
const Teko::LinearOp invP = Teko::buildInverse(*inverse_, P);
Teko::BlockedLinearOp L = Teko::zeroBlockedOp(blockOp);
Teko::setBlock(1, 0, L, A_10);
Teko::endBlockFill(L);
std::vector<Teko::LinearOp> invDiag = {invP, invH};
return Teko::createBlockLowerTriInverseOp(L, invDiag);
}
An implementation of a state object for block preconditioners.
Key utilities on display (all in Teko_Utilities.hpp): blockRowCount/blockColCount, getBlock, getInvDiagonalOp, explicitAdd, scale, buildInverse, zeroBlockedOp / setBlock / endBlockFill, and createBlockLowerTriInverseOp. The companion example-test.cpp shows how to assemble four Tpetra sub-blocks, wrap them with Thyra::tpetraLinearOp, combine with Teko::block2x2, and apply the resulting preconditioner. See Advanced Topics for how to register such a factory so it can be selected by a "Type" string, and for the state/rebuild pattern that extends this example to cache inverse and explicit operators across nonlinear or time-step updates.
Full source (the custom factory):
#include "Teko_BlockPreconditionerFactory.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_BlockLowerTriInverseOp.hpp"
#include "Teko_BlockUpperTriInverseOp.hpp"
using Teuchos::RCP;
class ExamplePreconditionerFactory
public:
ExamplePreconditionerFactory(const RCP<const Teko::InverseFactory>& inverse, double alpha);
protected:
RCP<const Teko::InverseFactory> inverse_;
double alpha_;
};
ExamplePreconditionerFactory
::ExamplePreconditionerFactory(const RCP<const Teko::InverseFactory>& inverse, double alpha)
: inverse_(inverse), alpha_(alpha) {}
Teko::LinearOp ExamplePreconditionerFactory
::buildPreconditionerOperator(Teko::BlockedLinearOp& blockOp,
int rows = Teko::blockRowCount(blockOp);
int cols = Teko::blockColCount(blockOp);
TEUCHOS_ASSERT(rows == 2);
TEUCHOS_ASSERT(cols == 2);
const Teko::LinearOp A_00 = Teko::getBlock(0, 0, blockOp);
const Teko::LinearOp A_01 = Teko::getBlock(0, 1, blockOp);
const Teko::LinearOp A_10 = Teko::getBlock(1, 0, blockOp);
const Teko::LinearOp A_11 = Teko::getBlock(1, 1, blockOp);
const Teko::LinearOp invH = Teko::getInvDiagonalOp(A_11);
const Teko::LinearOp P =
Teko::explicitAdd(A_00, Teko::scale(alpha_, A_01));
const Teko::LinearOp invP =
Teko::buildInverse(*inverse_, P);
Teko::BlockedLinearOp L = Teko::zeroBlockedOp(blockOp);
Teko::setBlock(1, 0, L, A_10);
Teko::endBlockFill(L);
std::vector<Teko::LinearOp> invDiag(
2);
invDiag[0] = invP;
invDiag[1] = invH;
Teko::LinearOp invTildeA =
Teko::createBlockLowerTriInverseOp(L, invDiag);
return invTildeA;
}
Abstract class which block preconditioner factories in Teko should be based on.
virtual LinearOp buildPreconditionerOperator(BlockedLinearOp &blo, BlockPreconditionerState &state) const =0
Function that is called to build the preconditioner for the linear operator that is passed in.
Full source (the driver that exercises it):
#include "Teuchos_ConfigDefs.hpp"
#include "Teuchos_RCP.hpp"
#include "Thyra_TpetraLinearOp.hpp"
#include "Thyra_TpetraThyraWrappers.hpp"
#include "Tpetra_Core.hpp"
#include "Tpetra_Map.hpp"
#include "Tpetra_CrsMatrix.hpp"
#include "Tpetra_Vector.hpp"
#include "Tpetra_MultiVector.hpp"
#include "Teko_InverseFactory.hpp"
#include "Teko_InverseLibrary.hpp"
#include "Teko_TpetraOperatorWrapper.hpp"
#include "Teko_TpetraBlockPreconditioner.hpp"
#include "Teko_ConfigDefs.hpp"
#include "ExamplePreconditionerFactory.cpp"
#include <iostream>
#include <vector>
using Teuchos::RCP;
using Teuchos::rcp;
RCP<Tpetra::CrsMatrix<Teko::ST, Teko::LO, Teko::GO, Teko::NT> > build2x2(
double a, double b, double c, double d, const RCP<const Teuchos::Comm<int> >& comm) {
using ST = Teko::ST;
using LO = Teko::LO;
using GO = Teko::GO;
using NT = Teko::NT;
using map_t = Tpetra::Map<LO, GO, NT>;
using crs_t = Tpetra::CrsMatrix<ST, LO, GO, NT>;
RCP<const map_t> map = rcp(new map_t(2, 0, comm));
RCP<crs_t> matrix = rcp(new crs_t(map, 2));
Teuchos::Array<GO> indices(2);
Teuchos::Array<ST> values(2);
indices[0] = 0;
indices[1] = 1;
if (map->isNodeGlobalElement(0)) {
values[0] = a;
values[1] = b;
matrix->insertGlobalValues(0, indices(), values());
}
if (map->isNodeGlobalElement(1)) {
values[0] = c;
values[1] = d;
matrix->insertGlobalValues(1, indices(), values());
}
matrix->fillComplete();
return matrix;
}
void run_test() {
using ST = Teko::ST;
using LO = Teko::LO;
using GO = Teko::GO;
using NT = Teko::NT;
using vec_t = Tpetra::Vector<ST, LO, GO, NT>;
using mv_t = Tpetra::MultiVector<ST, LO, GO, NT>;
auto comm = Tpetra::getDefaultComm();
auto mat_00 = build2x2(1, 2, 2, 1, comm);
Teko::LinearOp A_00 = Thyra::tpetraLinearOp<ST, LO, GO, NT>(
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_00->getRangeMap()),
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_00->getDomainMap()), mat_00);
auto mat_01 = build2x2(0, -1, 3, 4, comm);
Teko::LinearOp A_01 = Thyra::tpetraLinearOp<ST, LO, GO, NT>(
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_01->getRangeMap()),
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_01->getDomainMap()), mat_01);
auto mat_10 = build2x2(1, 6, -3, 2, comm);
Teko::LinearOp A_10 = Thyra::tpetraLinearOp<ST, LO, GO, NT>(
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_10->getRangeMap()),
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_10->getDomainMap()), mat_10);
auto mat_11 = build2x2(2, 1, 1, 2, comm);
Teko::LinearOp A_11 = Thyra::tpetraLinearOp<ST, LO, GO, NT>(
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_11->getRangeMap()),
Thyra::tpetraVectorSpace<ST, LO, GO, NT>(mat_11->getDomainMap()), mat_11);
Teuchos::RCP<Teko::TpetraHelpers::TpetraOperatorWrapper> A = Teuchos::rcp(
RCP<vec_t> b = rcp(new vec_t(A->getRangeMap()));
RCP<vec_t> x = rcp(new vec_t(A->getDomainMap()));
b->replaceGlobalValue(0, 1.0);
b->replaceGlobalValue(1, 2.0);
b->replaceGlobalValue(2, 3.0);
b->replaceGlobalValue(3, 4.0);
RCP<Teko::InverseLibrary> invLib = Teko::InverseLibrary::buildFromStratimikos();
RCP<const Teko::InverseFactory> inverse = invLib->getInverseFactory("Amesos2");
RCP<Teko::BlockPreconditionerFactory> precFact =
rcp(new ExamplePreconditionerFactory(inverse, 0.9));
prec.buildPreconditioner(A);
RCP<mv_t> B = b;
RCP<mv_t> X = x;
prec.apply(*B, *X);
x->describe(*(Teuchos::VerboseObjectBase::getDefaultOStream()),
Teuchos::EVerbosityLevel::VERB_EXTREME);
}
int main(int argc, char* argv[]) {
Tpetra::ScopeGuard tpetraScope(&argc, &argv);
{ run_test(); }
return 0;
}
Implements the Tpetra::Operator interface with a Thyra LinearOperator. This enables the use of absrta...