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 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) 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 #ifndef TRILINOS_DETAILS_LINEARSOLVER_FACTORY_HPP
43 #define TRILINOS_DETAILS_LINEARSOLVER_FACTORY_HPP
44 
81 
82 #include "Teuchos_RCP.hpp" // includes Teuchos_ConfigDefs.hpp
83 #include "TeuchosRemainder_config.h"
84 #include <map>
85 #ifdef HAVE_TEUCHOSCORE_CXX11
86 # include <memory> // std::shared_ptr
87 #endif // HAVE_TEUCHOSCORE_CXX11
88 #include <stdexcept>
89 #include <sstream>
90 #include <string>
91 
92 
93 // Attempted fix for Bug 6392: declare all packages'
94 // LinearSolverFactory registration functions here, with weak linkage.
95 // This works whether or not the packages in question are actually
96 // enabled. In createPackageNames() below, actually call these
97 // functions if they are linked in. We only need to do this if
98 // building with static libraries; if building with dynamic libraries,
99 // each package takes care of this on its own.
100 //
101 // I wrote "attempted" because it DOESN'T WORK. It doesn't matter
102 // whether these or their uses are in the .cpp or .hpp file, or
103 // whether they are in a regular function that gets compiled or a
104 // templated function that might not.
105 #if ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
106 // FIXME (mfh 21 Aug 2015) NONE of the commented-out things work.
107 
108 // namespace Amesos2 {
109 // namespace Details {
110 // extern void __attribute__((weak)) registerLinearSolverFactory ();
111 // } // namespace Details
112 // } // namespace Amesos2
113 
114 // namespace Ifpack2 {
115 // namespace Details {
116 // // extern void __attribute__((weak)) registerLinearSolverFactory ();
117 // // void __attribute__((weak)) registerLinearSolverFactory ();
118 // // evoid __attribute__((weak)) registerLinearSolverFactory ();
119 // } // namespace Details
120 // } // namespace Ifpack2
121 #endif // ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
122 
123 
126 namespace Trilinos {
127 
134 namespace Details {
135 
136 template<class MV, class OP, class NormType>
137 class LinearSolver; // forward declaration
138 
165 template<class MV, class OP, class NormType>
167 getLinearSolver (const std::string& packageName, const std::string& solverName);
168 
234 template<class MV, class OP, class NormType>
236 public:
237  virtual ~LinearSolverFactory() {}
246  getLinearSolver (const std::string& solverName) = 0;
247 };
248 
326 template<class MV, class OP, class NormType>
327 void
328 registerLinearSolverFactory (const std::string& packageName,
329 #ifdef HAVE_TEUCHOSCORE_CXX11
330  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory);
331 #else
333 #endif // HAVE_TEUCHOSCORE_CXX11
334 
335 //
336 // EVERYTHING BELOW THIS LINE IS AN IMPLEMENTATION DETAIL
337 //
338 
344 namespace Impl {
345 
356 bool rememberRegisteredSomeLinearSolverFactory (const std::string& packageName);
357 
363 bool registeredSomeLinearSolverFactory (const std::string& packageName);
364 
372 
399 template<class MV, class OP, class NormType>
401 public:
407 #ifdef HAVE_TEUCHOSCORE_CXX11
408  typedef std::shared_ptr<LinearSolverFactory<MV, OP, NormType> > factory_pointer_type;
409 #else
411 #endif // HAVE_TEUCHOSCORE_CXX11
412 
420  typedef std::map<std::string, factory_pointer_type> map_type;
421 
422 public:
435  static factory_pointer_type
436  getFactory (const std::string& packageName)
437  {
438  createFactories ();
439  typedef typename map_type::iterator iter_type;
440  iter_type it = factories_->find (packageName);
441  if (it == factories_->end ()) { // didn't find package name
442  return factory_pointer_type (); // null pointer
443  } else { // found package name
444  return it->second;
445  }
446  }
447 
462  static void
463  registerLinearSolverFactory (const std::string& packageName,
464  const factory_pointer_type& factory)
465  {
467  (factory.get () == NULL, std::invalid_argument, "Trilinos::Details::"
468  "LinearSolverFactoryRepository::registerLinearSolverFactory: Input "
469  "'factory' is NULL!");
470  createFactories ();
471  if (factories_->find (packageName) == factories_->end ()) {
472  factories_->insert (std::make_pair (packageName, factory));
473  }
474  }
475 
476 private:
487  static map_type* factories_;
488 
492  static void createFactories () {
493  if (factories_ == NULL) {
494  factories_ = new map_type ();
495  // It _is_ possible for atexit() to fail (e.g., because it ran
496  // out of memory for storing callbacks). We could throw an
497  // exception here in that case, but I think it's better just
498  // to let the minor memory leak happen.
499  (void) atexit (freeFactories);
500  }
502  (factories_ == NULL, std::logic_error, "Trilinos::Details::"
503  "LinearSolverFactoryRepository::createFactories: "
504  "Should never get here! factories_ is NULL.");
505  }
506 
515  static void freeFactories () {
516  if (factories_ != NULL) {
517  delete factories_;
518  factories_ = NULL;
519  }
520  }
521 };
522 
523 // This is _not_ an explicit instantiation. C++ wants it, because
524 // LinearSolverFactoryRepository is a templated class with a static
525 // (class) member.
526 template<class MV, class OP, class NormType>
527 typename LinearSolverFactoryRepository<MV, OP, NormType>::map_type*
528 LinearSolverFactoryRepository<MV, OP, NormType>::factories_ = NULL;
529 
530 } // namespace Impl
531 
532 //
533 // Definitions of nonmember functions
534 //
535 
536 template<class MV, class OP, class NormType>
537 void
538 registerLinearSolverFactory (const std::string& packageName,
539 #ifdef HAVE_TEUCHOSCORE_CXX11
540  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory)
541 #else
543 #endif // HAVE_TEUCHOSCORE_CXX11
544 {
547 }
548 
549 template<class MV, class OP, class NormType>
551 getLinearSolver (const std::string& packageName, const std::string& solverName)
552 {
553  using Teuchos::RCP;
555  typedef Impl::LinearSolverFactoryRepository<MV, OP, NormType> repo_type;
556  typedef typename repo_type::factory_pointer_type factory_pointer_type;
557  typedef LinearSolver<MV, OP, NormType> solver_type;
558  const char prefix[] = "Trilinos::Details::getLinearSolver: ";
559 
560  // FIXME (mfh 21 Aug 2015) Attempted fix for Bug 6392: DOES NOT WORK.
561  // (Compiles just fine, but test doesn't pass.)
562 #if ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
563  // if (Amesos2::Details::registerLinearSolverFactory == NULL) {
564  // std::cout << "-- Amesos2::Details::registerLinearSolverFactory is NULL" << std::endl;
565  // } else {
566  // Amesos2::Details::registerLinearSolverFactory ();
567  // }
568  // if (Ifpack2::Details::registerLinearSolverFactory == NULL) {
569  // std::cout << "-- Ifpack2::Details::registerLinearSolverFactory is NULL" << std::endl;
570  // } else {
571  // Ifpack2::Details::registerLinearSolverFactory ();
572  // }
573 #endif // ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
574 
575  // Whether the CMake run-time registration option is ON. This
576  // doesn't actually say whether run-time registration has happened
577  // for the current combination of (MV, OP, NormType) template
578  // parameters.
579  const bool haveRunTimeReg =
581 
582  const bool pkgExists = Impl::registeredSomeLinearSolverFactory (packageName);
584  (! pkgExists, std::invalid_argument, prefix << "Package \"" << packageName
585  << "\" never registered a LinearSolverFactory for _any_ combination of "
586  "template parameters MV, OP, and NormType. This means either that the "
587  "package name is invalid, or that the package is not enabled. "
588  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
589  << (haveRunTimeReg ? "ON" : "OFF") << ".");
590 
591  factory_pointer_type factory = repo_type::getFactory (packageName);
593  (factory.get () == NULL, std::invalid_argument, prefix << "Package \"" <<
594  packageName << "\" is valid, but it never registered a LinearSolverFactory"
595  " for template parameters "
596  "MV = " << TypeNameTraits<MV>::name () << ", "
597  "OP = " << TypeNameTraits<OP>::name () << ", "
598  "NormType = " << TypeNameTraits<NormType>::name () << ". "
599  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
600  << (haveRunTimeReg ? "ON" : "OFF") << ".");
601 
602  RCP<solver_type> solver = factory->getLinearSolver (solverName);
604  (solver.is_null (), std::invalid_argument, prefix << "Invalid solver name "
605  "\"" << solverName << "\". However, package \"" << packageName << "\" is "
606  "valid, and it did register a LinearSolverFactory for template parameters "
607  "MV = " << TypeNameTraits<MV>::name () << ", "
608  "OP = " << TypeNameTraits<OP>::name () << ", "
609  "NormType = " << TypeNameTraits<NormType>::name () << ". "
610  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
611  << (haveRunTimeReg ? "ON" : "OFF") << ".");
612 
613  return solver;
614 }
615 
616 } // namespace Details
617 } // namespace Trilinos
618 
619 #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.