Stratimikos Version of the Day
Loading...
Searching...
No Matches
Thyra_MLPreconditionerFactory.cpp
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#include "Thyra_MLPreconditionerFactory.hpp"
11
12#include "Thyra_EpetraOperatorViewExtractorStd.hpp"
13#include "Thyra_EpetraLinearOp.hpp"
14#include "Thyra_DefaultPreconditioner.hpp"
15#include "ml_MultiLevelPreconditioner.h"
16#include "ml_MultiLevelOperator.h"
17#include "ml_ValidateParameters.h"
18#include "ml_RefMaxwell.h"
19#include "ml_GradDiv.h"
20#include "Epetra_RowMatrix.h"
21#include "Teuchos_StandardParameterEntryValidators.hpp"
22#include "Teuchos_dyn_cast.hpp"
23#include "Teuchos_TimeMonitor.hpp"
24#include "Teuchos_implicit_cast.hpp"
25#include "Teuchos_ValidatorXMLConverterDB.hpp"
26#include "Teuchos_StaticSetupMacro.hpp"
27#include "Teuchos_iostream_helpers.hpp"
28
29
30namespace {
31
32
33enum EMLProblemType {
34 ML_PROBTYPE_NONE,
35 ML_PROBTYPE_SMOOTHED_AGGREGATION,
36 ML_PROBTYPE_NONSYMMETRIC_SMOOTHED_AGGREGATION,
37 ML_PROBTYPE_DOMAIN_DECOMPOSITION,
38 ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML,
39 ML_PROBTYPE_MAXWELL,
40 ML_PROBTYPE_REFMAXWELL,
41 ML_PROBTYPE_GRADDIV
42};
43const std::string BaseMethodDefaults_valueNames_none = "none";
44const Teuchos::Array<std::string> BaseMethodDefaults_valueNames
45= Teuchos::tuple<std::string>(
46 BaseMethodDefaults_valueNames_none,
47 "SA",
48 "NSSA",
49 "DD",
50 "DD-ML",
51 "maxwell",
52 "refmaxwell",
53 "graddiv"
54 );
55
56
57TEUCHOS_ENUM_INPUT_STREAM_OPERATOR(EMLProblemType)
58
59
60TEUCHOS_STATIC_SETUP()
61{
62 TEUCHOS_ADD_STRINGTOINTEGRALVALIDATOR_CONVERTER(EMLProblemType);
63}
64
65const std::string BaseMethodDefaults_name = "Base Method Defaults";
66const std::string BaseMethodDefaults_default = "SA";
67Teuchos::RCP<
68 Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType>
69 >
70BaseMethodDefaults_validator;
71
72const std::string ReuseFineLevelSmoother_name = "Reuse Fine Level Smoother";
73const bool ReuseFineLevelSmoother_default = false;
74
75const std::string MLSettings_name = "ML Settings";
76
77
78} // namespace
79
80
81namespace Thyra {
82
83
84using Teuchos::RCP;
85using Teuchos::ParameterList;
86
87
88// Constructors/initializers/accessors
89
90
92 :epetraFwdOpViewExtractor_(Teuchos::rcp(new EpetraOperatorViewExtractorStd()))
93{}
94
95
96// Overridden from PreconditionerFactoryBase
97
98
100 const LinearOpSourceBase<double> &fwdOpSrc
101 ) const
102{
103 using Teuchos::outArg;
104 Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
105 EOpTransp epetraFwdOpTransp;
106 EApplyEpetraOpAs epetraFwdOpApplyAs;
107 EAdjointEpetraOp epetraFwdOpAdjointSupport;
108 double epetraFwdOpScalar;
109 Teuchos::RCP<const LinearOpBase<double> >
110 fwdOp = fwdOpSrc.getOp();
111 epetraFwdOpViewExtractor_->getEpetraOpView(
112 fwdOp,
113 outArg(epetraFwdOp),outArg(epetraFwdOpTransp),
114 outArg(epetraFwdOpApplyAs),
115 outArg(epetraFwdOpAdjointSupport),
116 outArg(epetraFwdOpScalar)
117 );
118 if( !dynamic_cast<const Epetra_RowMatrix*>(&*epetraFwdOp) )
119 return false;
120 return true;
121}
122
123
125{
126 return true;
127}
128
129
131{
132 return false; // See comment below
133}
134
135
136RCP<PreconditionerBase<double> >
138{
139 return Teuchos::rcp(new DefaultPreconditioner<double>());
140}
141
142
144 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
145 PreconditionerBase<double> *prec,
146 const ESupportSolveUse /* supportSolveUse */
147 ) const
148{
149 using Teuchos::outArg;
150 using Teuchos::OSTab;
151 using Teuchos::dyn_cast;
152 using Teuchos::RCP;
153 using Teuchos::null;
154 using Teuchos::rcp;
155 using Teuchos::rcp_dynamic_cast;
156 using Teuchos::rcp_const_cast;
157 using Teuchos::set_extra_data;
158 using Teuchos::get_optional_extra_data;
159 using Teuchos::implicit_cast;
160 Teuchos::Time totalTimer(""), timer("");
161 totalTimer.start(true);
162 const RCP<Teuchos::FancyOStream> out = this->getOStream();
163 const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
164 Teuchos::OSTab tab(out);
165 if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
166 *out << "\nEntering Thyra::MLPreconditionerFactory::initializePrec(...) ...\n";
167
168 // Get the problem type
169 const EMLProblemType problemType = BaseMethodDefaults_validator->getIntegralValue(*paramList_,BaseMethodDefaults_name,BaseMethodDefaults_default);
170
171 Teuchos::RCP<const LinearOpBase<double> > fwdOp = fwdOpSrc->getOp();
172#ifdef _DEBUG
173 TEUCHOS_TEST_FOR_EXCEPT(fwdOp.get()==NULL);
174 TEUCHOS_TEST_FOR_EXCEPT(prec==NULL);
175#endif
176 //
177 // Unwrap and get the forward Epetra_Operator object
178 //
179 Teuchos::RCP<const Epetra_Operator> epetraFwdOp;
180 EOpTransp epetraFwdOpTransp;
181 EApplyEpetraOpAs epetraFwdOpApplyAs;
182 EAdjointEpetraOp epetraFwdOpAdjointSupport;
183 double epetraFwdOpScalar;
184 epetraFwdOpViewExtractor_->getEpetraOpView(
185 fwdOp,outArg(epetraFwdOp),outArg(epetraFwdOpTransp),outArg(epetraFwdOpApplyAs),
186 outArg(epetraFwdOpAdjointSupport),outArg(epetraFwdOpScalar)
187 );
188 // Validate what we get is what we need
189 RCP<const Epetra_RowMatrix>
190 epetraFwdRowMat = rcp_dynamic_cast<const Epetra_RowMatrix>(epetraFwdOp,true);
191 TEUCHOS_TEST_FOR_EXCEPTION(
192 epetraFwdOpApplyAs != EPETRA_OP_APPLY_APPLY, std::logic_error
193 ,"Error, incorrect apply mode for an Epetra_RowMatrix"
194 );
195 RCP<const Epetra_CrsMatrix> epetraFwdCrsMat = rcp_dynamic_cast<const Epetra_CrsMatrix>(epetraFwdRowMat);
196
197 //
198 // Get the concrete preconditioner object
199 //
200 DefaultPreconditioner<double>
201 *defaultPrec = &Teuchos::dyn_cast<DefaultPreconditioner<double> >(*prec);
202 //
203 // Get the EpetraLinearOp object that is used to implement the preconditoner linear op
204 //
205 RCP<EpetraLinearOp>
206 epetra_precOp = rcp_dynamic_cast<EpetraLinearOp>(defaultPrec->getNonconstUnspecifiedPrecOp(),true);
207 //
208 // Get the embedded ML_Epetra Preconditioner object if it exists
209 //
210 Teuchos::RCP<ML_Epetra::MultiLevelPreconditioner> ml_precOp;
211 Teuchos::RCP<ML_Epetra::RefMaxwellPreconditioner> rm_precOp;
212 Teuchos::RCP<ML_Epetra::GradDivPreconditioner> gd_precOp;
213 if(epetra_precOp.get()) {
214 if(problemType == ML_PROBTYPE_REFMAXWELL)
215 rm_precOp = rcp_dynamic_cast<ML_Epetra::RefMaxwellPreconditioner>(epetra_precOp->epetra_op(),true);
216 else if(problemType == ML_PROBTYPE_GRADDIV)
217 gd_precOp = rcp_dynamic_cast<ML_Epetra::GradDivPreconditioner>(epetra_precOp->epetra_op(),true);
218 else
219 ml_precOp = rcp_dynamic_cast<ML_Epetra::MultiLevelPreconditioner>(epetra_precOp->epetra_op(),true);
220 }
221 //
222 // Get the attached forward operator if it exists and make sure that it matches
223 //
224 if(ml_precOp!=Teuchos::null) {
225 // Get the forward operator and make sure that it matches what is
226 // already being used!
227 const Epetra_RowMatrix & rm = ml_precOp->RowMatrix();
228
229 TEUCHOS_TEST_FOR_EXCEPTION(
230 &rm!=&*epetraFwdRowMat, std::logic_error
231 ,"ML requires Epetra_RowMatrix to be the same for each initialization of the preconditioner"
232 );
233 }
234 // NOTE: No such check exists for RefMaxwell
235
236 //
237 // Perform initialization if needed
238 //
239 const bool startingOver = (ml_precOp.get() == NULL && rm_precOp.get() == NULL);
240 if(startingOver)
241 {
242 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
243 *out << "\nCreating the initial ML_Epetra::MultiLevelPreconditioner object...\n";
244 timer.start(true);
245 // Create the initial preconditioner: DO NOT compute it yet
246
247 if(problemType==ML_PROBTYPE_REFMAXWELL)
248 rm_precOp = rcp(new ML_Epetra::RefMaxwellPreconditioner(*epetraFwdCrsMat, paramList_->sublist(MLSettings_name),false));
249 else if(problemType==ML_PROBTYPE_GRADDIV)
250 gd_precOp = rcp(new ML_Epetra::GradDivPreconditioner(*epetraFwdCrsMat, paramList_->sublist(MLSettings_name),false));
251 else
252 ml_precOp = rcp(new ML_Epetra::MultiLevelPreconditioner(*epetraFwdRowMat, paramList_->sublist(MLSettings_name),false));
253
254
255 timer.stop();
256 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
257 OSTab(out).o() <<"> Creation time = "<<timer.totalElapsedTime()<<" sec\n";
258 // RAB: Above, I am just passing a string to ML::Create(...) in order
259 // get this code written. However, in the future, it would be good to
260 // copy the contents of what is in ML::Create(...) into a local
261 // function and then use switch(...) to create the initial
262 // ML_Epetra::MultiLevelPreconditioner object. This would result in better validation
263 // and faster code.
264 // Set parameters if the list exists
265 if(paramList_.get()) {
266 if (problemType==ML_PROBTYPE_REFMAXWELL) {
267 TEUCHOS_TEST_FOR_EXCEPT(0!=rm_precOp->SetParameterList(paramList_->sublist(MLSettings_name)));
268 }
269 else if (problemType==ML_PROBTYPE_GRADDIV) {
270 TEUCHOS_TEST_FOR_EXCEPT(0!=gd_precOp->SetParameterList(paramList_->sublist(MLSettings_name)));
271 }
272 else {
273 TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->SetParameterList(paramList_->sublist(MLSettings_name)));
274 }
275 }
276 }
277 //
278 // Attach the epetraFwdOp to the ml_precOp to guarantee that it will not go away
279 //
280 if (problemType==ML_PROBTYPE_REFMAXWELL)
281 set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(rm_precOp),
282 Teuchos::POST_DESTROY, false);
283 else if (problemType==ML_PROBTYPE_GRADDIV)
284 set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(gd_precOp),
285 Teuchos::POST_DESTROY, false);
286 else
287 set_extra_data(epetraFwdOp, "IFPF::epetraFwdOp", Teuchos::inOutArg(ml_precOp),
288 Teuchos::POST_DESTROY, false);
289 //
290 // Update the factorization
291 //
292 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
293 *out << "\nComputing the preconditioner ...\n";
294 timer.start(true);
295 if (problemType==ML_PROBTYPE_REFMAXWELL) {
296 if (startingOver) {
297 TEUCHOS_TEST_FOR_EXCEPT(0!=rm_precOp->ComputePreconditioner());
298 }
299 else {
300 TEUCHOS_TEST_FOR_EXCEPT(0!=rm_precOp->ReComputePreconditioner());
301 }
302 }
303 else if (problemType==ML_PROBTYPE_GRADDIV) {
304 if (startingOver) {
305 TEUCHOS_TEST_FOR_EXCEPT(0!=gd_precOp->ComputePreconditioner());
306 }
307 else {
308 TEUCHOS_TEST_FOR_EXCEPT(0!=gd_precOp->ReComputePreconditioner());
309 }
310 }
311 else {
312 if (startingOver) {
313 TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ComputePreconditioner());
314 }
315 else {
316 TEUCHOS_TEST_FOR_EXCEPT(0!=ml_precOp->ReComputePreconditioner(paramList_->get<bool>(ReuseFineLevelSmoother_name)));
317 }
318 }
319 timer.stop();
320 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
321 OSTab(out).o() <<"=> Setup time = "<<timer.totalElapsedTime()<<" sec\n";
322 //
323 // Compute the conditioner number estimate if asked
324 //
325
326 // ToDo: Implement
327
328 //
329 // Attach fwdOp to the ml_precOp
330 //
331 if (problemType==ML_PROBTYPE_REFMAXWELL)
332 set_extra_data(fwdOp, "IFPF::fwdOp", Teuchos::inOutArg(rm_precOp),
333 Teuchos::POST_DESTROY, false);
334 else if (problemType==ML_PROBTYPE_GRADDIV)
335 set_extra_data(fwdOp, "IFPF::fwdOp", Teuchos::inOutArg(gd_precOp),
336 Teuchos::POST_DESTROY, false);
337 else
338 set_extra_data(fwdOp, "IFPF::fwdOp", Teuchos::inOutArg(ml_precOp),
339 Teuchos::POST_DESTROY, false);
340 //
341 // Initialize the output EpetraLinearOp
342 //
343 if(startingOver) {
344 epetra_precOp = rcp(new EpetraLinearOp);
345 }
346 // ToDo: Look into adjoints again.
347 if (problemType==ML_PROBTYPE_REFMAXWELL)
348 epetra_precOp->initialize(rm_precOp,epetraFwdOpTransp,EPETRA_OP_APPLY_APPLY_INVERSE,EPETRA_OP_ADJOINT_UNSUPPORTED);
349 else if (problemType==ML_PROBTYPE_GRADDIV)
350 epetra_precOp->initialize(gd_precOp,epetraFwdOpTransp,EPETRA_OP_APPLY_APPLY_INVERSE,EPETRA_OP_ADJOINT_UNSUPPORTED);
351 else
352 epetra_precOp->initialize(ml_precOp,epetraFwdOpTransp,EPETRA_OP_APPLY_APPLY_INVERSE,EPETRA_OP_ADJOINT_UNSUPPORTED);
353 //
354 // Initialize the preconditioner
355 //
356 defaultPrec->initializeUnspecified(
357 Teuchos::rcp_implicit_cast<LinearOpBase<double> >(epetra_precOp)
358 );
359 totalTimer.stop();
360 if(out.get() && implicit_cast<int>(verbLevel) >= implicit_cast<int>(Teuchos::VERB_LOW))
361 *out << "\nTotal time in MLPreconditionerFactory = "<<totalTimer.totalElapsedTime()<<" sec\n";
362 if(out.get() && implicit_cast<int>(verbLevel) > implicit_cast<int>(Teuchos::VERB_LOW))
363 *out << "\nLeaving Thyra::MLPreconditionerFactory::initializePrec(...) ...\n";
364}
365
366
368 PreconditionerBase<double> * /* prec */,
369 Teuchos::RCP<const LinearOpSourceBase<double> > * /* fwdOp */,
370 ESupportSolveUse * /* supportSolveUse */
371 ) const
372{
373 TEUCHOS_TEST_FOR_EXCEPT(true);
374}
375
376
377// Overridden from ParameterListAcceptor
378
379
381 Teuchos::RCP<ParameterList> const& paramList
382 )
383{
384 TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==NULL);
385
386 // Do not recurse
387 paramList->validateParameters(*this->getValidParameters(),0);
388 paramList_ = paramList;
389
390 // set default for reuse of fine level smoother
391 if(!paramList_->isType<bool>(ReuseFineLevelSmoother_name))
392 paramList_->set<bool>(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default);
393
394 const EMLProblemType
395 defaultType = BaseMethodDefaults_validator->getIntegralValue(
396 *paramList_,BaseMethodDefaults_name,BaseMethodDefaults_default
397 );
398 if( ML_PROBTYPE_NONE != defaultType ) {
399 const std::string defaultTypeStr = BaseMethodDefaults_valueNames[defaultType];
400
401 // ML will do validation on its own. We don't need to duplicate that here.
402 Teuchos::ParameterList defaultParams;
403 if(defaultType == ML_PROBTYPE_REFMAXWELL) {
404 ML_Epetra::SetDefaultsRefMaxwell(defaultParams);
405 }
406 else if(defaultType == ML_PROBTYPE_GRADDIV) {
407 ML_Epetra::SetDefaultsGradDiv(defaultParams);
408 }
409 else {
410 TEUCHOS_TEST_FOR_EXCEPTION(0!=ML_Epetra::SetDefaults(defaultTypeStr,defaultParams)
411 ,Teuchos::Exceptions::InvalidParameterValue
412 ,"Error, the ML problem type \"" << defaultTypeStr << "\' is not recognized by ML!"
413 );
414 }
415
416 // Note, the only way the above exception message could be generated is if
417 // a default problem type was removed from ML_Epetra::SetDefaults(...).
418 // When a new problem type is added to this function, it must be added to
419 // our enum EMLProblemType along with associated objects ... In other
420 // words, this adapter must be maintained as ML is maintained. An
421 // alternative design would be to just pass in whatever string to this
422 // function. This would improve maintainability but it would not generate
423 // very good error messages when a bad string was passed in. Currently,
424 // the error message attached to the exception will contain the list of
425 // valid problem types.
426 paramList_->sublist(MLSettings_name).setParametersNotAlreadySet(
427 defaultParams);
428 }
429
430}
431
432
433RCP<ParameterList>
435{
436 return paramList_;
437}
438
439
440RCP<ParameterList>
442{
443 Teuchos::RCP<ParameterList> _paramList = paramList_;
444 paramList_ = Teuchos::null;
445 return _paramList;
446}
447
448
449RCP<const ParameterList>
451{
452 return paramList_;
453}
454
455
456RCP<const ParameterList>
458{
459 // NOTE: We're only going to use this function to genrate valid *Stratimikos* parameters.
460 // Since ML's parameters can be validated internally, we'll handle those separarely.
461
462
463 using Teuchos::rcp;
464 using Teuchos::tuple;
465 using Teuchos::implicit_cast;
466 using Teuchos::rcp_implicit_cast;
467 typedef Teuchos::ParameterEntryValidator PEV;
468
469 static RCP<const ParameterList> validPL;
470
471 if(is_null(validPL)) {
472
473 RCP<ParameterList>
474 pl = rcp(new ParameterList());
475
476 BaseMethodDefaults_validator = rcp(
477 new Teuchos::StringToIntegralParameterEntryValidator<EMLProblemType>(
478 BaseMethodDefaults_valueNames,
479 tuple<std::string>(
480 "Do not set any default parameters",
481 "Set default parameters for a smoothed aggregation method",
482 "Set default parameters for a nonsymmetric smoothed aggregation method",
483 "Set default parameters for a domain decomposition method",
484 "Set default parameters for a domain decomposition method special to ML",
485 "Set default parameters for a Maxwell-type of preconditioner",
486 "Set default parameters for a RefMaxwell-type preconditioner",
487 "Set default parameters for a Grad-Div-type preconditioner"
488 ),
489 tuple<EMLProblemType>(
490 ML_PROBTYPE_NONE,
491 ML_PROBTYPE_SMOOTHED_AGGREGATION,
492 ML_PROBTYPE_NONSYMMETRIC_SMOOTHED_AGGREGATION,
493 ML_PROBTYPE_DOMAIN_DECOMPOSITION,
494 ML_PROBTYPE_DOMAIN_DECOMPOSITION_ML,
495 ML_PROBTYPE_MAXWELL,
496 ML_PROBTYPE_REFMAXWELL,
497 ML_PROBTYPE_GRADDIV
498 ),
499 BaseMethodDefaults_name
500 )
501 );
502
503 pl->set(BaseMethodDefaults_name,BaseMethodDefaults_default,
504 "Select the default method type which also sets parameter defaults\n"
505 "in the sublist \"" + MLSettings_name + "\"!",
506 rcp_implicit_cast<const PEV>(BaseMethodDefaults_validator)
507 );
508
509 pl->set(ReuseFineLevelSmoother_name,ReuseFineLevelSmoother_default,
510 "Enables/disables the reuse of the fine level smoother.");
511
512 ParameterList mlpl;
513 pl->set(MLSettings_name,mlpl,
514 "Sampling of the parameters directly accepted by ML\n"
515 "This list of parameters is generated by combining all of\n"
516 "the parameters set for all of the default problem types supported\n"
517 "by ML. Therefore, do not assume these parameters are at values that\n"
518 "are reasonable to ML. This list is just to give a sense of some of\n"
519 "the parameters that ML accepts. Consult ML documentation on how to\n"
520 "set these parameters. Also, you can print the parameter list after\n"
521 "it is used and see what defaults where set for each default problem\n"
522 "type. Warning! the parameters in this sublist are currently *not*\n"
523 "being validated by ML!"
524 );
525
526 validPL = pl;
527
528 }
529
530 return validPL;
531
532}
533
534
535// Public functions overridden from Teuchos::Describable
536
537
539{
540 std::ostringstream oss;
541 oss << "Thyra::MLPreconditionerFactory";
542 return oss.str();
543}
544
545
546} // namespace Thyra
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
bool isCompatible(const LinearOpSourceBase< double > &fwdOp) const
void uninitializePrec(PreconditionerBase< double > *prec, Teuchos::RCP< const LinearOpSourceBase< double > > *fwdOp, ESupportSolveUse *supportSolveUse) const
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList()
void initializePrec(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOp, PreconditionerBase< double > *prec, const ESupportSolveUse supportSolveUse) const
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
Teuchos::RCP< PreconditionerBase< double > > createPrec() const
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)

Generated for Stratimikos by doxygen 1.9.8