Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
simple_stratimikos_example.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 "EpetraExt_readEpetraLinearSystem.h"
17 #ifdef HAVE_MPI
18 # include "Epetra_MpiComm.h"
19 #else
20 # include "Epetra_SerialComm.h"
21 #endif
22 
23 
24 namespace {
25 
26 
27 // Helper function to compute a single norm for a vector
28 double epetraNorm2( const Epetra_Vector &v )
29 {
30  double norm[1] = { -1.0 };
31  v.Norm2(&norm[0]);
32  return norm[0];
33 }
34 
35 
36 } // namespace
37 
38 
39 int main(int argc, char* argv[])
40 {
41 
42  using Teuchos::rcp;
43  using Teuchos::RCP;
46 
47  bool success = true;
48  bool verbose = true;
49 
50  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
51 
53  out = Teuchos::VerboseObjectBase::getDefaultOStream();
54 
55  try {
56 
57 
58  //
59  // A) Program setup code
60  //
61 
62  //
63  // Read options from command-line
64  //
65 
66  std::string matrixFile = "";
67  std::string extraParamsFile = "";
68  double tol = 1e-5;
69  bool onlyPrintOptions = false;
70  bool printXmlFormat = false;
71  bool showDoc = true;
72 
73  Stratimikos::DefaultLinearSolverBuilder linearSolverBuilder;
74 
75  CommandLineProcessor clp(false); // Don't throw exceptions
76 
77  // Set up command-line options for the linear solver that will be used!
78  linearSolverBuilder.setupCLP(&clp);
79 
80  clp.setOption( "matrix-file", &matrixFile
81  ,"Defines the matrix and perhaps the RHS and LHS for a linear system to be solved." );
82  clp.setOption( "tol", &tol, "Tolerance to check against the scaled residual norm." );
83  clp.setOption( "extra-params-file", &extraParamsFile, "File containing extra parameters in XML format.");
84  clp.setOption( "only-print-options", "continue-after-printing-options", &onlyPrintOptions
85  ,"Only print options and stop or continue on" );
86  clp.setOption( "print-xml-format", "print-readable-format", &printXmlFormat
87  ,"Print the valid options in XML format or in readable format." );
88  clp.setOption( "show-doc", "hide-doc", &showDoc
89  ,"Print the valid options with or without documentation." );
90 
91  clp.setDocString(
92  "Simple example for the use of the Stratimikos facade Stratimikos::DefaultLinearSolverBuilder.\n"
93  "\n"
94  "To print out just the valid options use --matrix-file=\"\" --only-print-options with --print-xml-format"
95  " or --print-readable-format.\n"
96  "\n"
97  "To solve a linear system read from a file use --matrix-file=\"SomeFile.mtx\""
98  " with options read from an XML file using --linear-solver-params-file=\"SomeFile.xml\"\n"
99  );
100 
101  CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
102  if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
103 
104  //
105  // Print out the valid options and stop if asked
106  //
107 
108  if(onlyPrintOptions) {
109  if(printXmlFormat)
110  Teuchos::writeParameterListToXmlOStream(
111  *linearSolverBuilder.getValidParameters()
112  ,*out
113  );
114  else
115  linearSolverBuilder.getValidParameters()->print(
116  *out,PLPrintOptions().indent(2).showTypes(true).showDoc(showDoc)
117  );
118  return 0;
119  }
120 
121 
122  //
123  // B) Epetra-specific code that sets up the linear system to be solved
124  //
125  // While the below code reads in the Epetra objects from a file, you can
126  // setup the Epetra objects any way you would like. Note that this next
127  // set of code as nothing to do with Thyra at all, and it should not.
128  //
129 
130  *out << "\nReading linear system in Epetra format from the file \'"<<matrixFile<<"\' ...\n";
131 
132 #ifdef HAVE_MPI
133  Epetra_MpiComm comm(MPI_COMM_WORLD);
134 #else
135  Epetra_SerialComm comm;
136 #endif
137  RCP<Epetra_CrsMatrix> epetra_A;
138  RCP<Epetra_Vector> epetra_x, epetra_b;
139  EpetraExt::readEpetraLinearSystem( matrixFile, comm, &epetra_A, NULL, &epetra_x, &epetra_b );
140 
141  if(!epetra_b.get()) {
142  *out << "\nThe RHS b was not read in so generate a new random vector ...\n";
143  epetra_b = rcp(new Epetra_Vector(epetra_A->OperatorRangeMap()));
144  epetra_b->Random();
145  }
146 
147  if(!epetra_x.get()) {
148  *out << "\nThe LHS x was not read in so generate a new zero vector ...\n";
149  epetra_x = rcp(new Epetra_Vector(epetra_A->OperatorDomainMap()));
150  epetra_x->PutScalar(0.0); // Initial guess is critical!
151  }
152 
153  *out << "\nPrinting statistics of the Epetra linear system ...\n";
154 
155  *out
156  << "\n Epetra_CrsMatrix epetra_A of dimension "
157  << epetra_A->OperatorRangeMap().NumGlobalElements()
158  << " x " << epetra_A->OperatorDomainMap().NumGlobalElements()
159  << "\n ||epetraA||inf = " << epetra_A->NormInf()
160  << "\n ||epetra_b||2 = " << epetraNorm2(*epetra_b)
161  << "\n ||epetra_x||2 = " << epetraNorm2(*epetra_x)
162  << "\n";
163 
164 
165  //
166  // C) The "Glue" code that takes Epetra objects and wraps them as Thyra
167  // objects
168  //
169  // This next set of code wraps the Epetra objects that define the linear
170  // system to be solved as Thyra objects so that they can be passed to the
171  // linear solver.
172  //
173 
174  RCP<const Thyra::LinearOpBase<double> > A = Thyra::epetraLinearOp( epetra_A );
175  RCP<Thyra::VectorBase<double> > x = Thyra::create_Vector( epetra_x, A->domain() );
176  RCP<const Thyra::VectorBase<double> > b = Thyra::create_Vector( epetra_b, A->range() );
177 
178  // Note that above Thyra is only interacted with in the most trival of
179  // ways. For most users, Thyra will only be seen as a thin wrapper that
180  // they need know little about in order to wrap their objects in order to
181  // pass them to Thyra-enabled solvers.
182 
183 
184  //
185  // D) Thyra-specific code for solving the linear system
186  //
187  // Note that this code has no mention of any concrete implementation and
188  // therefore can be used in any use case.
189  //
190 
191  // Reading in the solver parameters from the parameters file and/or from
192  // the command line. This was setup by the command-line options
193  // set by the setupCLP(...) function above.
194  linearSolverBuilder.readParameters(out.get());
195 
196  // Augment parameters if appropriate
197  if(extraParamsFile.length()) {
198  Teuchos::updateParametersFromXmlFile( "./"+extraParamsFile,
199  linearSolverBuilder.getNonconstParameterList().ptr() );
200  }
201 
202  // Create a linear solver factory given information read from the
203  // parameter list.
204  RCP<Thyra::LinearOpWithSolveFactoryBase<double> > lowsFactory =
205  linearSolverBuilder.createLinearSolveStrategy("");
206 
207  // Setup output stream and the verbosity level
208  lowsFactory->setOStream(out);
209  lowsFactory->setVerbLevel(Teuchos::VERB_LOW);
210 
211  // Create a linear solver based on the forward operator A
212  RCP<Thyra::LinearOpWithSolveBase<double> > lows =
213  Thyra::linearOpWithSolve(*lowsFactory, A);
214 
215  // Solve the linear system (note: the initial guess in 'x' is critical)
216  Thyra::SolveStatus<double> status =
217  Thyra::solve<double>(*lows, Thyra::NOTRANS, *b, x.ptr());
218  *out << "\nSolve status:\n" << status;
219 
220  // Write the linear solver parameters after they were read
221  linearSolverBuilder.writeParamsFile(*lowsFactory);
222 
223 
224  //
225  // E) Post process the solution and check the error
226  //
227  // Note that the below code is based only on the Epetra objects themselves
228  // and does not in any way depend or interact with any Thyra-based
229  // objects. The point is that most users of Thyra can largely gloss over
230  // the fact that Thyra is really being used for anything.
231  //
232 
233  // Wipe out the Thyra wrapper for x to guarantee that the solution will be
234  // written back to epetra_x! At the time of this writting this is not
235  // really needed but the behavior may change at some point so this is a
236  // good idea.
237  x = Teuchos::null;
238 
239  *out
240  << "\nSolution ||epetra_x||2 = " << epetraNorm2(*epetra_x) << "\n";
241 
242  *out << "\nTesting the solution error ||b-A*x||/||b|| computed through the Epetra objects ...\n";
243 
244  // r = b - A*x
245  Epetra_Vector epetra_r(*epetra_b);
246  {
247  Epetra_Vector epetra_A_x(epetra_A->OperatorRangeMap());
248  epetra_A->Apply(*epetra_x,epetra_A_x);
249  epetra_r.Update(-1.0,epetra_A_x,1.0);
250  }
251 
252  const double
253  nrm_r = epetraNorm2(epetra_r),
254  nrm_b = epetraNorm2(*epetra_b),
255  rel_err = ( nrm_r / nrm_b );
256  const bool
257  passed = (rel_err <= tol);
258 
259  *out
260  << "||b-A*x||/||b|| = " << nrm_r << "/" << nrm_b << " = " << rel_err
261  << " < tol = " << tol << " ? " << ( passed ? "passed" : "failed" ) << "\n";
262 
263  if(!passed) success = false;
264 
265  }
266  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success)
267 
268  if (verbose) {
269  if(success) *out << "\nCongratulations! All of the tests checked out!\n";
270  else *out << "\nOh no! At least one of the tests failed!\n";
271  }
272 
273  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
274 
275 }
int main(int argc, char *argv[])
T * get() const
void readParameters(std::ostream *out)
Force the parameters to be read from a file and/or an extra XML string.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
RCP< VectorBase< double > > create_Vector(const RCP< Epetra_Vector > &epetra_v, const RCP< const VectorSpaceBase< double > > &space=Teuchos::null)
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
ParameterList::PrintOptions PLPrintOptions
RCP< Thyra::LinearOpWithSolveFactoryBase< Scalar > > createLinearSolveStrategy(const std::string &linearSolveStrategyName) const
Concrete subclass of Thyra::LinearSolverBuilderBase for creating Thyra::LinearOpWithSolveFactoryBase ...
void writeParamsFile(const Thyra::LinearOpWithSolveFactoryBase< Scalar > &lowsFactory, const std::string &outputXmlFileName="") const
Write the parameters list for a LinearOpWithSolveFactoryBase object to a file after the parameters ar...
void setupCLP(Teuchos::CommandLineProcessor *clp)
Setup the command-line processor to read in the needed data to extra the parameters from...
RCP< const ParameterList > getValidParameters() const