Teko Version of the Day
Loading...
Searching...
No Matches
Teko_StratimikosFactory.cpp
1// @HEADER
2// *****************************************************************************
3// Teko: A package for block and physics based preconditioning
4//
5// Copyright 2010 NTESS and the Teko contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#include "Teko_StratimikosFactory.hpp"
11
12#include "Teko_TpetraInverseFactoryOperator.hpp"
13#include "Teuchos_Time.hpp"
14#include "Teuchos_AbstractFactoryStd.hpp"
15
16#include "Thyra_DefaultPreconditioner.hpp"
17
18#include "Teko_InverseLibrary.hpp"
19#include "Teko_Preconditioner.hpp"
20#include "Teko_Utilities.hpp"
21#include "Teko_InverseLibrary.hpp"
22#include "Teko_ReorderedLinearOp.hpp"
23
24#include "Teko_ConfigDefs.hpp"
25#include "Teko_TpetraOperatorWrapper.hpp"
26#include "Teko_BlockedTpetraOperator.hpp"
27#include "Thyra_TpetraLinearOp.hpp"
28
29namespace Teko {
30
31using Teuchos::ParameterList;
32using Teuchos::RCP;
33
34// hide stuff
35namespace {
36// Simple preconditioner class that adds a counter
37class StratimikosFactoryPreconditioner : public Thyra::DefaultPreconditioner<double> {
38 public:
39 StratimikosFactoryPreconditioner() : iter_(0) {}
40
41 inline void incrIter() { iter_++; }
42 inline std::size_t getIter() { return iter_; }
43
44 private:
45 StratimikosFactoryPreconditioner(const StratimikosFactoryPreconditioner &);
46
47 std::size_t iter_;
48};
49
50// factory used to initialize the Teko::StratimikosFactory
51// user data
52class TekoFactoryBuilder
53 : public Teuchos::AbstractFactory<Thyra::PreconditionerFactoryBase<double> > {
54 public:
55 TekoFactoryBuilder(const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> &builder,
56 const Teuchos::RCP<Teko::RequestHandler> &rh)
57 : builder_(builder), requestHandler_(rh) {}
58 Teuchos::RCP<Thyra::PreconditionerFactoryBase<double> > create() const {
59 return Teuchos::rcp(new StratimikosFactory(builder_, requestHandler_));
60 }
61
62 private:
63 Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> builder_;
64 Teuchos::RCP<Teko::RequestHandler> requestHandler_;
65};
66} // namespace
67
68// Constructors/initializers/accessors
70
71// Constructors/initializers/accessors
72StratimikosFactory::StratimikosFactory(const Teuchos::RCP<Teko::RequestHandler> &rh) {
74}
75
77 const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> &builder,
78 const Teuchos::RCP<Teko::RequestHandler> &rh)
79 : builder_(builder) {
81}
82
83// Overridden from PreconditionerFactoryBase
85 const Thyra::LinearOpSourceBase<double> & /* fwdOpSrc */) const {
86 // Always return true - compatibility is determined in initializePrec
87 return true;
88}
89
90bool StratimikosFactory::applySupportsConj(Thyra::EConj /* conj */) const { return false; }
91
92bool StratimikosFactory::applyTransposeSupportsConj(Thyra::EConj /* conj */) const {
93 return false; // See comment below
94}
95
96Teuchos::RCP<Thyra::PreconditionerBase<double> > StratimikosFactory::createPrec() const {
97 return Teuchos::rcp(new StratimikosFactoryPreconditioner());
98}
99
101 const Teuchos::RCP<const Thyra::LinearOpSourceBase<double> > &fwdOpSrc,
102 Thyra::PreconditionerBase<double> *prec, const Thyra::ESupportSolveUse supportSolveUse) const {
103 Teuchos::RCP<const LinearOpBase<double> > fwdOp = fwdOpSrc->getOp();
104
105 // Always use Tpetra path (Thyra path that supports Tpetra)
106 initializePrec_Thyra(fwdOpSrc, prec, supportSolveUse);
107}
108
110 const Teuchos::RCP<const Thyra::LinearOpSourceBase<double> > &fwdOpSrc,
111 Thyra::PreconditionerBase<double> *prec,
112 const Thyra::ESupportSolveUse /* supportSolveUse */) const {
113 using Teuchos::implicit_cast;
114 using Teuchos::RCP;
115 using Teuchos::rcp;
116 using Teuchos::rcp_dynamic_cast;
117 using Thyra::LinearOpBase;
118
119 Teuchos::Time totalTimer(""), timer("");
120 totalTimer.start(true);
121
122 const RCP<Teuchos::FancyOStream> out = this->getOStream();
123 const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
124
125 bool mediumVerbosity =
126 (out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW));
127
128 Teuchos::OSTab tab(out);
129 if (mediumVerbosity)
130 *out << "\nEntering Teko::StratimikosFactory::initializePrec_Thyra(...) ...\n";
131
132 Teuchos::RCP<const LinearOpBase<double> > fwdOp = fwdOpSrc->getOp();
133
134 // Get the concrete preconditioner object
135 StratimikosFactoryPreconditioner &defaultPrec =
136 Teuchos::dyn_cast<StratimikosFactoryPreconditioner>(*prec);
137 Teuchos::RCP<LinearOpBase<double> > prec_Op = defaultPrec.getNonconstUnspecifiedPrecOp();
138
139 // Perform initialization if needed
140 const bool startingOver = (prec_Op == Teuchos::null);
141 if (startingOver) {
142 invLib_ = Teuchos::null;
143 invFactory_ = Teuchos::null;
144
145 if (mediumVerbosity) *out << "\nCreating the initial Teko Operator object...\n";
146
147 timer.start(true);
148
149 // build library, and set request handler (user defined!)
150 invLib_ = Teko::InverseLibrary::buildFromParameterList(
151 paramList_->sublist("Inverse Factory Library"), builder_);
152 invLib_->setRequestHandler(reqHandler_);
153
154 // build preconditioner factory
155 invFactory_ = invLib_->getInverseFactory(paramList_->get<std::string>("Inverse Type"));
156
157 timer.stop();
158 if (mediumVerbosity)
159 Teuchos::OSTab(out).o() << "> Creation time = " << timer.totalElapsedTime() << " sec\n";
160 }
161
162 if (mediumVerbosity) *out << "\nComputing the preconditioner ...\n";
163
164 // Parse XML-driven strided blocking decomposition
165 decomp_.clear();
166 {
167 std::stringstream ss;
168 ss << paramList_->get<std::string>("Strided Blocking", "1");
169
170 while (!ss.eof()) {
171 int num = 0;
172 ss >> num;
173 if (!ss.fail()) {
174 TEUCHOS_ASSERT(num > 0);
175 decomp_.push_back(num);
176 }
177 }
178
179 if (decomp_.empty()) decomp_.push_back(1);
180 }
181
182 std::string reorderType = paramList_->get<std::string>("Reorder Type");
183
184 // No blocking requested: preserve original Thyra path
185 if (decomp_.size() == 1) {
186 if (reorderType != "") {
187 Teuchos::RCP<const Thyra::BlockedLinearOpBase<double> > blkFwdOp =
188 Teuchos::rcp_dynamic_cast<const Thyra::BlockedLinearOpBase<double> >(fwdOp, true);
189
190 RCP<const Teko::BlockReorderManager> brm = Teko::blockedReorderFromString(reorderType);
191 Teko::LinearOp blockedFwdOp = Teko::buildReorderedLinearOp(*brm, blkFwdOp);
192
193 if (prec_Op == Teuchos::null) {
194 Teko::ModifiableLinearOp reorderedPrec = Teko::buildInverse(*invFactory_, blockedFwdOp);
195 prec_Op = Teuchos::rcp(new ReorderedLinearOp(brm, reorderedPrec));
196 } else {
197 Teko::ModifiableLinearOp reorderedPrec =
198 Teuchos::rcp_dynamic_cast<ReorderedLinearOp>(prec_Op, true)->getBlockedOp();
199 Teko::rebuildInverse(*invFactory_, blockedFwdOp, reorderedPrec);
200 }
201 } else {
202 if (prec_Op == Teuchos::null)
203 prec_Op = Teko::buildInverse(*invFactory_, fwdOp);
204 else
205 Teko::rebuildInverse(*invFactory_, fwdOp, prec_Op);
206 }
207 } else {
208 // Multi-block case: XML-driven Tpetra wrapper path
209 timer.start(true);
210
211 // Extract underlying Tpetra operator from the incoming Thyra operator
212 RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT> > tpetraThyraOp =
213 rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST, LO, GO, NT> >(fwdOp, true);
214 RCP<const Tpetra::Operator<ST, LO, GO, NT> > tpetraOp = tpetraThyraOp->getConstTpetraOperator();
215
216 // Build explicit GID vectors for block decomposition
217 std::vector<std::vector<GO> > vars;
218 {
219 const auto rangeMap = tpetraOp->getRangeMap();
220
221 int numVars = 0;
222 for (std::size_t i = 0; i < decomp_.size(); i++) numVars += decomp_[i];
223
224 TEUCHOS_ASSERT((rangeMap->getLocalNumElements() % numVars) == 0);
225 TEUCHOS_ASSERT((rangeMap->getGlobalNumElements() % numVars) == 0);
226
227 vars.resize(decomp_.size());
228
229 const LO numMyElts = rangeMap->getLocalNumElements();
230 LO i = 0;
231 while (i < numMyElts) {
232 for (std::size_t d = 0; d < decomp_.size(); d++) {
233 const int current = decomp_[d];
234 for (int v = 0; v < current; v++, i++) {
235 vars[d].push_back(rangeMap->getGlobalElement(i));
236 }
237 }
238 }
239 }
240
241 // Build blocked Tpetra wrapper
242 Teuchos::RCP<Teko::TpetraHelpers::BlockedTpetraOperator> wrappedFwdOp =
243 Teuchos::rcp(new Teko::TpetraHelpers::BlockedTpetraOperator(vars, tpetraOp));
244
245 // Optional reordering
246 if (reorderType != "") {
247 RCP<const Teko::BlockReorderManager> brm = Teko::blockedReorderFromString(reorderType);
248 wrappedFwdOp->Reorder(*brm);
249 }
250
251 // Build inverse through Tpetra wrapper path so external spaces remain monolithic
252 Teuchos::RCP<Teko::TpetraHelpers::InverseFactoryOperator> teko_precOp =
253 Teuchos::rcp(new Teko::TpetraHelpers::InverseFactoryOperator(invFactory_));
254 teko_precOp->initInverse(true);
255 teko_precOp->buildInverseOperator(
256 Teuchos::rcp_dynamic_cast<Tpetra::Operator<ST, LO, GO, NT> >(wrappedFwdOp));
257
258 prec_Op = Thyra::tpetraLinearOp<double, LO, GO, NT>(
259 Thyra::tpetraVectorSpace<double, LO, GO, NT>(teko_precOp->getRangeMap()),
260 Thyra::tpetraVectorSpace<double, LO, GO, NT>(teko_precOp->getDomainMap()),
261 Teuchos::rcp_dynamic_cast<Tpetra::Operator<ST, LO, GO, NT> >(teko_precOp));
262
263 timer.stop();
264 if (mediumVerbosity)
265 Teuchos::OSTab(out).o() << "> Blocked Tpetra construction time = " << timer.totalElapsedTime()
266 << " sec\n";
267 }
268
269 if (mediumVerbosity) *out << "\nFinished computing the preconditioner ...\n";
270
271 defaultPrec.initializeUnspecified(prec_Op);
272 defaultPrec.incrIter();
273 totalTimer.stop();
274
275 if (out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
276 *out << "\nTotal time in Teko::StratimikosFactory = " << totalTimer.totalElapsedTime()
277 << " sec\n";
278 if (mediumVerbosity)
279 *out << "\nLeaving Teko::StratimikosFactory::initializePrec_Thyra(...) ...\n";
280}
281
283 Thyra::PreconditionerBase<double> * /* prec */,
284 Teuchos::RCP<const Thyra::LinearOpSourceBase<double> > * /* fwdOp */,
285 Thyra::ESupportSolveUse * /* supportSolveUse */
286) const {
287 TEUCHOS_TEST_FOR_EXCEPT(true);
288}
289
290// Overridden from ParameterListAcceptor
291
292void StratimikosFactory::setParameterList(Teuchos::RCP<Teuchos::ParameterList> const &paramList) {
293 TEUCHOS_TEST_FOR_EXCEPT(paramList.get() == NULL);
294
295 paramList->validateParametersAndSetDefaults(*this->getValidParameters(), 0);
296 paramList_ = paramList;
297}
298
299Teuchos::RCP<Teuchos::ParameterList> StratimikosFactory::getNonconstParameterList() {
300 return paramList_;
301}
302
303Teuchos::RCP<Teuchos::ParameterList> StratimikosFactory::unsetParameterList() {
304 Teuchos::RCP<ParameterList> _paramList = paramList_;
305 paramList_ = Teuchos::null;
306 return _paramList;
307}
308
309Teuchos::RCP<const Teuchos::ParameterList> StratimikosFactory::getParameterList() const {
310 return paramList_;
311}
312
313Teuchos::RCP<const Teuchos::ParameterList> StratimikosFactory::getValidParameters() const {
314 using Teuchos::implicit_cast;
315 using Teuchos::rcp;
316 using Teuchos::rcp_implicit_cast;
317 using Teuchos::tuple;
318
319 static RCP<const ParameterList> validPL;
320
321 if (is_null(validPL)) {
322 Teuchos::RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList());
323
324 pl->set("Test Block Operator", false,
325 "If Stratiikos/Teko is used to break an operator into its parts,\n"
326 "then setting this parameter to true will compare applications of the\n"
327 "segregated operator to the original operator.");
328 pl->set("Write Block Operator", false,
329 "Write out the segregated operator to disk with the name \"block-?_xx\"");
330 pl->set("Strided Blocking", "1",
331 "Assuming that the user wants Strided blocking, break the operator into\n"
332 "blocks. The syntax can be thought to be associated with the solution\n"
333 "vector. For example if your variables are [u v w p T], and we want [u v w]\n"
334 "blocked together, and p and T separate then the relevant string is \"3 1 1\".\n"
335 "Meaning put the first 3 unknowns per node together and separate the v and w\n"
336 "components.");
337 pl->set("Reorder Type", "",
338 "This specifies how the blocks are reordered for use in the preconditioner.\n"
339 "For example, assume the linear system is generated from 3D Navier-Stokes\n"
340 "with an energy equation, yielding the unknowns [u v w p T]. If the\n"
341 "\"Strided Blocking\" string is \"3 1 1\", then setting this parameter to\n"
342 "\"[2 [0 1]]\" will reorder the blocked operator so its nested with the\n"
343 "velocity and pressure forming an inner two-by-two block, and then the\n"
344 "temperature unknowns forming a two-by-two system with the velocity-pressure\n"
345 "block.");
346 std::string defaultInverseType = "";
347#if defined(Teko_ENABLE_Amesos)
348 defaultInverseType = "Amesos";
349#elif defined(Teko_ENABLE_Amesos2)
350 defaultInverseType = "Amesos2";
351#endif
352 pl->set("Inverse Type", defaultInverseType,
353 "The type of inverse operator the user wants. This can be one of the defaults\n"
354 "from Stratimikos, or a Teko preconditioner defined in the\n"
355 "\"Inverse Factory Library\".");
356 pl->sublist("Inverse Factory Library", false, "Definition of Teko preconditioners.");
357
358 validPL = pl;
359 }
360
361 return validPL;
362}
363
365 std::ostringstream oss;
366 oss << "Teko::StratimikosFactory";
367 return oss.str();
368}
369
370void addTekoToStratimikosBuilder(Stratimikos::DefaultLinearSolverBuilder &builder,
371 const std::string &stratName) {
372 TEUCHOS_TEST_FOR_EXCEPTION(
373 builder.getValidParameters()->sublist("Preconditioner Types").isParameter(stratName),
374 std::logic_error,
375 "Teko::addTekoToStratimikosBuilder cannot add \"" + stratName +
376 "\" because it is already included in builder!");
377
378 Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> builderCopy =
379 Teuchos::rcp(new Stratimikos::DefaultLinearSolverBuilder(builder));
380
381 // use default constructor to add Teko::StratimikosFactory
382 Teuchos::RCP<TekoFactoryBuilder> tekoFactoryBuilder =
383 Teuchos::rcp(new TekoFactoryBuilder(builderCopy, Teuchos::null));
384 builder.setPreconditioningStrategyFactory(tekoFactoryBuilder, stratName);
385}
386
387void addTekoToStratimikosBuilder(Stratimikos::DefaultLinearSolverBuilder &builder,
388 const Teuchos::RCP<Teko::RequestHandler> &rh,
389 const std::string &stratName) {
390 TEUCHOS_TEST_FOR_EXCEPTION(
391 builder.getValidParameters()->sublist("Preconditioner Types").isParameter(stratName),
392 std::logic_error,
393 "Teko::addTekoToStratimikosBuilder cannot add \"" + stratName +
394 "\" because it is already included in builder!");
395
396 Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> builderCopy =
397 Teuchos::rcp(new Stratimikos::DefaultLinearSolverBuilder(builder));
398
399 // build an instance of a Teuchos::AbsractFactory<Thyra::PFB> so request handler is passed onto
400 // the resulting StratimikosFactory
401 Teuchos::RCP<TekoFactoryBuilder> tekoFactoryBuilder =
402 Teuchos::rcp(new TekoFactoryBuilder(builderCopy, rh));
403 builder.setPreconditioningStrategyFactory(tekoFactoryBuilder, stratName);
404}
405
406} // namespace Teko
Teuchos::RCP< const BlockReorderManager > blockedReorderFromString(std::string &reorder)
Convert a string to a block reorder manager object.
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A)
Build an inverse operator using a factory and a linear operator.
void rebuildInverse(const InverseFactory &factory, const LinearOp &A, InverseLinearOp &invA)
This class takes a blocked linear op and represents it in a flattened form.
void initializePrec(const Teuchos::RCP< const Thyra::LinearOpSourceBase< double > > &fwdOp, Thyra::PreconditionerBase< double > *prec, const Thyra::ESupportSolveUse supportSolveUse) const
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
Teuchos::RCP< Thyra::PreconditionerBase< double > > createPrec() const
bool isCompatible(const Thyra::LinearOpSourceBase< double > &fwdOp) const
bool applyTransposeSupportsConj(Thyra::EConj conj) const
bool applySupportsConj(Thyra::EConj conj) const
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)
void uninitializePrec(Thyra::PreconditionerBase< double > *prec, Teuchos::RCP< const Thyra::LinearOpSourceBase< double > > *fwdOp, Thyra::ESupportSolveUse *supportSolveUse) const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
void setRequestHandler(const Teuchos::RCP< Teko::RequestHandler > &rh)
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList()
void initializePrec_Thyra(const Teuchos::RCP< const Thyra::LinearOpSourceBase< double > > &fwdOp, Thyra::PreconditionerBase< double > *prec, const Thyra::ESupportSolveUse supportSolveUse) const
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Tear about a user specified Tpetra::Operator<ST,LO,GO,NT> (CrsMatrix) using a vector of vectors of GI...
A single Tpetra wrapper for all operators constructed from an inverse operator.