11 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
12 #include "Thyra_PreconditionerFactoryHelpers.hpp"
13 #include "Thyra_DefaultInverseLinearOp.hpp"
14 #include "Thyra_DefaultMultipliedLinearOp.hpp"
18 #include "Thyra_TestingTools.hpp"
19 #include "EpetraExt_CrsMatrixIn.h"
20 #include "Epetra_CrsMatrix.h"
28 # include "Epetra_MpiComm.h"
30 # include "Epetra_SerialComm.h"
48 readEpetraCrsMatrixFromMatrixMarket(
49 const std::string fileName,
const Epetra_Comm &comm
52 Epetra_CrsMatrix *
A = 0;
54 0!=EpetraExt::MatrixMarketFileToCrsMatrix( fileName.c_str(), comm, A ),
56 "Error, could not read matrix file \""<<fileName<<
"\"!"
64 readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
65 const std::string fileName,
const Epetra_Comm &comm,
66 const std::string &label
69 return Thyra::epetraLinearOp(
70 readEpetraCrsMatrixFromMatrixMarket(fileName,comm),label
78 int main(
int argc,
char* argv[])
81 using Teuchos::describe;
83 using Teuchos::rcp_dynamic_cast;
84 using Teuchos::rcp_const_cast;
88 using Teuchos::sublist;
91 using Thyra::initializePreconditionedOp;
92 using Thyra::initializeOp;
93 using Thyra::unspecifiedPrec;
95 typedef RCP<const Thyra::LinearOpBase<double> > LinearOpPtr;
96 typedef RCP<Thyra::VectorBase<double> > VectorPtr;
104 out = Teuchos::VerboseObjectBase::getDefaultOStream();
112 const int numVerbLevels = 6;
122 {
"default",
"none",
"low",
"medium",
"high",
"extreme" };
125 std::string paramsFile =
"";
126 std::string extraParamsFile =
"";
127 std::string baseDir =
".";
128 bool useP1Prec =
true;
129 bool invertP1 =
false;
130 bool showParams =
false;
131 double solveTol = 1e-8;
133 CommandLineProcessor clp(
false);
135 clp.setOption(
"verb-level", &verbLevel,
136 numVerbLevels, verbLevelValues, verbLevelNames,
137 "Verbosity level used for all objects."
139 clp.setOption(
"params-file", ¶msFile,
140 "File containing parameters in XML format.",
143 clp.setOption(
"extra-params-file", &extraParamsFile,
144 "File containing extra parameters in XML format."
146 clp.setOption(
"base-dir", &baseDir,
147 "Base directory for all of the files."
149 clp.setOption(
"use-P1-prec",
"use-algebraic-prec", &useP1Prec,
150 "Use the physics-based preconditioner for P2 based on P1 or just an algebraic preconditioner"
152 clp.setOption(
"invert-P1",
"prec-P1-only", &invertP1,
153 "In the physics-based preconditioner, use P1's preconditioner or fully invert P1."
155 clp.setOption(
"solve-tol", &solveTol,
156 "Tolerance for the solution to determine success or failure!"
158 clp.setOption(
"show-params",
"no-show-params", &showParams,
159 "Show the parameter list or not."
162 "This example program shows an attempt to create a physics-based\n"
163 "preconditioner using the building blocks of Stratimikos and Thyra\n"
164 "implicit linear operators. The idea is to use the linear operator\n"
165 "for first-order Lagrange finite elements as the preconditioner for the\n"
166 "operator using second-order Lagrange finite elements. The details of the\n"
167 "PDE being represented, the mesh being used, or the boundary conditions are\n"
168 "beyond the scope of this example.\n"
170 "The matrices used in this example are:\n"
172 " P2: The discretized PDE matrix using second-order Lagrange finite elements.\n"
173 " P1: The discretized PDE matrix using first-order Lagrange finite elements.\n"
174 " M22: The mass matrix for the second-order Lagrange finite-element basis functions.\n"
175 " M11: The mass matrix for the first-order Lagrange finite-element basis functions.\n"
176 " M21: A rectangular matrix that uses mixed first- and second-order basis functions\n"
177 " to map from P2 space to P1 space.\n"
178 " M12: A rectangular matrix that uses mixed first- and second-order basis functions\n"
179 " to map from P1 space to P2 space.\n"
181 "The above matrices are read from Matrix Market *.mtx files in the directory given by\n"
182 "the --base-dir command-line option.\n"
184 "The preconditioner operator created in this example program is:\n"
186 " precP2Op = (inv(M22) * M12) * prec(P1) * (inv(M11) * M21)\n"
188 "where prec(P1) is either the algebraic preconditioner for P1 (--prec-P1-only)\n"
189 "or is a full solve for P1 (--invert-P1).\n"
191 "We use Stratimikos to specify the linear solvers and/or algebraic\n"
192 "preconditioners and we use the Thyra implicit operators to build the\n"
193 "implicitly multiplied linear operators associated with the preconditioner.\n"
195 "Warning! This physics-based preconditioner is singular and can not\n"
196 "be used to solve the linear system given a random right-hand side. However,\n"
197 "singular or not, this example shows how one can use Thyra/Stratimikos to quickly\n"
198 "try out these types of preconditioning ideas (even if they do not work).\n"
203 CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
204 if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL )
return parse_return;
208 *out <<
"\nA) Reading in Epetra_CrsMatrix objects for P1, P2, M11, M12, M21, and M22 ...\n";
212 Epetra_MpiComm comm(MPI_COMM_WORLD);
214 Epetra_SerialComm comm;
217 LinearOpPtr P1=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
218 baseDir+
"/P1.mtx",comm,
"P1");
219 *out <<
"\nP1 = " << describe(*P1,verbLevel) <<
"\n";
220 LinearOpPtr P2= readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
221 baseDir+
"/P2.mtx",comm,
"P2");
222 *out <<
"\nP2 = " << describe(*P2,verbLevel) <<
"\n";
223 LinearOpPtr M11=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
224 baseDir+
"/M11.mtx",comm,
"M11");
225 *out <<
"\nM11 = " << describe(*M11,verbLevel) <<
"\n";
226 LinearOpPtr M22=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
227 baseDir+
"/M22.mtx",comm,
"M22");
228 *out <<
"\nM22 = " << describe(*M22,verbLevel) <<
"\n";
229 LinearOpPtr M12=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
230 baseDir+
"/M12.mtx",comm,
"M12");
231 *out <<
"\nM12 = " << describe(*M12,verbLevel) <<
"\n";
232 LinearOpPtr M21=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
233 baseDir+
"/M21.mtx",comm,
"M21");
234 *out <<
"\nM21 = " << describe(*M21,verbLevel) <<
"\n";
240 *out <<
"\nB) Get the preconditioner and/or linear solver strategies to invert M11, M22, P1, and P2 ...\n";
248 RCP<ParameterList> paramList =
249 Teuchos::getParametersFromXmlFile( baseDir+
"/"+paramsFile );
250 if (extraParamsFile.length()) {
251 Teuchos::updateParametersFromXmlFile( baseDir+
"/"+extraParamsFile, paramList.ptr() );
254 *out <<
"\nRead in parameter list:\n\n";
255 paramList->print(*out,PLPrintOptions().indent(2).showTypes(
true));
260 sublist(paramList,
"M11 Solver",
true) );
264 sublist(paramList,
"M22 Solver",
true) );
268 sublist(paramList,
"P1 Solver",
true) );
272 sublist(paramList,
"P2 Solver",
true) );
282 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > M11_linsolve_strategy
283 = createLinearSolveStrategy(M11_linsolve_strategy_builder);
285 RCP<Thyra::LinearOpWithSolveFactoryBase<double> > M22_linsolve_strategy
286 = createLinearSolveStrategy(M22_linsolve_strategy_builder);
290 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P1_linsolve_strategy;
291 RCP<const Thyra::PreconditionerFactoryBase<double> > P1_prec_strategy;
294 = createLinearSolveStrategy(P1_linsolve_strategy_builder);
297 = createPreconditioningStrategy(P1_linsolve_strategy_builder);
302 RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P2_linsolve_strategy
303 = createLinearSolveStrategy(P2_linsolve_strategy_builder);
306 *out <<
"\nC) Create the physics-based preconditioner! ...\n";
309 *out <<
"\nCreating inv(M11) ...\n";
310 LinearOpPtr invM11 = inverse(*M11_linsolve_strategy, M11);
311 *out <<
"\ninvM11 = " << describe(*invM11,verbLevel) <<
"\n";
313 *out <<
"\nCreating inv(M22) ...\n";
314 LinearOpPtr invM22 = inverse(*M22_linsolve_strategy, M22);
315 *out <<
"\ninvM22 = " << describe(*invM22,verbLevel) <<
"\n";
317 *out <<
"\nCreating prec(P1) ...\n";
320 *out <<
"\nCreating prec(P1) as a full solver ...\n";
321 invP1 = inverse(*P1_linsolve_strategy, P1);
324 *out <<
"\nCreating prec(P1) as just an algebraic preconditioner ...\n";
325 RCP<Thyra::PreconditionerBase<double> >
326 precP1 = prec(*P1_prec_strategy,P1);
327 *out <<
"\nprecP1 = " << describe(*precP1,verbLevel) <<
"\n";
328 invP1 = precP1->getUnspecifiedPrecOp();
330 rcp_const_cast<Thyra::LinearOpBase<double> >(
331 invP1)->setObjectLabel(
"invP1");
332 *out <<
"\ninvP1 = " << describe(*invP1,verbLevel) <<
"\n";
334 LinearOpPtr P2ToP1 = multiply( invM11, M21 );
335 *out <<
"\nP2ToP1 = " << describe(*P2ToP1,verbLevel) <<
"\n";
337 LinearOpPtr P1ToP2 = multiply( invM22, M12 );
338 *out <<
"\nP1ToP2 = " << describe(*P1ToP2,verbLevel) <<
"\n";
340 LinearOpPtr precP2Op = multiply( P1ToP2, invP1, P2ToP1 );
341 *out <<
"\nprecP2Op = " << describe(*precP2Op,verbLevel) <<
"\n";
344 *out <<
"\nD) Setup the solver for P2 ...\n";
347 RCP<Thyra::LinearOpWithSolveBase<double> >
348 P2_lows = P2_linsolve_strategy->createOp();
350 *out <<
"\nCreating the solver P2 using the specialized precP2Op\n";
351 initializePreconditionedOp<double>( *P2_linsolve_strategy, P2,
352 unspecifiedPrec(precP2Op), P2_lows.ptr());
355 *out <<
"\nCreating the solver P2 using algebraic preconditioner\n";
356 initializeOp(*P2_linsolve_strategy, P2, P2_lows.ptr());
358 *out <<
"\nP2_lows = " << describe(*P2_lows, verbLevel) <<
"\n";
361 *out <<
"\nE) Solve P2 for a random RHS ...\n";
364 VectorPtr x = createMember(P2->domain());
365 VectorPtr b = createMember(P2->range());
366 Thyra::randomize(-1.0, +1.0, b.ptr());
367 Thyra::assign(x.ptr(), 0.0);
369 Thyra::SolveStatus<double>
370 solveStatus = solve<double>( *P2_lows, Thyra::NOTRANS, *b, x.ptr() );
372 *out <<
"\nSolve status:\n" << solveStatus;
374 *out <<
"\nSolution ||x|| = " << Thyra::norm(*x) <<
"\n";
377 *out <<
"\nParameter list after use:\n\n";
378 paramList->print(*out, PLPrintOptions().indent(2).showTypes(
true));
382 *out <<
"\nF) Checking the error in the solution of r=b-P2*x ...\n";
385 VectorPtr P2x = Thyra::createMember(b->space());
386 Thyra::apply( *P2, Thyra::NOTRANS, *x, P2x.ptr() );
387 VectorPtr r = Thyra::createMember(b->space());
388 Thyra::V_VmV<double>(r.ptr(), *b, *P2x);
391 P2x_nrm = Thyra::norm(*P2x),
392 r_nrm = Thyra::norm(*r),
393 b_nrm = Thyra::norm(*b),
394 r_nrm_over_b_nrm = r_nrm / b_nrm;
396 bool result = r_nrm_over_b_nrm <= solveTol;
397 if(!result) success =
false;
400 <<
"\n||P2*x|| = " << P2x_nrm <<
"\n";
403 <<
"\n||P2*x-b||/||b|| = " << r_nrm <<
"/" << b_nrm
404 <<
" = " << r_nrm_over_b_nrm <<
" <= " << solveTol
405 <<
" : " << Thyra::passfail(result) <<
"\n";
412 if(success) *out <<
"\nCongratulations! All of the tests checked out!\n";
413 else *out <<
"\nOh no! At least one of the tests failed!\n";
416 return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
int main(int argc, char *argv[])
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setParameterList(RCP< ParameterList > const ¶mList)
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 Thyra::LinearOpWithSolveFactoryBase ...