Stratimikos Version of the Day
Loading...
Searching...
No Matches
Thyra_BelosTpetraPreconditionerFactory_def.hpp
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
13#include "Thyra_BelosTpetraPreconditionerFactory_decl.hpp"
14
15#include "Thyra_DefaultPreconditioner.hpp"
16#include "Thyra_TpetraLinearOp.hpp"
17#include "Thyra_TpetraThyraWrappers.hpp"
18
19#include "BelosTpetraOperator.hpp"
20#include "BelosConfigDefs.hpp"
22#include "BelosTpetraAdapter.hpp"
23
24#include "Tpetra_MixedScalarMultiplyOp.hpp"
25
26#include "Teuchos_TestForException.hpp"
27#include "Teuchos_Assert.hpp"
28#include "Teuchos_Time.hpp"
29#include "Teuchos_FancyOStream.hpp"
30#include "Teuchos_VerbosityLevel.hpp"
31#include "Teuchos_VerboseObjectParameterListHelpers.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
45namespace Thyra {
46
47// Constructors/initializers/accessors
48
49
50template <typename MatrixType>
53
54
55// Overridden from PreconditionerFactoryBase
56
57
58template <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();
68 using TpetraExtractHelper = TpetraOperatorVectorExtraction<scalar_type, local_ordinal_type, global_ordinal_type, node_type>;
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
77template <typename MatrixType>
78Teuchos::RCP<PreconditionerBase<typename BelosTpetraPreconditionerFactory<MatrixType>::scalar_type> >
80{
81 return Teuchos::rcp(new DefaultPreconditioner<scalar_type>);
82}
83
84
85template <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
97 TEUCHOS_ASSERT(Teuchos::nonnull(fwdOpSrc));
98 TEUCHOS_ASSERT(this->isCompatible(*fwdOpSrc));
99 TEUCHOS_ASSERT(prec);
100
101 Teuchos::Time totalTimer("Stratimikos::BelosTpetraPreconditionerFactory");
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);
107 if (Teuchos::nonnull(out) && Teuchos::includesVerbLevel(verbLevel, Teuchos::VERB_MEDIUM)) {
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();
114 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(fwdOp));
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;
121 using TpetraExtractHelper = TpetraOperatorVectorExtraction<scalar_type, local_ordinal_type, global_ordinal_type, node_type>;
122 const auto tpetraFwdOp = TpetraExtractHelper::getConstTpetraOperator(fwdOp);
123 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(tpetraFwdOp));
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;
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;
139#endif
140
141 // Retrieve concrete preconditioner object
142
143 const Teuchos::Ptr<DefaultPreconditioner<scalar_type> > defaultPrec =
144 Teuchos::ptr(dynamic_cast<DefaultPreconditioner<scalar_type> *>(prec));
145 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(defaultPrec));
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
168 if (Teuchos::nonnull(out) && Teuchos::includesVerbLevel(verbLevel, Teuchos::VERB_MEDIUM)) {
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
175 if (Teuchos::nonnull(out) && Teuchos::includesVerbLevel(verbLevel, Teuchos::VERB_LOW)) {
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();
201 if (Teuchos::nonnull(out) && Teuchos::includesVerbLevel(verbLevel, Teuchos::VERB_LOW)) {
202 *out << "\nTotal time in Thyra::BelosTpetraPreconditionerFactory::initializePrec(...) = " << totalTimer.totalElapsedTime() << " sec\n";
203 }
204
205 if (Teuchos::nonnull(out) && Teuchos::includesVerbLevel(verbLevel, Teuchos::VERB_MEDIUM)) {
206 *out << "\nLeaving Thyra::BelosTpetraPreconditionerFactory::initializePrec(...) ...\n";
207 }
208}
209
210
211template <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
224 const Teuchos::Ptr<DefaultPreconditioner<scalar_type> > defaultPrec =
225 Teuchos::ptr(dynamic_cast<DefaultPreconditioner<scalar_type> *>(prec));
226 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(defaultPrec));
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
245template <typename MatrixType>
247 Teuchos::RCP<Teuchos::ParameterList> const& paramList
248 )
249{
250 TEUCHOS_TEST_FOR_EXCEPT(Teuchos::is_null(paramList));
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
261template <typename MatrixType>
262Teuchos::RCP<Teuchos::ParameterList>
267
268
269template <typename MatrixType>
270Teuchos::RCP<Teuchos::ParameterList>
272{
273 const Teuchos::RCP<Teuchos::ParameterList> savedParamList = paramList_;
274 paramList_ = Teuchos::null;
275 return savedParamList;
276}
277
278
279template <typename MatrixType>
280Teuchos::RCP<const Teuchos::ParameterList>
285
286template <typename MatrixType>
287Teuchos::RCP<const Teuchos::ParameterList>
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
315template <typename MatrixType>
317{
318 return "Thyra::BelosTpetraPreconditionerFactory";
319}
320
321
322} // namespace Thyra
323
324#endif // THYRA_BELOS_TPETRA_PRECONDITIONERFACTORY_DEF_HPP
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &paramList)
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
bool isCompatible(const LinearOpSourceBase< scalar_type > &fwdOp) const
void uninitializePrec(PreconditionerBase< scalar_type > *prec, Teuchos::RCP< const LinearOpSourceBase< scalar_type > > *fwdOp, ESupportSolveUse *supportSolveUse) const
void initializePrec(const Teuchos::RCP< const LinearOpSourceBase< scalar_type > > &fwdOp, PreconditionerBase< scalar_type > *prec, const ESupportSolveUse supportSolveUse) const
Teuchos::RCP< PreconditionerBase< scalar_type > > createPrec() const

Generated for Stratimikos by doxygen 1.9.8