Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_InverseLibrary.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_InverseLibrary.hpp"
11 
12 #include "Teko_SolveInverseFactory.hpp"
13 #include "Teko_PreconditionerInverseFactory.hpp"
14 #include "Teko_BlockPreconditionerFactory.hpp"
15 
16 #include "Teko_NeumannSeriesPreconditionerFactory.hpp"
17 #include "Teuchos_AbstractFactoryStd.hpp"
18 #include "Teko_Utilities.hpp"
19 
20 #include <algorithm>
21 
22 using Teuchos::RCP;
23 using Teuchos::rcp;
24 
25 namespace Teko {
26 
30 void addToStratimikosBuilder(const RCP<Stratimikos::DefaultLinearSolverBuilder>& builder) {
31  typedef Thyra::PreconditionerFactoryBase<double> PrecFactory;
32 
33  RCP<const Teuchos::ParameterList> parameters = builder->getValidParameters();
34 
35  if (!parameters->sublist("Preconditioner Types").isSublist("Neumann Series")) {
36  RCP<const Teuchos::AbstractFactory<Thyra::PreconditionerFactoryBase<double> > > factory;
37 
38  factory = Teuchos::abstractFactoryStd<PrecFactory,
39  Teko::NeumannSeriesPreconditionerFactory<double> >();
40  builder->setPreconditioningStrategyFactory(factory, "Neumann Series");
41  }
42 }
43 
44 InverseLibrary::InverseLibrary() {
45  Teko_DEBUG_SCOPE("InverseLibrary::InverseLibrary", 10);
46 
47  defaultBuilder_ = Teuchos::rcp(new Stratimikos::DefaultLinearSolverBuilder());
48  addToStratimikosBuilder(defaultBuilder_);
49 
50  // setup some valid Stratimikos parameters
52 
53  // set valid solve factory names
54  stratValidSolver_.push_back("Belos");
55  stratValidSolver_.push_back("Amesos");
56  stratValidSolver_.push_back("Amesos2");
57  stratValidSolver_.push_back("AztecOO");
58 
59  // set valid preconditioner factory name
60  stratValidPrecond_.push_back("ML");
61  stratValidPrecond_.push_back("Ifpack");
62  stratValidPrecond_.push_back("Neumann Series");
63  stratValidPrecond_.push_back("MueLu");
64  stratValidPrecond_.push_back("Ifpack2");
65 
66  // set valid Teko preconditioner factory names
68 
69  Teko_DEBUG_MSG_BEGIN(10) DEBUG_STREAM << "Loaded \"block\" preconditioners = ";
70  for (std::size_t i = 0; i < blockValidPrecond_.size(); i++)
71  DEBUG_STREAM << blockValidPrecond_[i] << ", ";
72  DEBUG_STREAM << std::endl;
73  Teko_DEBUG_MSG_END()
74 }
75 
76 InverseLibrary::InverseLibrary(const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder>& strat)
77  : defaultBuilder_(strat) {
78  Teko_DEBUG_SCOPE("InverseLibrary::InverseLibrary", 10);
79 
80  RCP<Teuchos::ParameterList> pl =
81  rcp(new Teuchos::ParameterList(*defaultBuilder_->getValidParameters()));
82  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
83  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
84 
85  Teuchos::ParameterList::ConstIterator itr;
86 
87  // set valid solve factory names
88  for (itr = lst.begin(); itr != lst.end(); ++itr) stratValidSolver_.push_back(itr->first);
89 
90  Teko_DEBUG_MSG_BEGIN(10) DEBUG_STREAM << "Loaded \"Stratimikos\" solvers = ";
91  for (std::size_t i = 0; i < stratValidSolver_.size(); i++)
92  DEBUG_STREAM << stratValidSolver_[i] << ", ";
93  DEBUG_STREAM << std::endl;
94  Teko_DEBUG_MSG_END()
95 
96  // set valid prec factory names
97  for (itr = pft.begin(); itr != pft.end(); ++itr) stratValidPrecond_.push_back(itr->first);
98 
99  Teko_DEBUG_MSG_BEGIN(10) DEBUG_STREAM << "Loaded \"Stratimikos\" preconditioners = ";
100  for (std::size_t i = 0; i < stratValidPrecond_.size(); i++)
101  DEBUG_STREAM << stratValidPrecond_[i] << ", ";
102  DEBUG_STREAM << std::endl;
103  Teko_DEBUG_MSG_END()
104 
105  // set valid Teko preconditioner factory names
106  PreconditionerFactory::getPreconditionerFactoryNames(blockValidPrecond_);
107 
108  Teko_DEBUG_MSG_BEGIN(10) DEBUG_STREAM << "Loaded \"block\" preconditioners = ";
109  for (std::size_t i = 0; i < blockValidPrecond_.size(); i++)
110  DEBUG_STREAM << blockValidPrecond_[i] << ", ";
111  DEBUG_STREAM << std::endl;
112  Teko_DEBUG_MSG_END()
113 }
114 
116 void InverseLibrary::addInverse(const std::string& label, const Teuchos::ParameterList& pl) {
117  // strip out the label
118  const std::string type = pl.get<std::string>("Type");
119 
120  // copy the parameter list so we can modify it
121  Teuchos::ParameterList settingsList;
122  settingsList.set(type, pl);
123  settingsList.sublist(type).remove("Type");
124 
125  // is this a Stratimikos preconditioner or solver
126  if (std::find(stratValidPrecond_.begin(), stratValidPrecond_.end(), type) !=
127  stratValidPrecond_.end()) {
128  // this is a Stratimikos preconditioner factory
129  addStratPrecond(label, type, settingsList);
130  } else if (std::find(stratValidSolver_.begin(), stratValidSolver_.end(), type) !=
131  stratValidSolver_.end()) {
132  // this is a Stratimikos preconditioner factory
133  addStratSolver(label, type, settingsList);
134  } else if (std::find(blockValidPrecond_.begin(), blockValidPrecond_.end(), type) !=
135  blockValidPrecond_.end()) {
136  // this is a Teko preconditioner factory
137  addBlockPrecond(label, type, settingsList);
138  } else {
139  Teuchos::FancyOStream& os = *Teko::getOutputStream();
140  os << "ERROR: Could not find inverse type \"" << type << "\" required by inverse name \""
141  << label << "\"" << std::endl;
142  TEUCHOS_ASSERT(false);
143  }
144 }
145 
147 void InverseLibrary::addStratSolver(const std::string& label, const std::string& type,
148  const Teuchos::ParameterList& pl) {
149  // add some additional parameters onto the list
150  RCP<Teuchos::ParameterList> stratList = rcp(new Teuchos::ParameterList());
151  stratList->set("Linear Solver Type", type);
152  stratList->set("Linear Solver Types", pl);
153  stratList->set("Preconditioner Type", "None");
154 
155  stratSolver_[label] = stratList;
156 }
157 
159 void InverseLibrary::addStratPrecond(const std::string& label, const std::string& type,
160  const Teuchos::ParameterList& pl) {
161  // add some additional parameters onto the list
162  RCP<Teuchos::ParameterList> stratList = rcp(new Teuchos::ParameterList());
163  stratList->set("Preconditioner Type", type);
164  stratList->set("Preconditioner Types", pl);
165 
166  stratPrecond_[label] = stratList;
167 }
168 
170 void InverseLibrary::addBlockPrecond(const std::string& label, const std::string& type,
171  const Teuchos::ParameterList& pl) {
172  // add some additional parameters onto the list
173  RCP<Teuchos::ParameterList> blockList = rcp(new Teuchos::ParameterList());
174  blockList->set("Preconditioner Type", type);
175  blockList->set("Preconditioner Settings", pl.sublist(type));
176 
177  // add the Teko preconditioner parameter list into the library
178  blockPrecond_[label] = blockList;
179 }
180 
188 Teuchos::RCP<const Teuchos::ParameterList> InverseLibrary::getParameterList(
189  const std::string& label) const {
190  std::map<std::string, RCP<const Teuchos::ParameterList> >::const_iterator itr;
191 
192  // check preconditioners
193  itr = stratPrecond_.find(label);
194  if (itr != stratPrecond_.end()) return itr->second;
195 
196  // check solvers
197  itr = stratSolver_.find(label);
198  if (itr != stratSolver_.end()) return itr->second;
199 
200  // check solvers
201  itr = blockPrecond_.find(label);
202  if (itr != blockPrecond_.end()) return itr->second;
203 
204  return Teuchos::null;
205 }
206 
208 Teuchos::RCP<InverseFactory> InverseLibrary::getInverseFactory(const std::string& label) const {
209  Teko_DEBUG_SCOPE("InverseLibrary::getInverseFactory", 10);
210 
211  std::map<std::string, RCP<const Teuchos::ParameterList> >::const_iterator itr;
212 
213  bool isStratSolver = false, isStratPrecond = false, isBlockPrecond = false;
214 
215  // is this a Stratimikos solver?
216  itr = stratPrecond_.find(label);
217  isStratPrecond = itr != stratPrecond_.end();
218 
219  // is this a Stratimikos preconditioner?
220  if (not isStratPrecond) {
221  itr = stratSolver_.find(label);
222  isStratSolver = itr != stratSolver_.end();
223  }
224 
225  // must be a "block" preconditioner
226  if (not(isStratSolver || isStratPrecond)) {
227  itr = blockPrecond_.find(label);
228  isBlockPrecond = itr != blockPrecond_.end();
229  }
230 
231  Teko_DEBUG_MSG("Inverse \"" << label << "\" is of type "
232  << "strat prec = " << isStratPrecond << ", "
233  << "strat solv = " << isStratSolver << ", "
234  << "block prec = " << isBlockPrecond,
235  3);
236 
237  // Must be one of Strat solver, strat preconditioner, block preconditioner
238  if (not(isStratSolver || isStratPrecond || isBlockPrecond)) {
239  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
240 
241  *out << "InverseLibrary::getInverseFactory could not find \"" << label << "\" ... aborting\n";
242  *out << "Choose one of: " << std::endl;
243 
244  *out << " Stratimikos preconditioners = ";
245  for (itr = stratPrecond_.begin(); itr != stratPrecond_.end(); ++itr)
246  *out << " \"" << itr->first << "\"\n";
247  *out << std::endl;
248 
249  *out << " Stratimikos solvers = ";
250  for (itr = stratSolver_.begin(); itr != stratSolver_.end(); ++itr)
251  *out << " \"" << itr->first << "\"\n";
252  *out << std::endl;
253 
254  *out << " Block preconditioners = ";
255  for (itr = blockPrecond_.begin(); itr != blockPrecond_.end(); ++itr)
256  *out << " \"" << itr->first << "\"\n";
257  *out << std::endl;
258 
259  TEUCHOS_ASSERT(isStratSolver || isStratPrecond || isBlockPrecond);
260  }
261 
262  RCP<const Teuchos::ParameterList> pl = itr->second;
263 
264  // build inverse factory
265  if (isStratPrecond) {
266  // remove required parameters
267  RCP<Teuchos::ParameterList> plCopy = rcp(new Teuchos::ParameterList(*pl));
268  std::string type = plCopy->get<std::string>("Preconditioner Type");
269  RCP<Teuchos::ParameterList> xtraParams;
270  if (plCopy->sublist("Preconditioner Types").sublist(type).isParameter("Required Parameters")) {
271  xtraParams = rcp(new Teuchos::ParameterList(
272  plCopy->sublist("Preconditioner Types").sublist(type).sublist("Required Parameters")));
273  plCopy->sublist("Preconditioner Types").sublist(type).remove("Required Parameters");
274  }
275 
276  // print some debuggin info
277  Teko_DEBUG_MSG_BEGIN(10);
278  DEBUG_STREAM << "Printing parameter list: " << std::endl;
279  Teko_DEBUG_PUSHTAB();
280  plCopy->print(DEBUG_STREAM);
281  Teko_DEBUG_POPTAB();
282 
283  if (xtraParams != Teuchos::null) {
284  DEBUG_STREAM << "Printing extra parameters: " << std::endl;
285  Teko_DEBUG_PUSHTAB();
286  xtraParams->print(DEBUG_STREAM);
287  Teko_DEBUG_POPTAB();
288  }
289  Teko_DEBUG_MSG_END();
290 
291  // Stratimikos::DefaultLinearSolverBuilder strat;
292  // addToStratimikosBuilder(strat);
293  defaultBuilder_->setParameterList(plCopy);
294 
295  // try to build a preconditioner factory
296  RCP<Thyra::PreconditionerFactoryBase<double> > precFact =
297  defaultBuilder_->createPreconditioningStrategy(type);
298 
299  // string must map to a preconditioner
300  RCP<Teko::PreconditionerInverseFactory> precInvFact =
301  rcp(new PreconditionerInverseFactory(precFact, xtraParams, getRequestHandler()));
302  precInvFact->setupParameterListFromRequestHandler();
303  return precInvFact;
304  } else if (isStratSolver) {
305  RCP<Teuchos::ParameterList> solveList = rcp(new Teuchos::ParameterList(*pl));
306  std::string type = solveList->get<std::string>("Linear Solver Type");
307 
308  // get preconditioner name, remove "Use Preconditioner" parameter
309  Teuchos::ParameterList& solveSettings = solveList->sublist("Linear Solver Types").sublist(type);
310  std::string precKeyWord = "Use Preconditioner";
311  std::string precName = "None";
312  if (solveSettings.isParameter(precKeyWord)) {
313  precName = solveSettings.get<std::string>(precKeyWord);
314  solveSettings.remove(precKeyWord);
315  }
316 
317  // build Thyra preconditioner factory
318  RCP<Thyra::PreconditionerFactoryBase<double> > precFactory;
319  if (precName != "None") {
320  // we will manually set the preconditioner, so set this to null
321  solveList->set<std::string>("Preconditioner Type", "None");
322 
323  // build inverse that preconditioner corresponds to
324  RCP<PreconditionerInverseFactory> precInvFactory =
325  Teuchos::rcp_dynamic_cast<PreconditionerInverseFactory>(getInverseFactory(precName));
326 
327  // extract preconditioner factory from preconditioner _inverse_ factory
328  precFactory = precInvFactory->getPrecFactory();
329  }
330 
331  // Stratimikos::DefaultLinearSolverBuilder strat;
332  // addToStratimikosBuilder(strat);
333  defaultBuilder_->setParameterList(solveList);
334 
335  // try to build a solver factory
336  RCP<Thyra::LinearOpWithSolveFactoryBase<double> > solveFact =
337  defaultBuilder_->createLinearSolveStrategy(type);
338  if (precFactory != Teuchos::null) solveFact->setPreconditionerFactory(precFactory, precName);
339 
340  // if its around, build a InverseFactory
341  return rcp(new SolveInverseFactory(solveFact));
342  } else if (isBlockPrecond) {
343  try {
344  std::string type = pl->get<std::string>("Preconditioner Type");
345  const Teuchos::ParameterList& settings = pl->sublist("Preconditioner Settings");
346 
347  // build preconditioner factory from the string
348  RCP<PreconditionerFactory> precFact = PreconditionerFactory::buildPreconditionerFactory(
349  type, settings, Teuchos::rcpFromRef(*this));
350 
351  TEUCHOS_ASSERT(precFact != Teuchos::null);
352 
353  // return the inverse factory object
354  return rcp(new PreconditionerInverseFactory(precFact, getRequestHandler()));
355  } catch (std::exception& e) {
356  RCP<Teuchos::FancyOStream> out = Teko::getOutputStream();
357 
358  *out << "Teko: \"getInverseFactory\" failed, Parameter List =\n";
359  pl->print(*out);
360 
361  *out << "*** THROWN EXCEPTION ***\n";
362  *out << e.what() << std::endl;
363  *out << "************************\n";
364 
365  throw e;
366  }
367  }
368 
369  TEUCHOS_ASSERT(false);
370 }
371 
373 void InverseLibrary::PrintAvailableInverses(std::ostream& os) const {
374  std::map<std::string, Teuchos::RCP<const Teuchos::ParameterList> >::const_iterator itr;
375 
376  os << "Stratimikos Solvers: " << std::endl;
377  os << "********************************" << std::endl;
378  for (itr = stratSolver_.begin(); itr != stratSolver_.end(); ++itr) {
379  os << "name = \"" << itr->first << "\"" << std::endl;
380  itr->second->print(os);
381  os << std::endl;
382  }
383 
384  os << "Stratimikos Preconditioners: " << std::endl;
385  os << "********************************" << std::endl;
386  for (itr = stratPrecond_.begin(); itr != stratPrecond_.end(); ++itr) {
387  os << "name = \"" << itr->first << "\"" << std::endl;
388  itr->second->print(os);
389  os << std::endl;
390  }
391 
392  os << "Teko Preconditioners: " << std::endl;
393  os << "********************************" << std::endl;
394  for (itr = blockPrecond_.begin(); itr != blockPrecond_.end(); ++itr) {
395  os << "name = \"" << itr->first << "\"" << std::endl;
396  itr->second->print(os);
397  os << std::endl;
398  }
399 }
400 
410 RCP<InverseLibrary> InverseLibrary::buildFromParameterList(const Teuchos::ParameterList& pl,
411  bool useStratDefaults) {
412  // build from Stratimikos or allocate a new inverse library
413  RCP<InverseLibrary> invLib;
414  if (useStratDefaults)
415  invLib = InverseLibrary::buildFromStratimikos();
416  else
417  invLib = rcp(new InverseLibrary());
418 
419  // to convert the void* like entry
420  Teuchos::ParameterList* temp = 0;
421 
422  // loop over all entries in parameter list
423  Teuchos::ParameterList::ConstIterator itr;
424  for (itr = pl.begin(); itr != pl.end(); ++itr) {
425  // get current entry
426  std::string label = itr->first;
427  Teuchos::ParameterList& list = itr->second.getValue(temp);
428 
429  // add to library
430  invLib->addInverse(label, list);
431  }
432 
433  return invLib;
434 }
435 
446 RCP<InverseLibrary> InverseLibrary::buildFromParameterList(
447  const Teuchos::ParameterList& pl,
448  const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder>& strat) {
449  // if strat is set to null, use the defaults
450  if (strat == Teuchos::null) return buildFromParameterList(pl, true);
451 
452  // build from Stratimikos or allocate a new inverse library
453  RCP<InverseLibrary> invLib = InverseLibrary::buildFromStratimikos(strat);
454 
455  // to convert the void* like entry
456  Teuchos::ParameterList* temp = 0;
457 
458  // loop over all entries in parameter list
459  Teuchos::ParameterList::ConstIterator itr;
460  for (itr = pl.begin(); itr != pl.end(); ++itr) {
461  // get current entry
462  std::string label = itr->first;
463  Teuchos::ParameterList& list = itr->second.getValue(temp);
464 
465  // add to library
466  invLib->addInverse(label, list);
467  }
468 
469  return invLib;
470 }
471 
480 Teuchos::RCP<InverseLibrary> InverseLibrary::buildFromStratimikos() {
481  RCP<InverseLibrary> invLib = rcp(new InverseLibrary());
482 
483  // get default inveres in Stratimikos
484  RCP<Stratimikos::DefaultLinearSolverBuilder> strat = invLib->defaultBuilder_;
485  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*strat->getValidParameters()));
486  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
487  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
488 
489  Teuchos::ParameterList::ConstIterator itr;
490  Teuchos::ParameterList* temp = 0;
491 
492  // loop over all entries in solver list
493  for (itr = lst.begin(); itr != lst.end(); ++itr) {
494  // get current entry
495  std::string label = itr->first;
496  Teuchos::ParameterList& list = itr->second.getValue(temp);
497  list.set("Type", label);
498 
499  // add to library
500  invLib->addInverse(label, list);
501  }
502 
503  // loop over all entries in preconditioner list
504  for (itr = pft.begin(); itr != pft.end(); ++itr) {
505  // get current entry
506  std::string label = itr->first;
507  Teuchos::ParameterList& list = itr->second.getValue(temp);
508  list.set("Type", label);
509 
510  // add to library
511  invLib->addInverse(label, list);
512  }
513 
514  return invLib;
515 }
516 
526 Teuchos::RCP<InverseLibrary> InverseLibrary::buildFromStratimikos(
527  const Stratimikos::DefaultLinearSolverBuilder& strat) {
528  RCP<InverseLibrary> invLib = rcp(new InverseLibrary());
529 
530  // get default inveres in Stratimikos
531  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*strat.getValidParameters()));
532  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
533  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
534 
535  Teuchos::ParameterList::ConstIterator itr;
536  Teuchos::ParameterList* temp = 0;
537 
538  // loop over all entries in solver list
539  for (itr = lst.begin(); itr != lst.end(); ++itr) {
540  // get current entry
541  std::string label = itr->first;
542  Teuchos::ParameterList& list = itr->second.getValue(temp);
543  list.set("Type", label);
544 
545  // add to library
546  invLib->addInverse(label, list);
547  }
548 
549  // loop over all entries in preconditioner list
550  for (itr = pft.begin(); itr != pft.end(); ++itr) {
551  // get current entry
552  std::string label = itr->first;
553  Teuchos::ParameterList& list = itr->second.getValue(temp);
554  list.set("Type", label);
555 
556  // add to library
557  invLib->addInverse(label, list);
558  }
559 
560  return invLib;
561 }
562 
572 Teuchos::RCP<InverseLibrary> InverseLibrary::buildFromStratimikos(
573  const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder>& strat) {
574  RCP<InverseLibrary> invLib = rcp(new InverseLibrary(strat));
575 
576  // get default inveres in Stratimikos
577  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*strat->getValidParameters()));
578  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
579  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
580 
581  Teuchos::ParameterList::ConstIterator itr;
582  Teuchos::ParameterList* temp = 0;
583 
584  // loop over all entries in solver list
585  for (itr = lst.begin(); itr != lst.end(); ++itr) {
586  // get current entry
587  std::string label = itr->first;
588  Teuchos::ParameterList& list = itr->second.getValue(temp);
589  list.set("Type", label);
590 
591  // add to library
592  invLib->addInverse(label, list);
593  }
594 
595  // loop over all entries in preconditioner list
596  for (itr = pft.begin(); itr != pft.end(); ++itr) {
597  // get current entry
598  std::string label = itr->first;
599  Teuchos::ParameterList& list = itr->second.getValue(temp);
600  list.set("Type", label);
601 
602  // add to library
603  invLib->addInverse(label, list);
604  }
605 
606  return invLib;
607 }
608 
609 } // end namespace Teko
static void getPreconditionerFactoryNames(std::vector< std::string > &names)
Get the names of the block preconditioner factories.
static Teuchos::RCP< PreconditionerFactory > buildPreconditionerFactory(const std::string &name, const Teuchos::ParameterList &settings, const Teuchos::RCP< const InverseLibrary > &invLib=Teuchos::null)
Builder function for creating preconditioner factories (yes this is a factory factory).