Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
simple_tpetra_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 
10 #include "Tpetra_Core.hpp"
11 #include "Tpetra_CrsMatrix.hpp"
12 #include "Tpetra_Vector.hpp"
15 #include "Thyra_LinearOpTester.hpp"
16 #include "Thyra_LinearOpWithSolveTester.hpp"
17 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
18 #include "Thyra_TpetraLinearOp.hpp"
19 #include "Thyra_TpetraVector.hpp"
20 #include "MatrixMarket_Tpetra.hpp"
24 
25 
26 namespace {
27 
28 // Helper function to compute a single norm for a vector
29 template<class Scalar, class LO, class GO, class Node>
30 double tpetraNorm2( const Tpetra::Vector<Scalar,LO,GO,Node> &v )
31 {
33  norm[0] = -1.0;
34  v.norm2(norm());
35  return norm[0];
36 }
37 
38 } // namespace
39 
40 
41 bool readAndSolveLinearSystem(int argc, char* argv[])
42 {
43 
44  using Teuchos::rcp;
45  using Teuchos::RCP;
46  using Teuchos::rcp_dynamic_cast;
50 
51  using Scalar = double;
52  using LocalOrdinal = Tpetra::Map<>::local_ordinal_type;
53  using GlobalOrdinal = Tpetra::Map<>::global_ordinal_type;
54  using NodeType = Tpetra::Map<>::node_type;
55  using CrsMatrix_t = Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, NodeType>;
56  using Vector_t = Tpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, NodeType>;
58 
59  bool success = true;
60 
61  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
62 
64  out = Teuchos::VerboseObjectBase::getDefaultOStream();
65 
66  //
67  // A) Program setup code
68  //
69 
70  //
71  // Read options from command-line
72  //
73 
74  std::string matrixFile = "";
75  std::string extraParamsFile = "";
76  double tol = 1e-5;
77  bool onlyPrintOptions = false;
78  bool printXmlFormat = false;
79  bool showDoc = true;
81 
82  auto validVerbLevels = Teuchos::getValidVerbLevels();
83  auto validVerbLevelsNamesRawStrings = Teuchos::getValidVerbLevelsNamesRawStrings();
84 
85  Stratimikos::DefaultLinearSolverBuilder linearSolverBuilder;
86 
87  CommandLineProcessor clp(false); // Don't throw exceptions
88 
89  // Set up command-line options for the linear solver that will be used!
90  linearSolverBuilder.setupCLP(&clp);
91 
92  clp.setOption( "matrix-file", &matrixFile,
93  "Defines the matrix and perhaps the RHS and LHS for a linear system to be solved." );
94  clp.setOption( "tol", &tol,
95  "Tolerance to check against the scaled residual norm." );
96  clp.setOption( "extra-params-file", &extraParamsFile,
97  "File containing extra parameters in XML format.");
98  clp.setOption( "only-print-options", "continue-after-printing-options",
99  &onlyPrintOptions,
100  "Only print options and stop or continue on" );
101  clp.setOption( "print-xml-format", "print-readable-format", &printXmlFormat,
102  "Print the valid options in XML format or in readable format." );
103  clp.setOption( "show-doc", "hide-doc", &showDoc,
104  "Print the valid options with or without documentation." );
105  clp.setOption("verb-level", &verbLevel, validVerbLevels.size(),
106  validVerbLevels.getRawPtr(), validVerbLevelsNamesRawStrings.getRawPtr(),
107  "The verbosity level." );
108 
109  clp.setDocString(
110  "Simple example for using TrilinosLinearSolver interface.\n"
111  "\n"
112  "To print out just the valid options use --only-print-options with"
113  " --print-xml-format or --print-readable-format.\n"
114  "\n"
115  "To solve a linear system read from a file use --matrix-file=\"<matrix>.mtx\""
116  " with options read from an XML file using"
117  " --linear-solver-params-file=\"<paramList>.xml\"\n"
118  );
119 
120  CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
121  if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
122 
123  //
124  // Print out the valid options and stop if asked
125  //
126 
127  if(onlyPrintOptions) {
128  if(printXmlFormat)
129  Teuchos::writeParameterListToXmlOStream(
130  *linearSolverBuilder.getValidParameters(), *out );
131  else
132  linearSolverBuilder.getValidParameters()->print(
133  *out,PLPrintOptions().indent(2).showTypes(true).showDoc(showDoc) );
134  return 0;
135  }
136 
137  //
138  // B) Set Tpetra-specific code that sets up the linear system to be solved
139  //
140  // While the below code reads in the Tpetra objects from a file, you can
141  // setup the Tpetra objects any way you would like.
142  //
143 
144  *out << "\nReading in Tpetra matrix A from the file"
145  << " \'"<<matrixFile<<"\' ...\n";
146 
147  RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
148  RCP<const CrsMatrix_t> tpetra_A =
149  Tpetra::MatrixMarket::Reader<CrsMatrix_t>::readSparseFile(matrixFile, comm);
150 
151  *out << "\nGenerate a random RHS random vector ...\n";
152  auto tpetra_b = rcp(new Vector_t(tpetra_A->getRangeMap()));
153  tpetra_b->randomize();
154 
155  *out << "\nGenerate LHS of zeros ...\n";
156  auto tpetra_x = rcp(new Vector_t(tpetra_A->getDomainMap()));
157  tpetra_x->putScalar(0.0); // Initial guess is critical!
158 
159  *out << "\nPrinting statistics of the Tpetra linear system ...\n";
160 
161  *out
162  << "\n Tpetra::CrsMatrix tpetra_A of dimension "
163  << tpetra_A->getRangeMap()->getGlobalNumElements()
164  << " x " << tpetra_A->getDomainMap()->getGlobalNumElements() << "\n"
165  << " ||tpetra_A||_F = " << tpetra_A->getFrobeniusNorm() << "\n"
166  << " ||tpetra_b||2 = " << tpetraNorm2(*tpetra_b) << "\n"
167  << " ||tpetra_x||2 = " << tpetraNorm2(*tpetra_x) << "\n";
168 
169  //
170  // C) The "Glue" code that takes Tpetra objects and wraps them as Thyra
171  // objects
172  //
173  // This next set of code wraps the Tpetra objects that define the linear
174  // system to be solved as Thyra objects so that they can be passed to the
175  // linear solver.
176  //
177 
178  using TpetraVectorSpace_t =
180 
181  RCP<const Thyra::LinearOpBase<double>> A =
182  Thyra::createConstLinearOp<Scalar,LocalOrdinal,GlobalOrdinal,NodeType>(tpetra_A);
183  RCP<Thyra::VectorBase<Scalar>> x =
184  Thyra::tpetraVector(rcp_dynamic_cast<const TpetraVectorSpace_t>(A->domain()),
185  tpetra_x);
186  RCP<const Thyra::VectorBase<Scalar>> b =
187  Thyra::tpetraVector(rcp_dynamic_cast<const TpetraVectorSpace_t>(A->range()),
188  tpetra_b);
189 
190  //
191  // D) Thyra-specific code for solving the linear system
192  //
193 
194  // Read in the solver parameters from the parameters file and/or from the
195  // command line. This was setup by the command-line options set by the
196  // setupCLP(...) function above.
197  linearSolverBuilder.readParameters(out.get());
198 
199  // Augment parameters if appropriate
200  if(extraParamsFile.length()) {
201  Teuchos::updateParametersFromXmlFile( "./"+extraParamsFile,
202  linearSolverBuilder.getNonconstParameterList().ptr() );
203  }
204 
205  // Create a linear solver factory given information read from the
206  // parameter list.
207  RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > lowsFactory =
208  linearSolverBuilder.createLinearSolveStrategy("");
209  *out << "\nlowsFactory: " << describe(*lowsFactory, verbLevel);
210 
211  // Setup output stream and the verbosity level
212  lowsFactory->setOStream(out);
213  lowsFactory->setVerbLevel(verbLevel);
214 
215  // Create a linear solver based on the forward operator A
216  RCP<Thyra::LinearOpWithSolveBase<Scalar> > A_lows =
217  Thyra::linearOpWithSolve(*lowsFactory, A);
218  *out << "\nA: " << describe(*A, verbLevel);
219  *out << "\nA_lows: " << describe(*A_lows, verbLevel);
220 
221  // Solve the linear system (note: the initial guess in 'x' is critical)
222  Thyra::SolveStatus<Scalar> status =
223  Thyra::solve<Scalar>(*A_lows, Thyra::NOTRANS, *b, x.ptr());
224  *out << "\nSolve status:\n" << status;
225 
226  // Write the linear solver parameters after they were read
227  linearSolverBuilder.writeParamsFile(*lowsFactory);
228 
229  //
230  // E) Post process the solution and check the error
231  //
232  // Note that the below code is based only on the Tpetra objects themselves
233  // and does not in any way depend or interact with any Thyra-based objects.
234  // The point is that most users of Thyra can largely gloss over the fact
235  // that Thyra is really being used for anything.
236  //
237 
238  // Wipe out the Thyra wrapper for x to guarantee that the solution will be
239  // written back to tpetra_x! At the time of this writting this is not
240  // really needed but the behavior may change at some point so this is a
241  // good idea.
242  x = Teuchos::null;
243 
244  *out << "\nSolution ||tpetra_x||2 = " << tpetraNorm2(*tpetra_x) << "\n";
245 
246  *out << "\nTesting the solution error ||b-A*x||/||b||:\n";
247 
248  // r = b - A*x
249  auto tpetra_r = rcp(new Vector_t(tpetra_b->getMap()));
250  tpetra_r->assign(*tpetra_b);
251  tpetra_A->apply(*tpetra_x, *tpetra_r, Teuchos::NO_TRANS, -ST::one(), ST::one());
252 
253  const double
254  nrm_r = tpetraNorm2(*tpetra_r),
255  nrm_b = tpetraNorm2(*tpetra_b),
256  rel_err = ( nrm_r / nrm_b );
257  const bool
258  passed = (rel_err <= tol);
259 
260  *out
261  << "||b-A*x||/||b|| = " << nrm_r << "/" << nrm_b << " = " << rel_err
262  << " < tol = " << tol << " ? " << ( passed ? "passed" : "failed" ) << "\n";
263 
264  if(!passed) success = false;
265 
266  return success;
267 
268 }
269 
270 
271 int main(int argc, char* argv[])
272 {
273 
275  out = Teuchos::VerboseObjectBase::getDefaultOStream();
276 
277  bool success = false;
278 
279  try {
280  success = readAndSolveLinearSystem(argc, argv);
281  }
282  TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success)
283 
284  if(success) *out << "\nCongratulations! All of the tests checked out!\n";
285  else *out << "\nOh no! At least one of the tests failed!\n";
286 
287  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
288 
289 }
int main(int argc, char *argv[])
TEUCHOSCORE_LIB_DLL_EXPORT ArrayView< const EVerbosityLevel > getValidVerbLevels()
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)
bool readAndSolveLinearSystem(int argc, char *argv[])
#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...
TEUCHOSCORE_LIB_DLL_EXPORT ArrayView< const char *const > getValidVerbLevelsNamesRawStrings()
RCP< const ParameterList > getValidParameters() const