Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MixedOrderPhysicsBasedPreconditioner.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stratimikos: Thyra-based strategies for linear solvers
4 //
5 // Copyright 2006 NTESS and the Stratimikos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
11 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
12 #include "Thyra_PreconditionerFactoryHelpers.hpp"
13 #include "Thyra_DefaultInverseLinearOp.hpp"
14 #include "Thyra_DefaultMultipliedLinearOp.hpp"
16 #include "Thyra_EpetraLinearOp.hpp"
18 #include "Thyra_TestingTools.hpp"
19 #include "EpetraExt_CrsMatrixIn.h"
20 #include "Epetra_CrsMatrix.h"
26 #include "Teuchos_TimeMonitor.hpp"
27 #ifdef HAVE_MPI
28 # include "Epetra_MpiComm.h"
29 #else
30 # include "Epetra_SerialComm.h"
31 #endif
32 
33 
43 namespace {
44 
45 
46 // Read a Epetra_CrsMatrix from a Matrix market file
48 readEpetraCrsMatrixFromMatrixMarket(
49  const std::string fileName, const Epetra_Comm &comm
50  )
51 {
52  Epetra_CrsMatrix *A = 0;
54  0!=EpetraExt::MatrixMarketFileToCrsMatrix( fileName.c_str(), comm, A ),
55  std::runtime_error,
56  "Error, could not read matrix file \""<<fileName<<"\"!"
57  );
58  return Teuchos::rcp(A);
59 }
60 
61 
62 // Read an Epetra_CrsMatrix in as a wrapped Thyra::EpetraLinearOp object
64 readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
65  const std::string fileName, const Epetra_Comm &comm,
66  const std::string &label
67  )
68 {
69  return Thyra::epetraLinearOp(
70  readEpetraCrsMatrixFromMatrixMarket(fileName,comm),label
71  );
72 }
73 
74 
75 } // namespace
76 
77 
78 int main(int argc, char* argv[])
79 {
80 
81  using Teuchos::describe;
82  using Teuchos::rcp;
83  using Teuchos::rcp_dynamic_cast;
84  using Teuchos::rcp_const_cast;
85  using Teuchos::RCP;
88  using Teuchos::sublist;
89  typedef ParameterList::PrintOptions PLPrintOptions;
90  using Thyra::inverse;
91  using Thyra::initializePreconditionedOp;
92  using Thyra::initializeOp;
93  using Thyra::unspecifiedPrec;
94  using Thyra::solve;
95  typedef RCP<const Thyra::LinearOpBase<double> > LinearOpPtr;
96  typedef RCP<Thyra::VectorBase<double> > VectorPtr;
97 
98  bool success = true;
99  bool verbose = true;
100 
101  Teuchos::GlobalMPISession mpiSession(&argc,&argv);
102 
104  out = Teuchos::VerboseObjectBase::getDefaultOStream();
105 
106  try {
107 
108  //
109  // Read in options from the command line
110  //
111 
112  const int numVerbLevels = 6;
114  verbLevelValues[] =
115  {
119  };
120  const char*
121  verbLevelNames[] =
122  { "default", "none", "low", "medium", "high", "extreme" };
123 
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;
132 
133  CommandLineProcessor clp(false); // Don't throw exceptions
134 
135  clp.setOption( "verb-level", &verbLevel,
136  numVerbLevels, verbLevelValues, verbLevelNames,
137  "Verbosity level used for all objects."
138  );
139  clp.setOption( "params-file", &paramsFile,
140  "File containing parameters in XML format.",
141  true // Required
142  );
143  clp.setOption( "extra-params-file", &extraParamsFile,
144  "File containing extra parameters in XML format."
145  );
146  clp.setOption( "base-dir", &baseDir,
147  "Base directory for all of the files."
148  );
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"
151  );
152  clp.setOption( "invert-P1", "prec-P1-only", &invertP1,
153  "In the physics-based preconditioner, use P1's preconditioner or fully invert P1."
154  );
155  clp.setOption( "solve-tol", &solveTol,
156  "Tolerance for the solution to determine success or failure!"
157  );
158  clp.setOption( "show-params", "no-show-params", &showParams,
159  "Show the parameter list or not."
160  );
161  clp.setDocString(
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"
169  "\n"
170  "The matrices used in this example are:\n"
171  "\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"
180  "\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"
183  "\n"
184  "The preconditioner operator created in this example program is:\n"
185  "\n"
186  " precP2Op = (inv(M22) * M12) * prec(P1) * (inv(M11) * M21)\n"
187  "\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"
190  "\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"
194  "\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"
199  );
200 
201  // Note: Use --help on the command line to see the above documentation
202 
203  CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
204  if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
205 
206 
207  //
208  *out << "\nA) Reading in Epetra_CrsMatrix objects for P1, P2, M11, M12, M21, and M22 ...\n";
209  //
210 
211 #ifdef HAVE_MPI
212  Epetra_MpiComm comm(MPI_COMM_WORLD);
213 #else
214  Epetra_SerialComm comm;
215 #endif
216 
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";
235 
236  // ToDo: Replace the above functions with a general Thyra strategy object
237  // to do the reading
238 
239  //
240  *out << "\nB) Get the preconditioner and/or linear solver strategies to invert M11, M22, P1, and P2 ...\n";
241  //
242 
243  //
244  // Get separate parameter sublists for each square operator separately
245  // that specify the type of linear solver and/or preconditioner to use.
246  //
247 
248  RCP<ParameterList> paramList =
249  Teuchos::getParametersFromXmlFile( baseDir+"/"+paramsFile );
250  if (extraParamsFile.length()) {
251  Teuchos::updateParametersFromXmlFile( baseDir+"/"+extraParamsFile, paramList.ptr() );
252  }
253  if (showParams) {
254  *out << "\nRead in parameter list:\n\n";
255  paramList->print(*out,PLPrintOptions().indent(2).showTypes(true));
256  }
257 
258  Stratimikos::DefaultLinearSolverBuilder M11_linsolve_strategy_builder;
259  M11_linsolve_strategy_builder.setParameterList(
260  sublist(paramList,"M11 Solver",true) );
261 
262  Stratimikos::DefaultLinearSolverBuilder M22_linsolve_strategy_builder;
263  M22_linsolve_strategy_builder.setParameterList(
264  sublist(paramList,"M22 Solver",true) );
265 
266  Stratimikos::DefaultLinearSolverBuilder P1_linsolve_strategy_builder;
267  P1_linsolve_strategy_builder.setParameterList(
268  sublist(paramList,"P1 Solver",true) );
269 
270  Stratimikos::DefaultLinearSolverBuilder P2_linsolve_strategy_builder;
271  P2_linsolve_strategy_builder.setParameterList(
272  sublist(paramList,"P2 Solver",true) );
273 
274  //
275  // Create the linear solver and/or preconditioner strategies
276  // (i.e. factories)
277  //
278 
279  // For M11 and M22, we want full linear solver factories with embedded
280  // algebraic preconditioner factories.
281 
282  RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > M11_linsolve_strategy
283  = createLinearSolveStrategy(M11_linsolve_strategy_builder);
284 
285  RCP<Thyra::LinearOpWithSolveFactoryBase<double> > M22_linsolve_strategy
286  = createLinearSolveStrategy(M22_linsolve_strategy_builder);
287 
288  // For P1, we only want its preconditioner factory.
289 
290  RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P1_linsolve_strategy;
291  RCP<const Thyra::PreconditionerFactoryBase<double> > P1_prec_strategy;
292  if(invertP1)
293  P1_linsolve_strategy
294  = createLinearSolveStrategy(P1_linsolve_strategy_builder);
295  else
296  P1_prec_strategy
297  = createPreconditioningStrategy(P1_linsolve_strategy_builder);
298 
299  // For P2, we only want a linear solver factory. We will supply the
300  // preconditioner ourselves (that is the whole point of this example).
301 
302  RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P2_linsolve_strategy
303  = createLinearSolveStrategy(P2_linsolve_strategy_builder);
304 
305  //
306  *out << "\nC) Create the physics-based preconditioner! ...\n";
307  //
308 
309  *out << "\nCreating inv(M11) ...\n";
310  LinearOpPtr invM11 = inverse(*M11_linsolve_strategy, M11);
311  *out << "\ninvM11 = " << describe(*invM11,verbLevel) << "\n";
312 
313  *out << "\nCreating inv(M22) ...\n";
314  LinearOpPtr invM22 = inverse(*M22_linsolve_strategy, M22);
315  *out << "\ninvM22 = " << describe(*invM22,verbLevel) << "\n";
316 
317  *out << "\nCreating prec(P1) ...\n";
318  LinearOpPtr invP1;
319  if(invertP1) {
320  *out << "\nCreating prec(P1) as a full solver ...\n";
321  invP1 = inverse(*P1_linsolve_strategy, P1);
322  }
323  else {
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();
329  }
330  rcp_const_cast<Thyra::LinearOpBase<double> >(
331  invP1)->setObjectLabel("invP1"); // Cast to set label ...
332  *out << "\ninvP1 = " << describe(*invP1,verbLevel) << "\n";
333 
334  LinearOpPtr P2ToP1 = multiply( invM11, M21 );
335  *out << "\nP2ToP1 = " << describe(*P2ToP1,verbLevel) << "\n";
336 
337  LinearOpPtr P1ToP2 = multiply( invM22, M12 );
338  *out << "\nP1ToP2 = " << describe(*P1ToP2,verbLevel) << "\n";
339 
340  LinearOpPtr precP2Op = multiply( P1ToP2, invP1, P2ToP1 );
341  *out << "\nprecP2Op = " << describe(*precP2Op,verbLevel) << "\n";
342 
343  //
344  *out << "\nD) Setup the solver for P2 ...\n";
345  //
346 
347  RCP<Thyra::LinearOpWithSolveBase<double> >
348  P2_lows = P2_linsolve_strategy->createOp();
349  if(useP1Prec) {
350  *out << "\nCreating the solver P2 using the specialized precP2Op\n";
351  initializePreconditionedOp<double>( *P2_linsolve_strategy, P2,
352  unspecifiedPrec(precP2Op), P2_lows.ptr());
353  }
354  else {
355  *out << "\nCreating the solver P2 using algebraic preconditioner\n";
356  initializeOp(*P2_linsolve_strategy, P2, P2_lows.ptr());
357  }
358  *out << "\nP2_lows = " << describe(*P2_lows, verbLevel) << "\n";
359 
360  //
361  *out << "\nE) Solve P2 for a random RHS ...\n";
362  //
363 
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); // Must give an initial guess!
368 
369  Thyra::SolveStatus<double>
370  solveStatus = solve<double>( *P2_lows, Thyra::NOTRANS, *b, x.ptr() );
371 
372  *out << "\nSolve status:\n" << solveStatus;
373 
374  *out << "\nSolution ||x|| = " << Thyra::norm(*x) << "\n";
375 
376  if(showParams) {
377  *out << "\nParameter list after use:\n\n";
378  paramList->print(*out, PLPrintOptions().indent(2).showTypes(true));
379  }
380 
381  //
382  *out << "\nF) Checking the error in the solution of r=b-P2*x ...\n";
383  //
384 
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);
389 
390  double
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;
395 
396  bool result = r_nrm_over_b_nrm <= solveTol;
397  if(!result) success = false;
398 
399  *out
400  << "\n||P2*x|| = " << P2x_nrm << "\n";
401 
402  *out
403  << "\n||P2*x-b||/||b|| = " << r_nrm << "/" << b_nrm
404  << " = " << r_nrm_over_b_nrm << " <= " << solveTol
405  << " : " << Thyra::passfail(result) << "\n";
406 
408  }
409  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose,std::cerr,success)
410 
411  if (verbose) {
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";
414  }
415 
416  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
417 
418 }
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 &paramList)
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 ...