Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
galeri_xpetra_driver.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4 //
5 // Copyright 2009 NTESS and the Ifpack2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include <iostream>
11 
12 /*
13  Call Ifpack2 via the Stratimikos interface.
14 
15 Usage:
16 ./Ifpack2_Stratimikos.exe : use xml configuration file stratimikos_ParameterList.xml
17 
18 Note:
19 The source code is not MueLu specific and can be used with any Stratimikos strategy.
20 */
21 
22 // Teuchos includes
23 #include <Teuchos_ConfigDefs.hpp>
25 #include <Teuchos_StackedTimer.hpp>
26 #include <Teuchos_RCP.hpp>
31 
32 // Thyra includes
33 #include <Thyra_LinearOpWithSolveBase.hpp>
34 #include <Thyra_VectorBase.hpp>
35 #include <Thyra_SolveSupportTypes.hpp>
36 
37 // Stratimikos includes
38 #include <Stratimikos_LinearSolverBuilder.hpp>
39 #include <Stratimikos_InternalConfig.h>
40 
41 // Xpetra include
42 #include <Xpetra_Parameters.hpp>
43 #include <Xpetra_ThyraUtils.hpp>
44 
45 // Galeri includes
46 #include <Galeri_XpetraParameters.hpp>
47 #include <Galeri_XpetraProblemFactory.hpp>
48 #include <Galeri_XpetraUtils.hpp>
49 #include <Galeri_XpetraMaps.hpp>
50 
51 
52 template <class Scalar>
53 int
54 main_(int argc, char *argv[], Teuchos::CommandLineProcessor& clp) {
55  typedef Tpetra::Map<> map_type;
56  typedef map_type::local_ordinal_type LocalOrdinal;
57  typedef map_type::global_ordinal_type GlobalOrdinal;
58  typedef map_type::node_type Node;
59  using Teuchos::RCP;
60  using Teuchos::rcp;
63  #include <Xpetra_UseShortNames.hpp>
64 
65  bool success = false;
66  bool verbose = true;
67  try {
68 
69  //
70  // MPI initialization
71  //
72  // Teuchos::CommandLineProcessor clp(false);
73  const auto comm = Teuchos::DefaultComm<int>::getComm ();
74 
75  //
76  // Parameters
77  //
78  // manage parameters of the test case
79  Galeri::Xpetra::Parameters<GlobalOrdinal> galeriParameters(clp, 100, 100, 100, "Laplace2D");
80  // manage parameters of Xpetra
81  Xpetra::Parameters xpetraParameters(clp);
82 
83  // command line parameters
84  std::string xmlFileName = "stratimikos_ParameterList.xml"; clp.setOption("xml", &xmlFileName, "read parameters from an xml file");
85  std::string yamlFileName = ""; clp.setOption("yaml", &yamlFileName, "read parameters from a yaml file");
86  bool printTimings = false; clp.setOption("timings", "notimings", &printTimings, "print timings to screen");
87  bool use_stacked_timer = false; clp.setOption("stacked-timer", "no-stacked-timer", &use_stacked_timer, "Run with or without stacked timer output");
88  std::string timingsFormat = "table-fixed"; clp.setOption("time-format", &timingsFormat, "timings format (table-fixed | table-scientific | yaml)");
89  int numVectors = 1; clp.setOption("multivector", &numVectors, "number of rhs to solve simultaneously");
90  int numSolves = 1; clp.setOption("numSolves", &numSolves, "number of times the system should be solved");
91 
92  switch (clp.parse(argc,argv)) {
93  case Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED: return EXIT_SUCCESS;
97  }
98 
99  RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
100  Teuchos::FancyOStream& out = *fancy;
101  out.setOutputToRootOnly(0);
102 
103  // Set up timers
105  if (use_stacked_timer)
106  stacked_timer = rcp(new Teuchos::StackedTimer("Main"));
107  TimeMonitor::setStackedTimer(stacked_timer);
108 
109  // Read in parameter list
110  TEUCHOS_TEST_FOR_EXCEPTION(xmlFileName == "" && yamlFileName == "", std::runtime_error,
111  "Need to provide xml or yaml input file");
112  RCP<ParameterList> paramList = rcp(new ParameterList("params"));
113  if (yamlFileName != "")
114  Teuchos::updateParametersFromYamlFileAndBroadcast(yamlFileName, paramList.ptr(), *comm);
115  else
116  Teuchos::updateParametersFromXmlFileAndBroadcast(xmlFileName, paramList.ptr(), *comm);
117 
118  //
119  // Construct the problem
120  //
121 
122  RCP<Matrix> A;
123  RCP<const Map> map;
124  RCP<MultiVector> X, B;
125 
126  std::ostringstream galeriStream;
127  Teuchos::ParameterList galeriList = galeriParameters.GetParameterList();
128  galeriStream << "========================================================\n" << xpetraParameters;
129  galeriStream << galeriParameters;
130 
131  // Galeri will attempt to create a square-as-possible distribution of subdomains di, e.g.,
132  // d1 d2 d3
133  // d4 d5 d6
134  // d7 d8 d9
135  // d10 d11 d12
136  // A perfect distribution is only possible when the #processors is a perfect square.
137  // This *will* result in "strip" distribution if the #processors is a prime number or if the factors are very different in
138  // size. For example, np=14 will give a 7-by-2 distribution.
139  // If you don't want Galeri to do this, specify mx or my on the galeriList.
140  std::string matrixType = galeriParameters.GetMatrixType();
141 
142  // Create map
143  if (matrixType == "Laplace1D") {
144  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian1D", comm, galeriList);
145 
146  } else if (matrixType == "Laplace2D" || matrixType == "Star2D" ||
147  matrixType == "BigStar2D" || matrixType == "AnisotropicDiffusion" || matrixType == "Elasticity2D") {
148  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian2D", comm, galeriList);
149 
150  } else if (matrixType == "Laplace3D" || matrixType == "Brick3D" || matrixType == "Elasticity3D") {
151  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian3D", comm, galeriList);
152  }
153 
154  // Expand map to do multiple DOF per node for block problems
155  if (matrixType == "Elasticity2D")
156  map = Xpetra::MapFactory<LO,GO,Node>::Build(map, 2);
157  if (matrixType == "Elasticity3D")
158  map = Xpetra::MapFactory<LO,GO,Node>::Build(map, 3);
159 
160  galeriStream << "Processor subdomains in x direction: " << galeriList.get<GO>("mx") << std::endl
161  << "Processor subdomains in y direction: " << galeriList.get<GO>("my") << std::endl
162  << "Processor subdomains in z direction: " << galeriList.get<GO>("mz") << std::endl
163  << "========================================================" << std::endl;
164 
165  if (matrixType == "Elasticity2D" || matrixType == "Elasticity3D") {
166  // Our default test case for elasticity: all boundaries of a square/cube have Neumann b.c. except left which has Dirichlet
167  galeriList.set("right boundary" , "Neumann");
168  galeriList.set("bottom boundary", "Neumann");
169  galeriList.set("top boundary" , "Neumann");
170  galeriList.set("front boundary" , "Neumann");
171  galeriList.set("back boundary" , "Neumann");
172  }
173 
174  RCP<Galeri::Xpetra::Problem<Map,CrsMatrixWrap,MultiVector> > Pr =
175  Galeri::Xpetra::BuildProblem<SC,LO,GO,Map,CrsMatrixWrap,MultiVector>(galeriParameters.GetMatrixType(), map, galeriList);
176  A = Pr->BuildMatrix();
177 
178  if (matrixType == "Elasticity2D" ||
179  matrixType == "Elasticity3D") {
180  A->SetFixedBlockSize((galeriParameters.GetMatrixType() == "Elasticity2D") ? 2 : 3);
181  }
182 
183  out << galeriStream.str();
184  X = MultiVectorFactory::Build(map, numVectors);
185  B = MultiVectorFactory::Build(map, numVectors);
186  B->putScalar(1);
187  X->putScalar(0);
188 
189  //
190  // Build Thyra linear algebra objects
191  //
192 
193  RCP<const Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> > xpCrsA = Teuchos::rcp_dynamic_cast<const Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(A);
194 
195  RCP<const Thyra::LinearOpBase<Scalar> > thyraA = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyra(xpCrsA->getCrsMatrix());
196  RCP< Thyra::MultiVectorBase<Scalar> > thyraX = Teuchos::rcp_const_cast<Thyra::MultiVectorBase<Scalar> >(Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyraMultiVector(X));
197  RCP<const Thyra::MultiVectorBase<Scalar> > thyraB = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyraMultiVector(B);
198 
199  //
200  // Build Stratimikos solver
201  //
202 
203  // This is the Stratimikos main class (= factory of solver factory).
204  Stratimikos::LinearSolverBuilder<Scalar> linearSolverBuilder;
205 
206  // Setup solver parameters using a Stratimikos parameter list.
207  linearSolverBuilder.setParameterList(paramList);
208 
209  // Build a new "solver factory" according to the previously specified parameter list.
210  RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > solverFactory = Thyra::createLinearSolveStrategy(linearSolverBuilder);
211  auto precFactory = solverFactory->getPreconditionerFactory();
212  RCP<Thyra::PreconditionerBase<Scalar> > prec;
214  if (!precFactory.is_null()) {
215  prec = precFactory->createPrec();
216 
217  // Build a Thyra operator corresponding to A^{-1} computed using the Stratimikos solver.
218  Thyra::initializePrec<Scalar>(*precFactory, thyraA, prec.ptr());
219  thyraInverseA = solverFactory->createOp();
220  Thyra::initializePreconditionedOp<Scalar>(*solverFactory, thyraA, prec, thyraInverseA.ptr());
221  } else {
222  thyraInverseA = Thyra::linearOpWithSolve(*solverFactory, thyraA);
223  }
224 
225  // Solve Ax = b.
226  Thyra::SolveStatus<Scalar> status = Thyra::solve<Scalar>(*thyraInverseA, Thyra::NOTRANS, *thyraB, thyraX.ptr());
227 
228  success = (status.solveStatus == Thyra::SOLVE_STATUS_CONVERGED);
229 
230  for (int solveno = 1; solveno < numSolves; solveno++) {
231  if (!precFactory.is_null())
232  Thyra::initializePrec<Scalar>(*precFactory, thyraA, prec.ptr());
233  thyraX->assign(0.);
234 
235  status = Thyra::solve<Scalar>(*thyraInverseA, Thyra::NOTRANS, *thyraB, thyraX.ptr());
236 
237  success = success && (status.solveStatus == Thyra::SOLVE_STATUS_CONVERGED);
238  }
239 
240  // print timings
241  if (printTimings) {
242  if (use_stacked_timer) {
243  stacked_timer->stop("Main");
245  options.output_fraction = options.output_histogram = options.output_minmax = true;
246  stacked_timer->report(out, comm, options);
247  } else {
248  RCP<ParameterList> reportParams = rcp(new ParameterList);
249  if (timingsFormat == "yaml") {
250  reportParams->set("Report format", "YAML"); // "Table" or "YAML"
251  reportParams->set("YAML style", "compact"); // "spacious" or "compact"
252  }
253  reportParams->set("How to merge timer sets", "Union");
254  reportParams->set("alwaysWriteLocal", false);
255  reportParams->set("writeGlobalStats", true);
256  reportParams->set("writeZeroTimers", false);
257 
258  const std::string filter = "";
259 
260  std::ios_base::fmtflags ff(out.flags());
261  if (timingsFormat == "table-fixed") out << std::fixed;
262  else out << std::scientific;
263  TimeMonitor::report(comm.ptr(), out, filter, reportParams);
264  out << std::setiosflags(ff);
265  }
266  }
267 
268  TimeMonitor::clearCounters();
269  out << std::endl;
270 
271  }
272  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success);
273 
274  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
275 }
276 
277 
283 };
284 
285 int
286 main(int argc, char *argv[]) {
287  Teuchos::GlobalMPISession session (&argc, &argv, NULL);
288 
290  scalarType scalar = DOUBLE;
291  std::vector<const char*> availableScalarTypeStrings;
292  std::vector<scalarType> availableScalarTypes;
293 #ifdef HAVE_TPETRA_INST_DOUBLE
294  availableScalarTypeStrings.push_back("double");
295  availableScalarTypes.push_back(DOUBLE);
296 #endif
297 #ifdef HAVE_TPETRA_INST_FLOAT
298  availableScalarTypeStrings.push_back("float");
299  availableScalarTypes.push_back(FLOAT);
300 #endif
301 #ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
302  availableScalarTypeStrings.push_back("complex<double>");
303  availableScalarTypes.push_back(COMPLEX_DOUBLE);
304 #endif
305 #ifdef HAVE_TPETRA_INST_COMPLEX_FLOAT
306  availableScalarTypeStrings.push_back("complex<float>");
307  availableScalarTypes.push_back(COMPLEX_FLOAT);
308 #endif
309  clp.setOption("scalarType", &scalar, availableScalarTypes.size(), availableScalarTypes.data(), availableScalarTypeStrings.data(), "scalar type");
310  clp.recogniseAllOptions(false);
311  switch (clp.parse(argc, argv, NULL)) {
312  case Teuchos::CommandLineProcessor::PARSE_ERROR: return EXIT_FAILURE;
316  }
317 
318 #ifdef HAVE_TPETRA_INST_DOUBLE
319  if (scalar == DOUBLE)
320  return main_<double>(argc, argv, clp);
321 #endif
322 #ifdef HAVE_TPETRA_INST_FLOAT
323  if (scalar == FLOAT)
324  return main_<float>(argc, argv, clp);
325 #endif
326 #ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
327  if (scalar == COMPLEX_DOUBLE)
328  return main_<std::complex<double> >(argc, argv, clp);
329 #endif
330 #ifdef HAVE_TPETRA_INST_COMPLEX_FLOAT
331  if (scalar == COMPLEX_FLOAT)
332  return main_<std::complex<float> >(argc, argv, clp);
333 #endif
334 }
int main(int argc, char *argv[])
void stop(const std::string &name, const bool pop_kokkos_profiling_region=true)
Tpetra::Map< int, int > map_type
void recogniseAllOptions(const bool &recogniseAllOptions)
T & get(ParameterList &l, const std::string &name)
int main_(int argc, char *argv[], Teuchos::CommandLineProcessor &clp)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
static Teuchos::RCP< const Comm< OrdinalType > > getComm()
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setParameterList(RCP< ParameterList > const &paramList)
void setOption(const char option_true[], const char option_false[], bool *option_val, const char documentation[]=NULL)
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
Ptr< T > ptr() const
EParseCommandLineReturn parse(int argc, char *argv[], std::ostream *errout=&std::cerr) const
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
void report(std::ostream &os)
Concrete subclass of Thyra::LinearSolverBuilderBase for creating Thyra::LinearOpWithSolveFactoryBase ...
map_type::global_ordinal_type GO