Belos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BelosSolverFactory.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Belos: Block Linear Solvers Package
4 //
5 // Copyright 2004-2016 NTESS and the Belos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef __Belos_SolverFactory_hpp
11 #define __Belos_SolverFactory_hpp
12 
13 #include <BelosConfigDefs.hpp>
14 #include <BelosOutputManager.hpp>
15 #include <BelosSolverManager.hpp>
16 
19 
20 #include <Teuchos_Describable.hpp>
23 
24 #include <map>
25 #include <sstream>
26 #include <stdexcept>
27 #include <vector>
28 
29 namespace Belos {
30 namespace Impl {
31 
33 void
34 printStringArray (std::ostream& out,
36 
38 void
39 printStringArray (std::ostream& out,
40  const std::vector<std::string>& array);
41 
43 std::string
44 upperCase (const std::string& s);
45 
62 template<class Scalar, class MV, class OP>
65 {
66 protected:
67  // SolverFactoryParent should never be created directly. Usually it will be
68  // created through derived classes EpetraSolverFactory, TpetraSolverFactory,
69  // BelosSolverFactory, or XpetraSolverFactory. If you are doing custom types
70  // and include BelosSolverFactory_Generic.hpp you should explicitly use
71  // GenericSolverFactory, not SolverFactory, which will avoid an error trying
72  // to construct here. GenericSolverFactory is special because it registers
73  // all the solver managers for any type. Note that if you are using hard coded
74  // types it is possible that some the type sets will be connecting to an
75  // automatic solver factory such as TpetraSolverFactory while another type
76  // set could be going through the GenericSolverFactory.
78 
79 public:
85  typedef ::Belos::SolverManager<Scalar, MV, OP> solver_base_type;
86 
90 
91 protected:
130  getSolver (const std::string& solverName,
131  const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
132 
133 public:
144  create (const std::string& solverName,
145  const Teuchos::RCP<Teuchos::ParameterList>& solverParams);
146 
152  virtual int numSupportedSolvers () const;
153 
160 
162  virtual bool isSupported (const std::string& solverName) const;
163 
178  void
180 
188  void
189  clearFactories ();
190 
192  static void
193  registerSolver (const std::string & solverName,
195  {
197  instance == Teuchos::null,
198  std::invalid_argument, "Belos::SolverFactoryParent::registerSolver "
199  "was given a null solver to register.");
200 
201  get_solverManagers()[solverName] = instance;
202  }
203 
205  static bool
206  isSolverRegistered (const std::string & solverName)
207  {
208  return (get_solverManagers().find(solverName) != get_solverManagers().end());
209  }
210 
212 
213 
215  virtual std::string description() const;
216 
222  virtual void
224  const Teuchos::EVerbosityLevel verbLevel =
227 
228 private:
230  static std::vector<Teuchos::RCP<custom_solver_factory_type> > factories_;
231 
232  static std::map<const std::string, Teuchos::RCP<typename
235  static std::map<const std::string, Teuchos::RCP<typename
237  return solverManagers;
238  }
239 };
240 
241 template<class Scalar, class MV, class OP>
242 std::vector<Teuchos::RCP<typename SolverFactoryParent<Scalar, MV, OP>::custom_solver_factory_type> >
243 SolverFactoryParent<Scalar, MV, OP>::factories_;
244 
245 template<class SolverClass, class Scalar, class MV, class OP>
246 void registerSolverSubclassForTypes (const std::string & solverName) {
248  Teuchos::RCP<SolverClass> solver (new SolverClass);
250  }
251 }
252 
253 // specializations get a typedef "type"
254 // If this compile fails then the error is likely that BelosSolverFactory.hpp
255 // was included directly but the specific sub class of SolverFactoryParent was
256 // not included. Examples are:
257 // BelosSolverFactory_Belos.hpp, BelosSolverFactory_Epetra.hpp,
258 // BelosSolverFactory_Tpetra.hpp, BelosSolverFactory_Xpetra.hpp
259 // These were setup to be automatically included through the corresponding
260 // adapter includes so something may have gone wrong with that.
261 template<class SC, class MV, class OP>
263  public:
264  // TODO: This could be deleted except for the GenericSolverFactory which
265  // needs to be declared for all types. So I added this but then if you
266  // include GenericSolverFactory you will have SolverFactory simply point
267  // to SolverFactoryParent. I changed that constructor to be protected so
268  // using SolverFactory (pointing to SolverFactoryParent) will give a compile
269  // error. For GenericSolverFactory you must explicity use GenericSolverFactory
270  // in the code. This may be preferable because it makes it clear that
271  // factory is not connecting to the standard set of types. I'm not sure how
272  // to do this in a better way.
274 };
275 
276 } // namespace Impl
277 
278 // Derived setups such as found in BelosSolverFactory_Tpetra.hpp will define
279 // this specialization so that SolverFactory will be used as SolverFactoryTpetra.
280 template<class SC, class MV, class OP>
281 using SolverFactory = typename ::Belos::Impl::SolverFactorySelector<SC, MV, OP>::type;
282 
283 namespace Impl {
284 
285 template<class Scalar, class MV, class OP>
288 create (const std::string& solverName,
289  const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
290 {
291  using Teuchos::RCP;
292  RCP<solver_base_type> solver = this->getSolver (solverName, solverParams);
294  (solver.is_null (), std::invalid_argument,
295  "Invalid or unsupported Belos solver name \"" << solverName << "\".");
296  return solver;
297 }
298 
299 template<class Scalar, class MV, class OP>
302 getSolver (const std::string& solverName,
303  const Teuchos::RCP<Teuchos::ParameterList>& solverParams)
304 {
305  using Teuchos::RCP;
306 
307  // First, check the overriding factories.
308  for (std::size_t k = 0; k < factories_.size (); ++k) {
309  RCP<CustomSolverFactory<Scalar, MV, OP> > factory = factories_[k];
310  if (! factory.is_null ()) {
311  RCP<SolverManager<Scalar, MV, OP> > solver =
312  factory->getSolver (solverName, solverParams);
313  if (! solver.is_null ()) {
314  return solver;
315  }
316  }
317  }
318 
319  // Upper-case version of the input solver name.
320  const std::string solverNameUC = Impl::upperCase (solverName);
321 
322  // Check whether the given name is an alias.
323  std::pair<std::string, bool> aliasResult =
324  Details::getCanonicalNameFromAlias (solverNameUC);
325  const std::string candidateCanonicalName = aliasResult.first;
326  const bool isAnAlias = aliasResult.second;
327 
328  // Get the standardized name for enum reference and map
329  std::string standardized_name = isAnAlias ?
330  candidateCanonicalName :
331  solverNameUC;
332 
333  // If the input list is null, we create a new list and use that.
334  // This is OK because the effect of a null parameter list input is
335  // to use default parameter values. Thus, we can always replace a
336  // null list with an empty list.
338  solverParams.is_null() ? Teuchos::parameterList() : solverParams;
339 
340  // Possibly modify the input parameter list as needed.
341  if (isAnAlias) {
342  Details::reviseParameterListForAlias (solverNameUC, *pl);
343  }
344 
345  typename std::map<const std::string, Teuchos::RCP<
347  it = get_solverManagers().find (standardized_name);
348 
350  it == get_solverManagers().end(),
351  std::invalid_argument, "Belos solver manager " << solverNameUC <<
352  " with standardized name " << standardized_name << " has not been"
353  " registered.");
354 
356  it->second == Teuchos::null,
357  std::logic_error, "Belos::SolverFactoryParent: The registered "
358  "clone source for " << solverNameUC << " with standardized name "
359  << standardized_name << " is null which should never happen."
360  ". Please report this bug to the Belos developers.");
361 
362  // clone the solver
363  RCP<solver_base_type> solver = (it->second)->clone ();
364 
366  solver == Teuchos::null,
367  std::logic_error, "Belos::SolverFactoryParent: Failed "
368  "to clone SolverManager with name " << solverNameUC << " with standardized"
369  " name" << standardized_name << "."
370  ". Please report this bug to the Belos developers.");
371 
372  // Some solvers may not like to get a null ParameterList. If params
373  // is null, replace it with an empty parameter list. The solver
374  // will fill in default parameters for that case. Use the name of
375  // the solver's default parameters to name the new empty list.
376  if (pl.is_null()) {
377  pl = Teuchos::parameterList (solver->getValidParameters ()->name ());
378  }
379 
381  pl.is_null(), std::logic_error,
382  "Belos::SolverFactory: ParameterList to pass to solver is null. This "
383  "should never happen. Please report this bug to the Belos developers.");
384  solver->setParameters (pl);
385  return solver;
386 }
387 
388 
389 template<class Scalar, class MV, class OP>
390 void
393 {
394  factories_.push_back (factory);
395 }
396 
397 
398 template<class Scalar, class MV, class OP>
399 void
402 {
403  factories_.clear();
404 }
405 
406 
407 template<class Scalar, class MV, class OP>
408 std::string
410 description () const
411 {
413 
414  std::ostringstream out;
415  out << "\"Belos::SolverFactory\": {";
416  if (this->getObjectLabel () != "") {
417  out << "Label: " << this->getObjectLabel () << ", ";
418  }
419  out << "Scalar: \"" << TypeNameTraits<Scalar>::name ()
420  << "\", MV: \"" << TypeNameTraits<MV>::name ()
421  << "\", OP: \"" << TypeNameTraits<OP>::name ()
422  << "\"}";
423  return out.str ();
424 }
425 
426 
427 template<class Scalar, class MV, class OP>
428 void
431  const Teuchos::EVerbosityLevel verbLevel) const
432 {
434  using std::endl;
435 
436  const Teuchos::EVerbosityLevel vl =
437  (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
438 
439  if (vl == Teuchos::VERB_NONE) {
440  return;
441  }
442 
443  // By convention, describe() always begins with a tab.
444  Teuchos::OSTab tab0 (out);
445  // The description prints in YAML format. The class name needs to
446  // be protected with quotes, so that YAML doesn't get confused
447  // between the colons in the class name and the colon separating
448  // (key,value) pairs.
449  out << "\"Belos::SolverFactory\":" << endl;
450  if (this->getObjectLabel () != "") {
451  out << "Label: " << this->getObjectLabel () << endl;
452  }
453  {
454  out << "Template parameters:" << endl;
455  Teuchos::OSTab tab1 (out);
456  out << "Scalar: \"" << TypeNameTraits<Scalar>::name () << "\"" << endl
457  << "MV: \"" << TypeNameTraits<MV>::name () << "\"" << endl
458  << "OP: \"" << TypeNameTraits<OP>::name () << "\"" << endl;
459  }
460 
461  // At higher verbosity levels, print out the list of supported solvers.
462  if (vl > Teuchos::VERB_LOW) {
463  Teuchos::OSTab tab1 (out);
464  out << "Number of solvers: " << numSupportedSolvers ()
465  << endl;
466  out << "Canonical solver names: ";
468  out << endl;
469 
470  out << "Aliases to canonical names: ";
472  out << endl;
473  }
474 }
475 
476 template<class Scalar, class MV, class OP>
477 int
480 {
481  int numSupported = 0;
482 
483  // First, check the overriding factories.
484  for (std::size_t k = 0; k < factories_.size (); ++k) {
485  using Teuchos::RCP;
486  RCP<custom_solver_factory_type> factory = factories_[k];
487  if (! factory.is_null ()) {
488  numSupported += factory->numSupportedSolvers ();
489  }
490  }
491 
492  // Now, see how many solvers this factory supports.
493  return numSupported + Details::numSupportedSolvers ();
494 }
495 
496 template<class Scalar, class MV, class OP>
500 {
501  typedef std::vector<std::string>::const_iterator iter_type;
503 
504  // First, check the overriding factories.
505  const std::size_t numFactories = factories_.size ();
506  for (std::size_t factInd = 0; factInd < numFactories; ++factInd) {
507  Teuchos::RCP<custom_solver_factory_type> factory = factories_[factInd];
508  if (! factory.is_null ()) {
509  std::vector<std::string> supportedSolvers =
510  factory->supportedSolverNames ();
511  const std::size_t numSolvers = supportedSolvers.size ();
512  for (std::size_t solvInd = 0; solvInd < numSolvers; ++solvInd) {
513  names.push_back (supportedSolvers[solvInd]);
514  }
515  }
516  }
517 
518  {
519  std::vector<std::string> aliases = Details::solverNameAliases ();
520  for (iter_type iter = aliases.begin (); iter != aliases.end (); ++iter) {
521  names.push_back (*iter);
522  }
523  }
524  {
525  std::vector<std::string> canonicalNames = Details::canonicalSolverNames ();
526  for (iter_type iter = canonicalNames.begin ();
527  iter != canonicalNames.end (); ++iter) {
528  names.push_back (*iter);
529  }
530  }
531  return names;
532 }
533 
534 template<class Scalar, class MV, class OP>
535 bool
537 isSupported (const std::string& solverName) const
538 {
539  // First, check the overriding factories.
540  const std::size_t numFactories = factories_.size ();
541  for (std::size_t factInd = 0; factInd < numFactories; ++factInd) {
542  using Teuchos::RCP;
543  RCP<custom_solver_factory_type> factory = factories_[factInd];
544  if (! factory.is_null ()) {
545  if (factory->isSupported (solverName)) {
546  return true;
547  }
548  }
549  }
550  // Now, check this factory.
551 
552  // Upper-case version of the input solver name.
553  const std::string solverNameUC = Impl::upperCase (solverName);
554 
555  // Check whether the given name is an alias.
556  std::pair<std::string, bool> aliasResult =
557  Details::getCanonicalNameFromAlias (solverNameUC);
558  const std::string candidateCanonicalName = aliasResult.first;
559  const bool validCanonicalName =
560  (get_solverManagers().find(candidateCanonicalName) != get_solverManagers().end());
561  return validCanonicalName;
562 }
563 
564 } // namespace Impl
565 } // namespace Belos
566 
567 // We have things like BelosSolverFactory_Tpetra.hpp which are automatically
568 // included through the adapter includes to maintain backwards compatibility.
569 // The Belos version itself doesn't have a place like that so included here
570 // which is awkward. It might make more sense to just copy that code here but
571 // it has symmetry with the other files and wanted to preserve that. To discuss.
573 
574 #endif // __Belos_SolverFactory_hpp
575 
Interface for custom Belos solver factories.
Class which manages the output and verbosity of the Belos solvers.
static std::vector< Teuchos::RCP< custom_solver_factory_type > > factories_
The list of solver factories given to addFactory.
SolverFactoryParent< SC, MV, OP > type
static void registerSolver(const std::string &solverName, Teuchos::RCP< SolverFactoryParent< Scalar, MV, OP >::solver_base_type > instance)
register a solver for Inverted Injection (DII).
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void clearFactories()
Clear all custom solver factories.
std::string upperCase(const std::string &s)
Return the upper-case version of s.
virtual int numSupportedSolvers() const
Number of supported solvers.
void addFactory(const Teuchos::RCP< custom_solver_factory_type > &factory)
Add a custom solver factory.
Declaration of alias functions for solver names.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Describe this object.
Pure virtual base class which describes the basic interface for a solver manager. ...
bool is_null(const RCP< T > &p)
std::vector< std::string > solverNameAliases()
List of supported aliases (to canonical solver names).
void printStringArray(std::ostream &out, const Teuchos::ArrayView< const std::string > &array)
Print the given array of strings, in YAML format, to out.
int numSupportedSolvers()
Number of Belos solvers supported for any linear algebra implementation (&quot;generically&quot;).
The Belos::SolverManager is a templated virtual base class that defines the basic interface that any ...
virtual Teuchos::RCP< solver_base_type > getSolver(const std::string &solverName, const Teuchos::RCP< Teuchos::ParameterList > &solverParams)
Return an instance of the specified solver, or Teuchos::null if this factory does not provide the req...
static const EVerbosityLevel verbLevel_default
TransListIter iter
virtual Teuchos::Array< std::string > supportedSolverNames() const
List of supported solver names.
void push_back(const value_type &x)
virtual Teuchos::RCP< solver_base_type > create(const std::string &solverName, const Teuchos::RCP< Teuchos::ParameterList > &solverParams)
Create, configure, and return the specified solver.
Specializations of Belos::SolverFactory may inherit from this class to get basic SolverFactory functi...
static std::map< const std::string, Teuchos::RCP< typename SolverFactoryParent< Scalar, MV, OP >::solver_base_type > > & get_solverManagers()
std::pair< std::string, bool > getCanonicalNameFromAlias(const std::string &candidateAlias)
Get the candidate canonical name for a given candidate alias.
::Belos::SolverManager< Scalar, MV, OP > solver_base_type
The type of the solver returned by create().
size_type size() const
void reviseParameterListForAlias(const std::string &aliasName, Teuchos::ParameterList &solverParams)
Modify the input ParameterList appropriately for the given solver alias.
void registerSolverSubclassForTypes(const std::string &solverName)
virtual bool isSupported(const std::string &solverName) const
Whether the given solver name names a supported solver.
Belos header file which uses auto-configuration information to include necessary C++ headers...
TransListIter end
typename::Belos::Impl::SolverFactorySelector< SC, MV, OP >::type SolverFactory
virtual std::string description() const
A string description of this object.
static bool isSolverRegistered(const std::string &solverName)
is solver registered for Inverted Injection (DII).
CustomSolverFactory< Scalar, MV, OP > custom_solver_factory_type
The type of a solver factory that users may give to addFactory() (which see below) ...
std::vector< std::string > canonicalSolverNames()
List of canonical solver names.