43 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
44 #include "Thyra_PreconditionerFactoryHelpers.hpp"
45 #include "Thyra_DefaultInverseLinearOp.hpp"
46 #include "Thyra_DefaultMultipliedLinearOp.hpp"
50 #include "Thyra_TestingTools.hpp"
51 #include "EpetraExt_CrsMatrixIn.h"
52 #include "Epetra_CrsMatrix.h"
60 # include "Epetra_MpiComm.h"
62 # include "Epetra_SerialComm.h"
80 readEpetraCrsMatrixFromMatrixMarket(
81 const std::string fileName,
const Epetra_Comm &comm
84 Epetra_CrsMatrix *
A = 0;
86 0!=EpetraExt::MatrixMarketFileToCrsMatrix( fileName.c_str(), comm, A ),
88 "Error, could not read matrix file \""<<fileName<<
"\"!"
96 readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
97 const std::string fileName,
const Epetra_Comm &comm,
98 const std::string &label
101 return Thyra::epetraLinearOp(
102 readEpetraCrsMatrixFromMatrixMarket(fileName,comm),label
110 int main(
int argc,
char* argv[])
113 using Teuchos::describe;
115 using Teuchos::rcp_dynamic_cast;
116 using Teuchos::rcp_const_cast;
120 using Teuchos::sublist;
122 using Thyra::inverse;
123 using Thyra::initializePreconditionedOp;
124 using Thyra::initializeOp;
125 using Thyra::unspecifiedPrec;
127 typedef RCP<const Thyra::LinearOpBase<double> > LinearOpPtr;
128 typedef RCP<Thyra::VectorBase<double> > VectorPtr;
136 out = Teuchos::VerboseObjectBase::getDefaultOStream();
144 const int numVerbLevels = 6;
154 {
"default",
"none",
"low",
"medium",
"high",
"extreme" };
157 std::string paramsFile =
"";
158 std::string extraParamsFile =
"";
159 std::string baseDir =
".";
160 bool useP1Prec =
true;
161 bool invertP1 =
false;
162 bool showParams =
false;
163 double solveTol = 1e-8;
165 CommandLineProcessor clp(
false);
167 clp.setOption(
"verb-level", &verbLevel,
168 numVerbLevels, verbLevelValues, verbLevelNames,
169 "Verbosity level used for all objects."
171 clp.setOption(
"params-file", ¶msFile,
172 "File containing parameters in XML format.",
175 clp.setOption(
"extra-params-file", &extraParamsFile,
176 "File containing extra parameters in XML format."
178 clp.setOption(
"base-dir", &baseDir,
179 "Base directory for all of the files."
181 clp.setOption(
"use-P1-prec",
"use-algebraic-prec", &useP1Prec,
182 "Use the physics-based preconditioner for P2 based on P1 or just an algebraic preconditioner"
184 clp.setOption(
"invert-P1",
"prec-P1-only", &invertP1,
185 "In the physics-based preconditioner, use P1's preconditioner or fully invert P1."
187 clp.setOption(
"solve-tol", &solveTol,
188 "Tolerance for the solution to determine success or failure!"
190 clp.setOption(
"show-params",
"no-show-params", &showParams,
191 "Show the parameter list or not."
194 "This example program shows an attempt to create a physics-based\n"
195 "preconditioner using the building blocks of Stratimikos and Thyra\n"
196 "implicit linear operators. The idea is to use the linear operator\n"
197 "for first-order Lagrange finite elements as the preconditioner for the\n"
198 "operator using second-order Lagrange finite elements. The details of the\n"
199 "PDE being represented, the mesh being used, or the boundary conditions are\n"
200 "beyond the scope of this example.\n"
202 "The matrices used in this example are:\n"
204 " P2: The discretized PDE matrix using second-order Lagrange finite elements.\n"
205 " P1: The discretized PDE matrix using first-order Lagrange finite elements.\n"
206 " M22: The mass matrix for the second-order Lagrange finite-element basis functions.\n"
207 " M11: The mass matrix for the first-order Lagrange finite-element basis functions.\n"
208 " M21: A rectangular matrix that uses mixed first- and second-order basis functions\n"
209 " to map from P2 space to P1 space.\n"
210 " M12: A rectangular matrix that uses mixed first- and second-order basis functions\n"
211 " to map from P1 space to P2 space.\n"
213 "The above matrices are read from Matrix Market *.mtx files in the directory given by\n"
214 "the --base-dir command-line option.\n"
216 "The preconditioner operator created in this example program is:\n"
218 " precP2Op = (inv(M22) * M12) * prec(P1) * (inv(M11) * M21)\n"
220 "where prec(P1) is either the algebraic preconditioner for P1 (--prec-P1-only)\n"
221 "or is a full solve for P1 (--invert-P1).\n"
223 "We use Stratimikos to specify the linear solvers and/or algebraic\n"
224 "preconditioners and we use the Thyra implicit operators to build the\n"
225 "implicitly multiplied linear operators associated with the preconditioner.\n"
227 "Warning! This physics-based preconditioner is singular and can not\n"
228 "be used to solve the linear system given a random right-hand side. However,\n"
229 "singular or not, this example shows how one can use Thyra/Stratimikos to quickly\n"
230 "try out these types of preconditioning ideas (even if they do not work).\n"
235 CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
236 if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL )
return parse_return;
240 *out <<
"\nA) Reading in Epetra_CrsMatrix objects for P1, P2, M11, M12, M21, and M22 ...\n";
244 Epetra_MpiComm comm(MPI_COMM_WORLD);
246 Epetra_SerialComm comm;
249 LinearOpPtr P1=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
250 baseDir+
"/P1.mtx",comm,
"P1");
251 *out <<
"\nP1 = " << describe(*P1,verbLevel) <<
"\n";
252 LinearOpPtr P2= readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
253 baseDir+
"/P2.mtx",comm,
"P2");
254 *out <<
"\nP2 = " << describe(*P2,verbLevel) <<
"\n";
255 LinearOpPtr M11=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
256 baseDir+
"/M11.mtx",comm,
"M11");
257 *out <<
"\nM11 = " << describe(*M11,verbLevel) <<
"\n";
258 LinearOpPtr M22=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
259 baseDir+
"/M22.mtx",comm,
"M22");
260 *out <<
"\nM22 = " << describe(*M22,verbLevel) <<
"\n";
261 LinearOpPtr M12=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
262 baseDir+
"/M12.mtx",comm,
"M12");
263 *out <<
"\nM12 = " << describe(*M12,verbLevel) <<
"\n";
264 LinearOpPtr M21=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
265 baseDir+
"/M21.mtx",comm,
"M21");
266 *out <<
"\nM21 = " << describe(*M21,verbLevel) <<
"\n";
272 *out <<
"\nB) Get the preconditioner and/or linear solver strategies to invert M11, M22, P1, and P2 ...\n";
280 RCP<ParameterList> paramList =
281 Teuchos::getParametersFromXmlFile( baseDir+
"/"+paramsFile );
282 if (extraParamsFile.length()) {
283 Teuchos::updateParametersFromXmlFile( baseDir+
"/"+extraParamsFile, paramList.ptr() );
286 *out <<
"\nRead in parameter list:\n\n";
287 paramList->print(*out,PLPrintOptions().indent(2).showTypes(
true));
292 sublist(paramList,
"M11 Solver",
true) );
296 sublist(paramList,
"M22 Solver",
true) );
300 sublist(paramList,
"P1 Solver",
true) );
304 sublist(paramList,
"P2 Solver",
true) );
314 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > M11_linsolve_strategy
315 = createLinearSolveStrategy(M11_linsolve_strategy_builder);
317 RCP<Thyra::LinearOpWithSolveFactoryBase<double> > M22_linsolve_strategy
318 = createLinearSolveStrategy(M22_linsolve_strategy_builder);
322 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P1_linsolve_strategy;
323 RCP<const Thyra::PreconditionerFactoryBase<double> > P1_prec_strategy;
326 = createLinearSolveStrategy(P1_linsolve_strategy_builder);
329 = createPreconditioningStrategy(P1_linsolve_strategy_builder);
334 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P2_linsolve_strategy
335 = createLinearSolveStrategy(P2_linsolve_strategy_builder);
338 *out <<
"\nC) Create the physics-based preconditioner! ...\n";
341 *out <<
"\nCreating inv(M11) ...\n";
342 LinearOpPtr invM11 = inverse(*M11_linsolve_strategy, M11);
343 *out <<
"\ninvM11 = " << describe(*invM11,verbLevel) <<
"\n";
345 *out <<
"\nCreating inv(M22) ...\n";
346 LinearOpPtr invM22 = inverse(*M22_linsolve_strategy, M22);
347 *out <<
"\ninvM22 = " << describe(*invM22,verbLevel) <<
"\n";
349 *out <<
"\nCreating prec(P1) ...\n";
352 *out <<
"\nCreating prec(P1) as a full solver ...\n";
353 invP1 = inverse(*P1_linsolve_strategy, P1);
356 *out <<
"\nCreating prec(P1) as just an algebraic preconditioner ...\n";
357 RCP<Thyra::PreconditionerBase<double> >
358 precP1 = prec(*P1_prec_strategy,P1);
359 *out <<
"\nprecP1 = " << describe(*precP1,verbLevel) <<
"\n";
360 invP1 = precP1->getUnspecifiedPrecOp();
362 rcp_const_cast<Thyra::LinearOpBase<double> >(
363 invP1)->setObjectLabel(
"invP1");
364 *out <<
"\ninvP1 = " << describe(*invP1,verbLevel) <<
"\n";
366 LinearOpPtr P2ToP1 = multiply( invM11, M21 );
367 *out <<
"\nP2ToP1 = " << describe(*P2ToP1,verbLevel) <<
"\n";
369 LinearOpPtr P1ToP2 = multiply( invM22, M12 );
370 *out <<
"\nP1ToP2 = " << describe(*P1ToP2,verbLevel) <<
"\n";
372 LinearOpPtr precP2Op = multiply( P1ToP2, invP1, P2ToP1 );
373 *out <<
"\nprecP2Op = " << describe(*precP2Op,verbLevel) <<
"\n";
376 *out <<
"\nD) Setup the solver for P2 ...\n";
379 RCP<Thyra::LinearOpWithSolveBase<double> >
380 P2_lows = P2_linsolve_strategy->createOp();
382 *out <<
"\nCreating the solver P2 using the specialized precP2Op\n";
383 initializePreconditionedOp<double>( *P2_linsolve_strategy, P2,
384 unspecifiedPrec(precP2Op), P2_lows.ptr());
387 *out <<
"\nCreating the solver P2 using algebraic preconditioner\n";
388 initializeOp(*P2_linsolve_strategy, P2, P2_lows.ptr());
390 *out <<
"\nP2_lows = " << describe(*P2_lows, verbLevel) <<
"\n";
393 *out <<
"\nE) Solve P2 for a random RHS ...\n";
396 VectorPtr x = createMember(P2->domain());
397 VectorPtr b = createMember(P2->range());
398 Thyra::randomize(-1.0, +1.0, b.ptr());
399 Thyra::assign(x.ptr(), 0.0);
401 Thyra::SolveStatus<double>
402 solveStatus = solve<double>( *P2_lows, Thyra::NOTRANS, *b, x.ptr() );
404 *out <<
"\nSolve status:\n" << solveStatus;
406 *out <<
"\nSolution ||x|| = " << Thyra::norm(*x) <<
"\n";
409 *out <<
"\nParameter list after use:\n\n";
410 paramList->print(*out, PLPrintOptions().indent(2).showTypes(
true));
414 *out <<
"\nF) Checking the error in the solution of r=b-P2*x ...\n";
417 VectorPtr P2x = Thyra::createMember(b->space());
418 Thyra::apply( *P2, Thyra::NOTRANS, *x, P2x.ptr() );
419 VectorPtr r = Thyra::createMember(b->space());
420 Thyra::V_VmV<double>(r.ptr(), *b, *P2x);
423 P2x_nrm = Thyra::norm(*P2x),
424 r_nrm = Thyra::norm(*r),
425 b_nrm = Thyra::norm(*b),
426 r_nrm_over_b_nrm = r_nrm / b_nrm;
428 bool result = r_nrm_over_b_nrm <= solveTol;
429 if(!result) success =
false;
432 <<
"\n||P2*x|| = " << P2x_nrm <<
"\n";
435 <<
"\n||P2*x-b||/||b|| = " << r_nrm <<
"/" << b_nrm
436 <<
" = " << r_nrm_over_b_nrm <<
" <= " << solveTol
437 <<
" : " << Thyra::passfail(result) <<
"\n";
444 if(success) *out <<
"\nCongratulations! All of the tests checked out!\n";
445 else *out <<
"\nOh no! At least one of the tests failed!\n";
448 return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
int main(int argc, char *argv[])
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void setParameterList(RCP< ParameterList > const ¶mList)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static void summarize(Ptr< const Comm< int > > comm, std::ostream &out=std::cout, const bool alwaysWriteLocal=false, const bool writeGlobalStats=true, const bool writeZeroTimers=true, const ECounterSetOp setOp=Intersection, const std::string &filter="", const bool ignoreZeroTimers=false)
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
ParameterList::PrintOptions PLPrintOptions
Concrete subclass of Thyra::LinearSolverBuilderBase for creating LinearOpWithSolveFactoryBase objects...