Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Trilinos_Details_LinearSolverFactory.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef TRILINOS_DETAILS_LINEARSOLVER_FACTORY_HPP
11 #define TRILINOS_DETAILS_LINEARSOLVER_FACTORY_HPP
12 
49 
50 #include "Teuchos_RCP.hpp" // includes Teuchos_ConfigDefs.hpp
51 #include "TeuchosRemainder_config.h"
52 #include <map>
53 #ifdef HAVE_TEUCHOSCORE_CXX11
54 # include <memory> // std::shared_ptr
55 #endif // HAVE_TEUCHOSCORE_CXX11
56 #include <stdexcept>
57 #include <sstream>
58 #include <string>
59 
60 
61 // Attempted fix for Bug 6392: declare all packages'
62 // LinearSolverFactory registration functions here, with weak linkage.
63 // This works whether or not the packages in question are actually
64 // enabled. In createPackageNames() below, actually call these
65 // functions if they are linked in. We only need to do this if
66 // building with static libraries; if building with dynamic libraries,
67 // each package takes care of this on its own.
68 //
69 // I wrote "attempted" because it DOESN'T WORK. It doesn't matter
70 // whether these or their uses are in the .cpp or .hpp file, or
71 // whether they are in a regular function that gets compiled or a
72 // templated function that might not.
73 #if ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
74 // FIXME (mfh 21 Aug 2015) NONE of the commented-out things work.
75 
76 // namespace Amesos2 {
77 // namespace Details {
78 // extern void __attribute__((weak)) registerLinearSolverFactory ();
79 // } // namespace Details
80 // } // namespace Amesos2
81 
82 // namespace Ifpack2 {
83 // namespace Details {
84 // // extern void __attribute__((weak)) registerLinearSolverFactory ();
85 // // void __attribute__((weak)) registerLinearSolverFactory ();
86 // // evoid __attribute__((weak)) registerLinearSolverFactory ();
87 // } // namespace Details
88 // } // namespace Ifpack2
89 #endif // ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
90 
91 
94 namespace Trilinos {
95 
102 namespace Details {
103 
104 template<class MV, class OP, class NormType>
105 class LinearSolver; // forward declaration
106 
133 template<class MV, class OP, class NormType>
135 getLinearSolver (const std::string& packageName, const std::string& solverName);
136 
202 template<class MV, class OP, class NormType>
204 public:
205  virtual ~LinearSolverFactory() {}
214  getLinearSolver (const std::string& solverName) = 0;
215 };
216 
294 template<class MV, class OP, class NormType>
295 void
296 registerLinearSolverFactory (const std::string& packageName,
297 #ifdef HAVE_TEUCHOSCORE_CXX11
298  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory);
299 #else
301 #endif // HAVE_TEUCHOSCORE_CXX11
302 
303 //
304 // EVERYTHING BELOW THIS LINE IS AN IMPLEMENTATION DETAIL
305 //
306 
312 namespace Impl {
313 
324 bool rememberRegisteredSomeLinearSolverFactory (const std::string& packageName);
325 
331 bool registeredSomeLinearSolverFactory (const std::string& packageName);
332 
340 
367 template<class MV, class OP, class NormType>
369 public:
375 #ifdef HAVE_TEUCHOSCORE_CXX11
376  typedef std::shared_ptr<LinearSolverFactory<MV, OP, NormType> > factory_pointer_type;
377 #else
379 #endif // HAVE_TEUCHOSCORE_CXX11
380 
388  typedef std::map<std::string, factory_pointer_type> map_type;
389 
390 public:
403  static factory_pointer_type
404  getFactory (const std::string& packageName)
405  {
406  createFactories ();
407  typedef typename map_type::iterator iter_type;
408  iter_type it = factories_->find (packageName);
409  if (it == factories_->end ()) { // didn't find package name
410  return factory_pointer_type (); // null pointer
411  } else { // found package name
412  return it->second;
413  }
414  }
415 
430  static void
431  registerLinearSolverFactory (const std::string& packageName,
432  const factory_pointer_type& factory)
433  {
435  (factory.get () == NULL, std::invalid_argument, "Trilinos::Details::"
436  "LinearSolverFactoryRepository::registerLinearSolverFactory: Input "
437  "'factory' is NULL!");
438  createFactories ();
439  if (factories_->find (packageName) == factories_->end ()) {
440  factories_->insert (std::make_pair (packageName, factory));
441  }
442  }
443 
444 private:
455  static map_type* factories_;
456 
460  static void createFactories () {
461  if (factories_ == NULL) {
462  factories_ = new map_type ();
463  // It _is_ possible for atexit() to fail (e.g., because it ran
464  // out of memory for storing callbacks). We could throw an
465  // exception here in that case, but I think it's better just
466  // to let the minor memory leak happen.
467  (void) atexit (freeFactories);
468  }
470  (factories_ == NULL, std::logic_error, "Trilinos::Details::"
471  "LinearSolverFactoryRepository::createFactories: "
472  "Should never get here! factories_ is NULL.");
473  }
474 
483  static void freeFactories () {
484  if (factories_ != NULL) {
485  delete factories_;
486  factories_ = NULL;
487  }
488  }
489 };
490 
491 // This is _not_ an explicit instantiation. C++ wants it, because
492 // LinearSolverFactoryRepository is a templated class with a static
493 // (class) member.
494 template<class MV, class OP, class NormType>
495 typename LinearSolverFactoryRepository<MV, OP, NormType>::map_type*
496 LinearSolverFactoryRepository<MV, OP, NormType>::factories_ = NULL;
497 
498 } // namespace Impl
499 
500 //
501 // Definitions of nonmember functions
502 //
503 
504 template<class MV, class OP, class NormType>
505 void
506 registerLinearSolverFactory (const std::string& packageName,
507 #ifdef HAVE_TEUCHOSCORE_CXX11
508  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory)
509 #else
511 #endif // HAVE_TEUCHOSCORE_CXX11
512 {
515 }
516 
517 template<class MV, class OP, class NormType>
519 getLinearSolver (const std::string& packageName, const std::string& solverName)
520 {
521  using Teuchos::RCP;
523  typedef Impl::LinearSolverFactoryRepository<MV, OP, NormType> repo_type;
524  typedef typename repo_type::factory_pointer_type factory_pointer_type;
525  typedef LinearSolver<MV, OP, NormType> solver_type;
526  const char prefix[] = "Trilinos::Details::getLinearSolver: ";
527 
528  // FIXME (mfh 21 Aug 2015) Attempted fix for Bug 6392: DOES NOT WORK.
529  // (Compiles just fine, but test doesn't pass.)
530 #if ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
531  // if (Amesos2::Details::registerLinearSolverFactory == NULL) {
532  // std::cout << "-- Amesos2::Details::registerLinearSolverFactory is NULL" << std::endl;
533  // } else {
534  // Amesos2::Details::registerLinearSolverFactory ();
535  // }
536  // if (Ifpack2::Details::registerLinearSolverFactory == NULL) {
537  // std::cout << "-- Ifpack2::Details::registerLinearSolverFactory is NULL" << std::endl;
538  // } else {
539  // Ifpack2::Details::registerLinearSolverFactory ();
540  // }
541 #endif // ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
542 
543  // Whether the CMake run-time registration option is ON. This
544  // doesn't actually say whether run-time registration has happened
545  // for the current combination of (MV, OP, NormType) template
546  // parameters.
547  const bool haveRunTimeReg =
549 
550  const bool pkgExists = Impl::registeredSomeLinearSolverFactory (packageName);
552  (! pkgExists, std::invalid_argument, prefix << "Package \"" << packageName
553  << "\" never registered a LinearSolverFactory for _any_ combination of "
554  "template parameters MV, OP, and NormType. This means either that the "
555  "package name is invalid, or that the package is not enabled. "
556  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
557  << (haveRunTimeReg ? "ON" : "OFF") << ".");
558 
559  factory_pointer_type factory = repo_type::getFactory (packageName);
561  (factory.get () == NULL, std::invalid_argument, prefix << "Package \"" <<
562  packageName << "\" is valid, but it never registered a LinearSolverFactory"
563  " for template parameters "
564  "MV = " << TypeNameTraits<MV>::name () << ", "
565  "OP = " << TypeNameTraits<OP>::name () << ", "
566  "NormType = " << TypeNameTraits<NormType>::name () << ". "
567  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
568  << (haveRunTimeReg ? "ON" : "OFF") << ".");
569 
570  RCP<solver_type> solver = factory->getLinearSolver (solverName);
572  (solver.is_null (), std::invalid_argument, prefix << "Invalid solver name "
573  "\"" << solverName << "\". However, package \"" << packageName << "\" is "
574  "valid, and it did register a LinearSolverFactory for template parameters "
575  "MV = " << TypeNameTraits<MV>::name () << ", "
576  "OP = " << TypeNameTraits<OP>::name () << ", "
577  "NormType = " << TypeNameTraits<NormType>::name () << ". "
578  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
579  << (haveRunTimeReg ? "ON" : "OFF") << ".");
580 
581  return solver;
582 }
583 
584 } // namespace Details
585 } // namespace Trilinos
586 
587 #endif // TRILINOS_DETAILS_LINEARSOLVER_FACTORY_HPP
static factory_pointer_type getFactory(const std::string &packageName)
Get a LinearSolverFactory from the given package.
Teuchos::RCP< LinearSolverFactory< MV, OP, NormType > > factory_pointer_type
Type of a reference-counted pointer to LinearSolverFactory.
bool rememberRegisteredSomeLinearSolverFactory(const std::string &packageName)
Remember which packages registered at least one LinearSolverFactory, with any template parameters...
static void registerLinearSolverFactory(const std::string &packageName, const factory_pointer_type &factory)
Register the given factory from a package.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
T * get() const
Get the raw C++ pointer to the underlying object.
bool registeredSomeLinearSolverFactory(const std::string &packageName)
Did the package with the given name register at least one LinearSolverFactory, with any template para...
virtual Teuchos::RCP< LinearSolver< MV, OP, NormType > > getLinearSolver(const std::string &solverName)=0
Get an instance of a solver from a particular package.
bool haveLinearSolverFactoryRunTimeRegistration()
Whether the CMake run-time registration option is ON.
std::map< std::string, factory_pointer_type > map_type
Type of a data structure that looks up a LinearSolverFactory corresponding to a given package name...
Interface for a &quot;factory&quot; that creates solvers.
Default traits class that just returns typeid(T).name().
Smart reference counting pointer class for automatic garbage collection.
Reference-counted pointer class and non-member templated function implementations.