Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
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:
245  getLinearSolver (const std::string& solverName) = 0;
246 };
247 
325 template<class MV, class OP, class NormType>
326 void
327 registerLinearSolverFactory (const std::string& packageName,
328 #ifdef HAVE_TEUCHOSCORE_CXX11
329  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory);
330 #else
332 #endif // HAVE_TEUCHOSCORE_CXX11
333 
334 //
335 // EVERYTHING BELOW THIS LINE IS AN IMPLEMENTATION DETAIL
336 //
337 
343 namespace Impl {
344 
355 bool rememberRegisteredSomeLinearSolverFactory (const std::string& packageName);
356 
362 bool registeredSomeLinearSolverFactory (const std::string& packageName);
363 
371 
398 template<class MV, class OP, class NormType>
400 public:
406 #ifdef HAVE_TEUCHOSCORE_CXX11
407  typedef std::shared_ptr<LinearSolverFactory<MV, OP, NormType> > factory_pointer_type;
408 #else
410 #endif // HAVE_TEUCHOSCORE_CXX11
411 
419  typedef std::map<std::string, factory_pointer_type> map_type;
420 
421 public:
434  static factory_pointer_type
435  getFactory (const std::string& packageName)
436  {
437  createFactories ();
438  typedef typename map_type::iterator iter_type;
439  iter_type it = factories_->find (packageName);
440  if (it == factories_->end ()) { // didn't find package name
441  return factory_pointer_type (); // null pointer
442  } else { // found package name
443  return it->second;
444  }
445  }
446 
461  static void
462  registerLinearSolverFactory (const std::string& packageName,
463  const factory_pointer_type& factory)
464  {
466  (factory.get () == NULL, std::invalid_argument, "Trilinos::Details::"
467  "LinearSolverFactoryRepository::registerLinearSolverFactory: Input "
468  "'factory' is NULL!");
469  createFactories ();
470  if (factories_->find (packageName) == factories_->end ()) {
471  factories_->insert (std::make_pair (packageName, factory));
472  }
473  }
474 
475 private:
487 
491  static void createFactories () {
492  if (factories_ == NULL) {
493  factories_ = new map_type ();
494  // It _is_ possible for atexit() to fail (e.g., because it ran
495  // out of memory for storing callbacks). We could throw an
496  // exception here in that case, but I think it's better just
497  // to let the minor memory leak happen.
498  (void) atexit (freeFactories);
499  }
501  (factories_ == NULL, std::logic_error, "Trilinos::Details::"
502  "LinearSolverFactoryRepository::createFactories: "
503  "Should never get here! factories_ is NULL.");
504  }
505 
514  static void freeFactories () {
515  if (factories_ != NULL) {
516  delete factories_;
517  factories_ = NULL;
518  }
519  }
520 };
521 
522 // This is _not_ an explicit instantiation. C++ wants it, because
523 // LinearSolverFactoryRepository is a templated class with a static
524 // (class) member.
525 template<class MV, class OP, class NormType>
528 
529 } // namespace Impl
530 
531 //
532 // Definitions of nonmember functions
533 //
534 
535 template<class MV, class OP, class NormType>
536 void
537 registerLinearSolverFactory (const std::string& packageName,
538 #ifdef HAVE_TEUCHOSCORE_CXX11
539  const std::shared_ptr<LinearSolverFactory<MV, OP, NormType> >& factory)
540 #else
542 #endif // HAVE_TEUCHOSCORE_CXX11
543 {
546 }
547 
548 template<class MV, class OP, class NormType>
550 getLinearSolver (const std::string& packageName, const std::string& solverName)
551 {
552  using Teuchos::RCP;
555  typedef typename repo_type::factory_pointer_type factory_pointer_type;
556  typedef LinearSolver<MV, OP, NormType> solver_type;
557  const char prefix[] = "Trilinos::Details::getLinearSolver: ";
558 
559  // FIXME (mfh 21 Aug 2015) Attempted fix for Bug 6392: DOES NOT WORK.
560  // (Compiles just fine, but test doesn't pass.)
561 #if ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
562  // if (Amesos2::Details::registerLinearSolverFactory == NULL) {
563  // std::cout << "-- Amesos2::Details::registerLinearSolverFactory is NULL" << std::endl;
564  // } else {
565  // Amesos2::Details::registerLinearSolverFactory ();
566  // }
567  // if (Ifpack2::Details::registerLinearSolverFactory == NULL) {
568  // std::cout << "-- Ifpack2::Details::registerLinearSolverFactory is NULL" << std::endl;
569  // } else {
570  // Ifpack2::Details::registerLinearSolverFactory ();
571  // }
572 #endif // ! defined(HAVE_TEUCHOS_DYNAMIC_LIBS) && defined(HAVE_TEUCHOS_CXX_ATTRIBUTE_WEAK)
573 
574  // Whether the CMake run-time registration option is ON. This
575  // doesn't actually say whether run-time registration has happened
576  // for the current combination of (MV, OP, NormType) template
577  // parameters.
578  const bool haveRunTimeReg =
580 
581  const bool pkgExists = Impl::registeredSomeLinearSolverFactory (packageName);
583  (! pkgExists, std::invalid_argument, prefix << "Package \"" << packageName
584  << "\" never registered a LinearSolverFactory for _any_ combination of "
585  "template parameters MV, OP, and NormType. This means either that the "
586  "package name is invalid, or that the package is not enabled. "
587  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
588  << (haveRunTimeReg ? "ON" : "OFF") << ".");
589 
590  factory_pointer_type factory = repo_type::getFactory (packageName);
592  (factory.get () == NULL, std::invalid_argument, prefix << "Package \"" <<
593  packageName << "\" is valid, but it never registered a LinearSolverFactory"
594  " for template parameters "
595  "MV = " << TypeNameTraits<MV>::name () << ", "
596  "OP = " << TypeNameTraits<OP>::name () << ", "
597  "NormType = " << TypeNameTraits<NormType>::name () << ". "
598  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
599  << (haveRunTimeReg ? "ON" : "OFF") << ".");
600 
601  RCP<solver_type> solver = factory->getLinearSolver (solverName);
603  (solver.is_null (), std::invalid_argument, prefix << "Invalid solver name "
604  "\"" << solverName << "\". However, package \"" << packageName << "\" is "
605  "valid, and it did register a LinearSolverFactory for template parameters "
606  "MV = " << TypeNameTraits<MV>::name () << ", "
607  "OP = " << TypeNameTraits<OP>::name () << ", "
608  "NormType = " << TypeNameTraits<NormType>::name () << ". "
609  "Trilinos_ENABLE_LINEAR_SOLVER_FACTORY_REGISTRATION = "
610  << (haveRunTimeReg ? "ON" : "OFF") << ".");
611 
612  return solver;
613 }
614 
615 } // namespace Details
616 } // namespace Trilinos
617 
618 #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.
Interface for a method for solving linear system(s) AX=B.
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.
Namespace of implementation details.
void registerLinearSolverFactory(const std::string &packageName, const Teuchos::RCP< LinearSolverFactory< MV, OP, NormType > > &factory)
Called by a package to register its LinearSolverFactory.
bool registeredSomeLinearSolverFactory(const std::string &packageName)
Did the package with the given name register at least one LinearSolverFactory, with any template para...
static void createFactories()
Initialize factories_ if it hasn&#39;t been initialized.
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.
Namespace of things generally useful to many Trilinos packages.
Teuchos::RCP< LinearSolver< MV, OP, NormType > > getLinearSolver(const std::string &packageName, const std::string &solverName)
Get a LinearSolver instance.
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 "factory" that creates solvers.
static map_type * factories_
Singleton where all packages&#39; factories get stored.
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.