Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_BelosTpetraPreconditionerFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stratimikos: Thyra-based strategies for linear solvers
4 //
5 // Copyright 2006 NTESS and the Stratimikos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef THYRA_BELOS_TPETRA_PRECONDITIONERFACTORY_DEF_HPP
11 #define THYRA_BELOS_TPETRA_PRECONDITIONERFACTORY_DEF_HPP
12 
14 
15 #include "Thyra_DefaultPreconditioner.hpp"
16 #include "Thyra_TpetraLinearOp.hpp"
18 
19 #include "BelosTpetraOperator.hpp"
20 #include "BelosConfigDefs.hpp"
21 #include "BelosLinearProblem.hpp"
22 #include "BelosTpetraAdapter.hpp"
23 
24 #include "Tpetra_MixedScalarMultiplyOp.hpp"
25 
27 #include "Teuchos_Assert.hpp"
28 #include "Teuchos_Time.hpp"
29 #include "Teuchos_FancyOStream.hpp"
32 
33 #include <string>
34 
35 
36 // CAG: This is not entirely ideal, since it disables half-precision
37 // altogether when we have e.g. double, float and
38 // complex<double>, but not complex<float>, although a
39 // double-float preconditioner would be possible.
40 #if (!defined(HAVE_TPETRA_INST_DOUBLE) || (defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT))) && \
41  (!defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) || (defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT)))
42 # define THYRA_BELOS_PREC_ENABLE_HALF_PRECISION
43 #endif
44 
45 namespace Thyra {
46 
47 // Constructors/initializers/accessors
48 
49 
50 template <typename MatrixType>
52 {}
53 
54 
55 // Overridden from PreconditionerFactoryBase
56 
57 
58 template <typename MatrixType>
60  const LinearOpSourceBase<scalar_type> &fwdOpSrc
61  ) const
62 {
63  typedef typename MatrixType::local_ordinal_type local_ordinal_type;
64  typedef typename MatrixType::global_ordinal_type global_ordinal_type;
65  typedef typename MatrixType::node_type node_type;
66 
67  const Teuchos::RCP<const LinearOpBase<scalar_type> > fwdOp = fwdOpSrc.getOp();
69  const auto tpetraFwdOp = TpetraExtractHelper::getConstTpetraOperator(fwdOp);
70 
71  const Teuchos::RCP<const MatrixType> tpetraFwdMatrix = Teuchos::rcp_dynamic_cast<const MatrixType>(tpetraFwdOp,true);
72 
73  return Teuchos::nonnull(tpetraFwdMatrix);
74 }
75 
76 
77 template <typename MatrixType>
80 {
81  return Teuchos::rcp(new DefaultPreconditioner<scalar_type>);
82 }
83 
84 
85 template <typename MatrixType>
87  const Teuchos::RCP<const LinearOpSourceBase<scalar_type> > &fwdOpSrc,
88  PreconditionerBase<scalar_type> *prec,
89  const ESupportSolveUse /* supportSolveUse */
90  ) const
91 {
92  using Teuchos::rcp;
93  using Teuchos::RCP;
94 
95  // Check precondition
96 
98  TEUCHOS_ASSERT(this->isCompatible(*fwdOpSrc));
99  TEUCHOS_ASSERT(prec);
100 
101  Teuchos::Time totalTimer(""), timer("");
102  totalTimer.start(true);
103 
104  const RCP<Teuchos::FancyOStream> out = this->getOStream();
105  const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
106  Teuchos::OSTab tab(out);
108  *out << "\nEntering Thyra::BelosTpetraPreconditionerFactory::initializePrec(...) ...\n";
109  }
110 
111  // Retrieve wrapped concrete Tpetra matrix from FwdOp
112 
113  const RCP<const LinearOpBase<scalar_type> > fwdOp = fwdOpSrc->getOp();
115 
116  typedef typename MatrixType::local_ordinal_type local_ordinal_type;
117  typedef typename MatrixType::global_ordinal_type global_ordinal_type;
118  typedef typename MatrixType::node_type node_type;
119 
120  typedef Tpetra::Operator<scalar_type, local_ordinal_type, global_ordinal_type, node_type> TpetraLinOp;
122  const auto tpetraFwdOp = TpetraExtractHelper::getConstTpetraOperator(fwdOp);
124 
125  // Belos-specific typedefs:
126  typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type> TpetraMV;
127  typedef Belos::TpetraOperator<scalar_type, local_ordinal_type, global_ordinal_type, node_type> BelosTpOp;
128  typedef Belos::LinearProblem<scalar_type, TpetraMV, TpetraLinOp> BelosTpLinProb;
129 
130 #ifdef THYRA_BELOS_PREC_ENABLE_HALF_PRECISION
131  // CAG: There is nothing special about the combination double-float,
132  // except that I feel somewhat confident that Trilinos builds
133  // with both scalar types.
134  typedef typename Teuchos::ScalarTraits<scalar_type>::halfPrecision half_scalar_type;
135  typedef Tpetra::Operator<half_scalar_type, local_ordinal_type, global_ordinal_type, node_type> TpetraLinOpHalf;
136  typedef Tpetra::MultiVector<half_scalar_type, local_ordinal_type, global_ordinal_type, node_type> TpetraMVHalf;
137  typedef Belos::TpetraOperator<half_scalar_type, local_ordinal_type, global_ordinal_type, node_type> BelosTpOpHalf;
138  typedef Belos::LinearProblem<half_scalar_type, TpetraMVHalf, TpetraLinOpHalf> BelosTpLinProbHalf;
139 #endif
140 
141  // Retrieve concrete preconditioner object
142 
144  Teuchos::ptr(dynamic_cast<DefaultPreconditioner<scalar_type> *>(prec));
146 
147  // This check needed to address Issue #535.
148  RCP<Teuchos::ParameterList> innerParamList;
149  if (paramList_.is_null ()) {
150  innerParamList = rcp(new Teuchos::ParameterList(*getValidParameters()));
151  }
152  else {
153  innerParamList = paramList_;
154  }
155 
156  bool useHalfPrecision = false;
157  if (innerParamList->isParameter("half precision"))
158  useHalfPrecision = Teuchos::getParameter<bool>(*innerParamList, "half precision");
159 
160  const std::string solverType = Teuchos::getParameter<std::string>(*innerParamList, "BelosPrec Solver Type");
161  const RCP<Teuchos::ParameterList> packageParamList = Teuchos::rcpFromRef(innerParamList->sublist("BelosPrec Solver Params"));
162 
163  // solverTypeUpper is the upper-case version of solverType.
164  std::string solverTypeUpper (solverType);
165  std::transform(solverTypeUpper.begin(), solverTypeUpper.end(),solverTypeUpper.begin(), ::toupper);
166 
167  // Create the initial preconditioner
169  *out << "\nCreating a new BelosTpetra::Preconditioner object...\n";
170  }
171  RCP<LinearOpBase<scalar_type> > thyraPrecOp;
172 
173  if (useHalfPrecision) {
174 #ifdef THYRA_BELOS_PREC_ENABLE_HALF_PRECISION
176  Teuchos::OSTab(out).o() << "> Creating half precision preconditioner\n";
177  }
178  const RCP<const MatrixType> tpetraFwdMatrix = Teuchos::rcp_dynamic_cast<const MatrixType>(tpetraFwdOp);
179  TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(tpetraFwdMatrix));
180  auto tpetraFwdMatrixHalf = tpetraFwdMatrix->template convert<half_scalar_type>();
181 
182  RCP<BelosTpLinProbHalf> belosLinProbHalf = rcp(new BelosTpLinProbHalf());
183  belosLinProbHalf->setOperator(tpetraFwdMatrixHalf);
184  RCP<TpetraLinOpHalf> belosOpRCPHalf = rcp(new BelosTpOpHalf(belosLinProbHalf, packageParamList, solverType, true));
185  RCP<TpetraLinOp> wrappedOp = rcp(new Tpetra::MixedScalarMultiplyOp<scalar_type,half_scalar_type,local_ordinal_type,global_ordinal_type,node_type>(belosOpRCPHalf));
186 
187  thyraPrecOp = Thyra::createLinearOp(wrappedOp);
188 #else
189  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Solver does not have correct precisions enabled to use half precision.")
190 #endif
191  } else {
192  // Wrap concrete preconditioner
193  RCP<BelosTpLinProb> belosLinProb = rcp(new BelosTpLinProb());
194  belosLinProb->setOperator(tpetraFwdOp);
195  RCP<TpetraLinOp> belosOpRCP = rcp(new BelosTpOp(belosLinProb, packageParamList, solverType, true));
196  thyraPrecOp = Thyra::createLinearOp(belosOpRCP);
197  }
198  defaultPrec->initializeUnspecified(thyraPrecOp);
199 
200  totalTimer.stop();
202  *out << "\nTotal time in Thyra::BelosTpetraPreconditionerFactory::initializePrec(...) = " << totalTimer.totalElapsedTime() << " sec\n";
203  }
204 
206  *out << "\nLeaving Thyra::BelosTpetraPreconditionerFactory::initializePrec(...) ...\n";
207  }
208 }
209 
210 
211 template <typename MatrixType>
213  PreconditionerBase<scalar_type> *prec,
214  Teuchos::RCP<const LinearOpSourceBase<scalar_type> > *fwdOp,
215  ESupportSolveUse *supportSolveUse
216  ) const
217 {
218  // Check precondition
219 
220  TEUCHOS_ASSERT(prec);
221 
222  // Retrieve concrete preconditioner object
223 
225  Teuchos::ptr(dynamic_cast<DefaultPreconditioner<scalar_type> *>(prec));
227 
228  if (fwdOp) {
229  // TODO: Implement properly instead of returning default value
230  *fwdOp = Teuchos::null;
231  }
232 
233  if (supportSolveUse) {
234  // TODO: Implement properly instead of returning default value
235  *supportSolveUse = Thyra::SUPPORT_SOLVE_UNSPECIFIED;
236  }
237 
238  defaultPrec->uninitialize();
239 }
240 
241 
242 // Overridden from ParameterListAcceptor
243 
244 
245 template <typename MatrixType>
247  Teuchos::RCP<Teuchos::ParameterList> const& paramList
248  )
249 {
251 
252  const auto validParamList = this->getValidParameters();
253  paramList->validateParametersAndSetDefaults(*validParamList, 0);
254  paramList->validateParameters(*validParamList, 0);
255 
256  paramList_ = paramList;
257  Teuchos::readVerboseObjectSublist(paramList_.getRawPtr(), this);
258 }
259 
260 
261 template <typename MatrixType>
264 {
265  return paramList_;
266 }
267 
268 
269 template <typename MatrixType>
272 {
273  const Teuchos::RCP<Teuchos::ParameterList> savedParamList = paramList_;
274  paramList_ = Teuchos::null;
275  return savedParamList;
276 }
277 
278 
279 template <typename MatrixType>
282 {
283  return paramList_;
284 }
285 
286 template <typename MatrixType>
289 {
290  static Teuchos::RCP<Teuchos::ParameterList> validParamList;
291 
292  if (Teuchos::is_null(validParamList)) {
293  validParamList = Teuchos::rcp(new Teuchos::ParameterList("BelosPrecTpetra"));
294  validParamList->set(
295  "BelosPrec Solver Type", "GMRES",
296  "Name of Belos solver to be used as a preconditioner. (Use valid names for Belos::SolverFactory.)"
297  );
298  validParamList->set(
299  "half precision", false,
300  "Whether a half-of-standard-precision Belos-solver-as-preconditioner should be built."
301  );
302  validParamList->sublist(
303  "BelosPrec Solver Params", false,
304  "Belos solver settings that are passed onto the Belos solver itself."
305  );
306  Teuchos::setupVerboseObjectSublist(validParamList.getRawPtr());
307  }
308 
309  return validParamList;
310 }
311 
312 
313 // Public functions overridden from Teuchos::Describable
314 
315 template <typename MatrixType>
317 {
318  return "Thyra::BelosTpetraPreconditionerFactory";
319 }
320 
321 
322 } // namespace Thyra
323 
324 #endif // THYRA_BELOS_TPETRA_PRECONDITIONERFACTORY_DEF_HPP
void uninitializePrec(PreconditionerBase< scalar_type > *prec, Teuchos::RCP< const LinearOpSourceBase< scalar_type > > *fwdOp, ESupportSolveUse *supportSolveUse) const
bool isCompatible(const LinearOpSourceBase< scalar_type > &fwdOp) const
bool nonnull(const std::shared_ptr< T > &p)
bool is_null(const std::shared_ptr< T > &p)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void initializePrec(const Teuchos::RCP< const LinearOpSourceBase< scalar_type > > &fwdOp, PreconditionerBase< scalar_type > *prec, const ESupportSolveUse supportSolveUse) const
RCP< ParameterList > sublist(const RCP< ParameterList > &paramList, const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
basic_OSTab< char > OSTab
RCP< LinearOpBase< Scalar > > createLinearOp(const RCP< Tpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &tpetraOperator, const RCP< const VectorSpaceBase< Scalar > > rangeSpace=Teuchos::null, const RCP< const VectorSpaceBase< Scalar > > domainSpace=Teuchos::null)
bool isParameter(const std::string &name) const
T * getRawPtr() const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &paramList)
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
TEUCHOSCORE_LIB_DLL_EXPORT bool includesVerbLevel(const EVerbosityLevel verbLevel, const EVerbosityLevel requestedVerbLevel, const bool isDefaultLevel=false)
void validateParameters(ParameterList const &validParamList, int const depth=1000, EValidateUsed const validateUsed=VALIDATE_USED_ENABLED, EValidateDefaults const validateDefaults=VALIDATE_DEFAULTS_ENABLED) const
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
Teuchos::RCP< PreconditionerBase< scalar_type > > createPrec() const
#define TEUCHOS_ASSERT(assertion_test)
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)