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 //
4 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
5 // Copyright (2009) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 //@HEADER
41 */
42 
43 #include <iostream>
44 
45 /*
46  Call Ifpack2 via the Stratimikos interface.
47 
48 Usage:
49 ./Ifpack2_Stratimikos.exe : use xml configuration file stratimikos_ParameterList.xml
50 
51 Note:
52 The source code is not MueLu specific and can be used with any Stratimikos strategy.
53 */
54 
55 // Teuchos includes
56 #include <Teuchos_ConfigDefs.hpp>
58 #include <Teuchos_StackedTimer.hpp>
59 #include <Teuchos_RCP.hpp>
64 
65 // Thyra includes
66 #include <Thyra_LinearOpWithSolveBase.hpp>
67 #include <Thyra_VectorBase.hpp>
68 #include <Thyra_SolveSupportTypes.hpp>
69 
70 // Stratimikos includes
71 #include <Stratimikos_LinearSolverBuilder.hpp>
72 #include <Stratimikos_InternalConfig.h>
73 
74 // Xpetra include
75 #include <Xpetra_Parameters.hpp>
76 #include <Xpetra_ThyraUtils.hpp>
77 
78 // Galeri includes
79 #include <Galeri_XpetraParameters.hpp>
80 #include <Galeri_XpetraProblemFactory.hpp>
81 #include <Galeri_XpetraUtils.hpp>
82 #include <Galeri_XpetraMaps.hpp>
83 
84 
85 template <class Scalar>
86 int
87 main_(int argc, char *argv[], Teuchos::CommandLineProcessor& clp) {
88  typedef Tpetra::Map<> map_type;
89  typedef map_type::local_ordinal_type LocalOrdinal;
90  typedef map_type::global_ordinal_type GlobalOrdinal;
91  typedef map_type::node_type Node;
92  using Teuchos::RCP;
93  using Teuchos::rcp;
96  #include <Xpetra_UseShortNames.hpp>
97 
98  bool success = false;
99  bool verbose = true;
100  try {
101 
102  //
103  // MPI initialization
104  //
105  // Teuchos::CommandLineProcessor clp(false);
106  const auto comm = Teuchos::DefaultComm<int>::getComm ();
107 
108  //
109  // Parameters
110  //
111  // manage parameters of the test case
112  Galeri::Xpetra::Parameters<GlobalOrdinal> galeriParameters(clp, 100, 100, 100, "Laplace2D");
113  // manage parameters of Xpetra
114  Xpetra::Parameters xpetraParameters(clp);
115 
116  // command line parameters
117  std::string xmlFileName = "stratimikos_ParameterList.xml"; clp.setOption("xml", &xmlFileName, "read parameters from an xml file");
118  std::string yamlFileName = ""; clp.setOption("yaml", &yamlFileName, "read parameters from a yaml file");
119  bool printTimings = false; clp.setOption("timings", "notimings", &printTimings, "print timings to screen");
120  bool use_stacked_timer = false; clp.setOption("stacked-timer", "no-stacked-timer", &use_stacked_timer, "Run with or without stacked timer output");
121  std::string timingsFormat = "table-fixed"; clp.setOption("time-format", &timingsFormat, "timings format (table-fixed | table-scientific | yaml)");
122  int numVectors = 1; clp.setOption("multivector", &numVectors, "number of rhs to solve simultaneously");
123  int numSolves = 1; clp.setOption("numSolves", &numSolves, "number of times the system should be solved");
124 
125  switch (clp.parse(argc,argv)) {
126  case Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED: return EXIT_SUCCESS;
130  }
131 
132  RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
133  Teuchos::FancyOStream& out = *fancy;
134  out.setOutputToRootOnly(0);
135 
136  // Set up timers
138  if (use_stacked_timer)
139  stacked_timer = rcp(new Teuchos::StackedTimer("Main"));
140  TimeMonitor::setStackedTimer(stacked_timer);
141 
142  // Read in parameter list
143  TEUCHOS_TEST_FOR_EXCEPTION(xmlFileName == "" && yamlFileName == "", std::runtime_error,
144  "Need to provide xml or yaml input file");
145  RCP<ParameterList> paramList = rcp(new ParameterList("params"));
146  if (yamlFileName != "")
147  Teuchos::updateParametersFromYamlFileAndBroadcast(yamlFileName, paramList.ptr(), *comm);
148  else
149  Teuchos::updateParametersFromXmlFileAndBroadcast(xmlFileName, paramList.ptr(), *comm);
150 
151  //
152  // Construct the problem
153  //
154 
155  RCP<Matrix> A;
156  RCP<const Map> map;
157  RCP<MultiVector> X, B;
158 
159  std::ostringstream galeriStream;
160  Teuchos::ParameterList galeriList = galeriParameters.GetParameterList();
161  galeriStream << "========================================================\n" << xpetraParameters;
162  galeriStream << galeriParameters;
163 
164  // Galeri will attempt to create a square-as-possible distribution of subdomains di, e.g.,
165  // d1 d2 d3
166  // d4 d5 d6
167  // d7 d8 d9
168  // d10 d11 d12
169  // A perfect distribution is only possible when the #processors is a perfect square.
170  // This *will* result in "strip" distribution if the #processors is a prime number or if the factors are very different in
171  // size. For example, np=14 will give a 7-by-2 distribution.
172  // If you don't want Galeri to do this, specify mx or my on the galeriList.
173  std::string matrixType = galeriParameters.GetMatrixType();
174 
175  // Create map
176  if (matrixType == "Laplace1D") {
177  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian1D", comm, galeriList);
178 
179  } else if (matrixType == "Laplace2D" || matrixType == "Star2D" ||
180  matrixType == "BigStar2D" || matrixType == "AnisotropicDiffusion" || matrixType == "Elasticity2D") {
181  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian2D", comm, galeriList);
182 
183  } else if (matrixType == "Laplace3D" || matrixType == "Brick3D" || matrixType == "Elasticity3D") {
184  map = Galeri::Xpetra::CreateMap<LO, GO, Node>(xpetraParameters.GetLib(), "Cartesian3D", comm, galeriList);
185  }
186 
187  // Expand map to do multiple DOF per node for block problems
188  if (matrixType == "Elasticity2D")
189  map = Xpetra::MapFactory<LO,GO,Node>::Build(map, 2);
190  if (matrixType == "Elasticity3D")
191  map = Xpetra::MapFactory<LO,GO,Node>::Build(map, 3);
192 
193  galeriStream << "Processor subdomains in x direction: " << galeriList.get<GO>("mx") << std::endl
194  << "Processor subdomains in y direction: " << galeriList.get<GO>("my") << std::endl
195  << "Processor subdomains in z direction: " << galeriList.get<GO>("mz") << std::endl
196  << "========================================================" << std::endl;
197 
198  if (matrixType == "Elasticity2D" || matrixType == "Elasticity3D") {
199  // Our default test case for elasticity: all boundaries of a square/cube have Neumann b.c. except left which has Dirichlet
200  galeriList.set("right boundary" , "Neumann");
201  galeriList.set("bottom boundary", "Neumann");
202  galeriList.set("top boundary" , "Neumann");
203  galeriList.set("front boundary" , "Neumann");
204  galeriList.set("back boundary" , "Neumann");
205  }
206 
207  RCP<Galeri::Xpetra::Problem<Map,CrsMatrixWrap,MultiVector> > Pr =
208  Galeri::Xpetra::BuildProblem<SC,LO,GO,Map,CrsMatrixWrap,MultiVector>(galeriParameters.GetMatrixType(), map, galeriList);
209  A = Pr->BuildMatrix();
210 
211  if (matrixType == "Elasticity2D" ||
212  matrixType == "Elasticity3D") {
213  A->SetFixedBlockSize((galeriParameters.GetMatrixType() == "Elasticity2D") ? 2 : 3);
214  }
215 
216  out << galeriStream.str();
217  X = MultiVectorFactory::Build(map, numVectors);
218  B = MultiVectorFactory::Build(map, numVectors);
219  B->putScalar(1);
220  X->putScalar(0);
221 
222  //
223  // Build Thyra linear algebra objects
224  //
225 
226  RCP<const Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> > xpCrsA = Teuchos::rcp_dynamic_cast<const Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(A);
227 
228  RCP<const Thyra::LinearOpBase<Scalar> > thyraA = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyra(xpCrsA->getCrsMatrix());
229  RCP< Thyra::MultiVectorBase<Scalar> > thyraX = Teuchos::rcp_const_cast<Thyra::MultiVectorBase<Scalar> >(Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyraMultiVector(X));
230  RCP<const Thyra::MultiVectorBase<Scalar> > thyraB = Xpetra::ThyraUtils<Scalar,LocalOrdinal,GlobalOrdinal,Node>::toThyraMultiVector(B);
231 
232  //
233  // Build Stratimikos solver
234  //
235 
236  // This is the Stratimikos main class (= factory of solver factory).
237  Stratimikos::LinearSolverBuilder<Scalar> linearSolverBuilder;
238 
239  // Setup solver parameters using a Stratimikos parameter list.
240  linearSolverBuilder.setParameterList(paramList);
241 
242  // Build a new "solver factory" according to the previously specified parameter list.
243  RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > solverFactory = Thyra::createLinearSolveStrategy(linearSolverBuilder);
244  auto precFactory = solverFactory->getPreconditionerFactory();
245  RCP<Thyra::PreconditionerBase<Scalar> > prec;
247  if (!precFactory.is_null()) {
248  prec = precFactory->createPrec();
249 
250  // Build a Thyra operator corresponding to A^{-1} computed using the Stratimikos solver.
251  Thyra::initializePrec<Scalar>(*precFactory, thyraA, prec.ptr());
252  thyraInverseA = solverFactory->createOp();
253  Thyra::initializePreconditionedOp<Scalar>(*solverFactory, thyraA, prec, thyraInverseA.ptr());
254  } else {
255  thyraInverseA = Thyra::linearOpWithSolve(*solverFactory, thyraA);
256  }
257 
258  // Solve Ax = b.
259  Thyra::SolveStatus<Scalar> status = Thyra::solve<Scalar>(*thyraInverseA, Thyra::NOTRANS, *thyraB, thyraX.ptr());
260 
261  success = (status.solveStatus == Thyra::SOLVE_STATUS_CONVERGED);
262 
263  for (int solveno = 1; solveno < numSolves; solveno++) {
264  if (!precFactory.is_null())
265  Thyra::initializePrec<Scalar>(*precFactory, thyraA, prec.ptr());
266  thyraX->assign(0.);
267 
268  status = Thyra::solve<Scalar>(*thyraInverseA, Thyra::NOTRANS, *thyraB, thyraX.ptr());
269 
270  success = success && (status.solveStatus == Thyra::SOLVE_STATUS_CONVERGED);
271  }
272 
273  // print timings
274  if (printTimings) {
275  if (use_stacked_timer) {
276  stacked_timer->stop("Main");
278  options.output_fraction = options.output_histogram = options.output_minmax = true;
279  stacked_timer->report(out, comm, options);
280  } else {
281  RCP<ParameterList> reportParams = rcp(new ParameterList);
282  if (timingsFormat == "yaml") {
283  reportParams->set("Report format", "YAML"); // "Table" or "YAML"
284  reportParams->set("YAML style", "compact"); // "spacious" or "compact"
285  }
286  reportParams->set("How to merge timer sets", "Union");
287  reportParams->set("alwaysWriteLocal", false);
288  reportParams->set("writeGlobalStats", true);
289  reportParams->set("writeZeroTimers", false);
290 
291  const std::string filter = "";
292 
293  std::ios_base::fmtflags ff(out.flags());
294  if (timingsFormat == "table-fixed") out << std::fixed;
295  else out << std::scientific;
296  TimeMonitor::report(comm.ptr(), out, filter, reportParams);
297  out << std::setiosflags(ff);
298  }
299  }
300 
301  TimeMonitor::clearCounters();
302  out << std::endl;
303 
304  }
305  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success);
306 
307  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
308 }
309 
310 
316 };
317 
318 int
319 main(int argc, char *argv[]) {
320  Teuchos::GlobalMPISession session (&argc, &argv, NULL);
321 
323  scalarType scalar = DOUBLE;
324  std::vector<const char*> availableScalarTypeStrings;
325  std::vector<scalarType> availableScalarTypes;
326 #ifdef HAVE_TPETRA_INST_DOUBLE
327  availableScalarTypeStrings.push_back("double");
328  availableScalarTypes.push_back(DOUBLE);
329 #endif
330 #ifdef HAVE_TPETRA_INST_FLOAT
331  availableScalarTypeStrings.push_back("float");
332  availableScalarTypes.push_back(FLOAT);
333 #endif
334 #ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
335  availableScalarTypeStrings.push_back("complex<double>");
336  availableScalarTypes.push_back(COMPLEX_DOUBLE);
337 #endif
338 #ifdef HAVE_TPETRA_INST_COMPLEX_FLOAT
339  availableScalarTypeStrings.push_back("complex<float>");
340  availableScalarTypes.push_back(COMPLEX_FLOAT);
341 #endif
342  clp.setOption("scalarType", &scalar, availableScalarTypes.size(), availableScalarTypes.data(), availableScalarTypeStrings.data(), "scalar type");
343  clp.recogniseAllOptions(false);
344  switch (clp.parse(argc, argv, NULL)) {
345  case Teuchos::CommandLineProcessor::PARSE_ERROR: return EXIT_FAILURE;
349  }
350 
351 #ifdef HAVE_TPETRA_INST_DOUBLE
352  if (scalar == DOUBLE)
353  return main_<double>(argc, argv, clp);
354 #endif
355 #ifdef HAVE_TPETRA_INST_FLOAT
356  if (scalar == FLOAT)
357  return main_<float>(argc, argv, clp);
358 #endif
359 #ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
360  if (scalar == COMPLEX_DOUBLE)
361  return main_<std::complex<double> >(argc, argv, clp);
362 #endif
363 #ifdef HAVE_TPETRA_INST_COMPLEX_FLOAT
364  if (scalar == COMPLEX_FLOAT)
365  return main_<std::complex<float> >(argc, argv, clp);
366 #endif
367 }
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)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
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