Teko  Version of the Day
Teko_InverseLibrary.cpp
1 /*
2 // @HEADER
3 //
4 // ***********************************************************************
5 //
6 // Teko: A package for block and physics based preconditioning
7 // Copyright 2010 Sandia Corporation
8 //
9 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Eric C. Cyr (eccyr@sandia.gov)
40 //
41 // ***********************************************************************
42 //
43 // @HEADER
44 
45 */
46 
47 #include "Teko_InverseLibrary.hpp"
48 
49 #include "Teko_SolveInverseFactory.hpp"
50 #include "Teko_PreconditionerInverseFactory.hpp"
51 #include "Teko_BlockPreconditionerFactory.hpp"
52 
53 #include "Teko_NeumannSeriesPreconditionerFactory.hpp"
54 #include "Teuchos_AbstractFactoryStd.hpp"
55 
56 #include <algorithm>
57 
58 using Teuchos::RCP;
59 using Teuchos::rcp;
60 
61 namespace Teko {
62 
66 void addToStratimikosBuilder(Stratimikos::DefaultLinearSolverBuilder & builder)
67 {
68  typedef Thyra::PreconditionerFactoryBase<double> PrecFactory;
69 
70  RCP<const Teuchos::ParameterList> parameters = builder.getValidParameters();
71 
72  if(!parameters->sublist("Preconditioner Types").isSublist("Neumann Series")) {
73  RCP<const Teuchos::AbstractFactory<Thyra::PreconditionerFactoryBase<double> > > factory;
74 
75  factory = Teuchos::abstractFactoryStd<PrecFactory,Teko::NeumannSeriesPreconditionerFactory<double> >();
76  builder.setPreconditioningStrategyFactory(factory,"Neumann Series");
77  }
78 }
79 
80 InverseLibrary::InverseLibrary()
81 {
82  Teko_DEBUG_SCOPE("InverseLibrary::InverseLibrary", 10);
83 
84  defaultBuilder_ = Teuchos::rcp(new Stratimikos::DefaultLinearSolverBuilder());
85  addToStratimikosBuilder(*defaultBuilder_);
86 
87  // setup some valid Stratimikos parameters
89 
90  // set valid solve factory names
91  stratValidSolver_.push_back("Belos");
92  stratValidSolver_.push_back("Amesos");
93  stratValidSolver_.push_back("AztecOO");
94 
95  // set valid preconditioner factory name
96  stratValidPrecond_.push_back("ML");
97  stratValidPrecond_.push_back("Ifpack");
98  stratValidPrecond_.push_back("Neumann Series");
99 
100  // set valid Teko preconditioner factory names
102 
103  Teko_DEBUG_MSG_BEGIN(10)
104  DEBUG_STREAM << "Loaded \"block\" preconditioners = ";
105  for(std::size_t i=0;i<blockValidPrecond_.size();i++)
106  DEBUG_STREAM << blockValidPrecond_[i] << ", ";
107  DEBUG_STREAM << std::endl;
108  Teko_DEBUG_MSG_END()
109 }
110 
111 InverseLibrary::InverseLibrary(const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> & strat)
112  : defaultBuilder_(strat)
113 {
114  Teko_DEBUG_SCOPE("InverseLibrary::InverseLibrary", 10);
115 
116  addToStratimikosBuilder(*defaultBuilder_);
117 
118  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*defaultBuilder_->getValidParameters()));
119  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
120  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
121 
122  Teuchos::ParameterList::ConstIterator itr;
123 
124  // set valid solve factory names
125  for(itr=lst.begin();itr!=lst.end();++itr)
126  stratValidSolver_.push_back(itr->first);
127 
128  Teko_DEBUG_MSG_BEGIN(10)
129  DEBUG_STREAM << "Loaded \"Stratimikos\" solvers = ";
130  for(std::size_t i=0;i<stratValidSolver_.size();i++)
131  DEBUG_STREAM << stratValidSolver_[i] << ", ";
132  DEBUG_STREAM << std::endl;
133  Teko_DEBUG_MSG_END()
134 
135  // set valid prec factory names
136  for(itr=pft.begin();itr!=pft.end();++itr)
137  stratValidPrecond_.push_back(itr->first);
138 
139  Teko_DEBUG_MSG_BEGIN(10)
140  DEBUG_STREAM << "Loaded \"Stratimikos\" preconditioners = ";
141  for(std::size_t i=0;i<stratValidPrecond_.size();i++)
142  DEBUG_STREAM << stratValidPrecond_[i] << ", ";
143  DEBUG_STREAM << std::endl;
144  Teko_DEBUG_MSG_END()
145 
146  // set valid Teko preconditioner factory names
147  PreconditionerFactory::getPreconditionerFactoryNames(blockValidPrecond_);
148 
149  Teko_DEBUG_MSG_BEGIN(10)
150  DEBUG_STREAM << "Loaded \"block\" preconditioners = ";
151  for(std::size_t i=0;i<blockValidPrecond_.size();i++)
152  DEBUG_STREAM << blockValidPrecond_[i] << ", ";
153  DEBUG_STREAM << std::endl;
154  Teko_DEBUG_MSG_END()
155 }
156 
158 void InverseLibrary::addInverse(const std::string & label,const Teuchos::ParameterList & pl)
159 {
160  // strip out the label
161  const std::string type = pl.get<std::string>("Type");
162 
163  // copy the parameter list so we can modify it
164  Teuchos::ParameterList settingsList;
165  settingsList.set(type,pl);
166  settingsList.sublist(type).remove("Type");
167 
168  // is this a Stratimikos preconditioner or solver
169  if(std::find(stratValidPrecond_.begin(),stratValidPrecond_.end(),type)!=stratValidPrecond_.end()) {
170  // this is a Stratimikos preconditioner factory
171  addStratPrecond(label,type,settingsList);
172  }
173  else if(std::find(stratValidSolver_.begin(),stratValidSolver_.end(),type)!=stratValidSolver_.end()) {
174  // this is a Stratimikos preconditioner factory
175  addStratSolver(label,type,settingsList);
176  }
177  else if(std::find(blockValidPrecond_.begin(),blockValidPrecond_.end(),type)!=blockValidPrecond_.end()) {
178  // this is a Teko preconditioner factory
179  addBlockPrecond(label,type,settingsList);
180  }
181  else {
182  Teuchos::FancyOStream & os = *Teko::getOutputStream();
183  os << "ERROR: Could not find inverse type \"" << type
184  << "\" required by inverse name \"" << label << "\"" << std::endl;
185  TEUCHOS_ASSERT(false);
186  }
187 }
188 
190 void InverseLibrary::addStratSolver(const std::string & label,const std::string & type,const Teuchos::ParameterList & pl)
191 {
192  // add some additional parameters onto the list
193  RCP<Teuchos::ParameterList> stratList = rcp(new Teuchos::ParameterList());
194  stratList->set("Linear Solver Type",type);
195  stratList->set("Linear Solver Types",pl);
196  stratList->set("Preconditioner Type","None");
197 
198  stratSolver_[label] = stratList;
199 }
200 
202 void InverseLibrary::addStratPrecond(const std::string & label,const std::string & type,const Teuchos::ParameterList & pl)
203 {
204  // add some additional parameters onto the list
205  RCP<Teuchos::ParameterList> stratList = rcp(new Teuchos::ParameterList());
206  stratList->set("Preconditioner Type",type);
207  stratList->set("Preconditioner Types",pl);
208 
209  stratPrecond_[label] = stratList;
210 }
211 
213 void InverseLibrary::addBlockPrecond(const std::string & label,const std::string & type,const Teuchos::ParameterList & pl)
214 {
215  // add some additional parameters onto the list
216  RCP<Teuchos::ParameterList> blockList = rcp(new Teuchos::ParameterList());
217  blockList->set("Preconditioner Type",type);
218  blockList->set("Preconditioner Settings",pl.sublist(type));
219 
220  // add the Teko preconditioner parameter list into the library
221  blockPrecond_[label] = blockList;
222 }
223 
231 Teuchos::RCP<const Teuchos::ParameterList> InverseLibrary::getParameterList(const std::string & label) const
232 {
233  std::map<std::string,RCP<const Teuchos::ParameterList> >::const_iterator itr;
234 
235  // check preconditioners
236  itr = stratPrecond_.find(label);
237  if(itr!=stratPrecond_.end()) return itr->second;
238 
239  // check solvers
240  itr = stratSolver_.find(label);
241  if(itr!=stratSolver_.end()) return itr->second;
242 
243  // check solvers
244  itr = blockPrecond_.find(label);
245  if(itr!=blockPrecond_.end()) return itr->second;
246 
247  return Teuchos::null;
248 }
249 
251 Teuchos::RCP<InverseFactory> InverseLibrary::getInverseFactory(const std::string & label) const
252 {
253  Teko_DEBUG_SCOPE("InverseLibrary::getInverseFactory",10);
254 
255  std::map<std::string,RCP<const Teuchos::ParameterList> >::const_iterator itr;
256 
257  bool isStratSolver=false,isStratPrecond=false,isBlockPrecond=false;
258 
259  // is this a Stratimikos solver?
260  itr = stratPrecond_.find(label);
261  isStratPrecond = itr!=stratPrecond_.end();
262 
263  // is this a Stratimikos preconditioner?
264  if(not isStratPrecond) {
265  itr = stratSolver_.find(label);
266  isStratSolver = itr!=stratSolver_.end();
267  }
268 
269  // must be a "block" preconditioner
270  if(not (isStratSolver || isStratPrecond)) {
271  itr = blockPrecond_.find(label);
272  isBlockPrecond = itr!=blockPrecond_.end();
273  }
274 
275  Teko_DEBUG_MSG("Inverse \"" << label << "\" is of type "
276  << "strat prec = " << isStratPrecond << ", "
277  << "strat solv = " << isStratSolver << ", "
278  << "block prec = " << isBlockPrecond,3);
279 
280  // Must be one of Strat solver, strat preconditioner, block preconditioner
281  if(not (isStratSolver || isStratPrecond || isBlockPrecond)) {
282  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
283 
284  *out << "InverseLibrary::getInverseFactory could not find \"" << label << "\" ... aborting\n";
285  *out << "Choose one of: " << std::endl;
286 
287  *out << " Stratimikos preconditioners = ";
288  for(itr=stratPrecond_.begin();itr!=stratPrecond_.end();++itr)
289  *out << " \"" << itr->first << "\"\n";
290  *out << std::endl;
291 
292  *out << " Stratimikos solvers = ";
293  for(itr=stratSolver_.begin();itr!=stratSolver_.end();++itr)
294  *out << " \"" << itr->first << "\"\n";
295  *out << std::endl;
296 
297  *out << " Block preconditioners = ";
298  for(itr=blockPrecond_.begin();itr!=blockPrecond_.end();++itr)
299  *out << " \"" << itr->first << "\"\n";
300  *out << std::endl;
301 
302  TEUCHOS_ASSERT(isStratSolver || isStratPrecond || isBlockPrecond);
303  }
304 
305  RCP<const Teuchos::ParameterList> pl = itr->second;
306 
307  // build inverse factory
308  if(isStratPrecond) {
309  // remove required parameters
310  RCP<Teuchos::ParameterList> plCopy = rcp(new Teuchos::ParameterList(*pl));
311  std::string type = plCopy->get<std::string>("Preconditioner Type");
312  RCP<Teuchos::ParameterList> xtraParams;
313  if(plCopy->sublist("Preconditioner Types").sublist(type).isParameter("Required Parameters")) {
314  xtraParams = rcp(new Teuchos::ParameterList(
315  plCopy->sublist("Preconditioner Types").sublist(type).sublist("Required Parameters")));
316  plCopy->sublist("Preconditioner Types").sublist(type).remove("Required Parameters");
317  }
318 
319  // print some debuggin info
320  Teko_DEBUG_MSG_BEGIN(10);
321  DEBUG_STREAM << "Printing parameter list: " << std::endl;
322  Teko_DEBUG_PUSHTAB(); plCopy->print(DEBUG_STREAM); Teko_DEBUG_POPTAB();
323 
324  if(xtraParams!=Teuchos::null) {
325  DEBUG_STREAM << "Printing extra parameters: " << std::endl;
326  Teko_DEBUG_PUSHTAB(); xtraParams->print(DEBUG_STREAM); Teko_DEBUG_POPTAB();
327  }
328  Teko_DEBUG_MSG_END();
329 
330  // Stratimikos::DefaultLinearSolverBuilder strat;
331  // addToStratimikosBuilder(strat);
332  defaultBuilder_->setParameterList(plCopy);
333 
334  // try to build a preconditioner factory
335  RCP<Thyra::PreconditionerFactoryBase<double> > precFact = defaultBuilder_->createPreconditioningStrategy(type);
336 
337  // string must map to a preconditioner
338  RCP<Teko::PreconditionerInverseFactory> precInvFact
339  = rcp(new PreconditionerInverseFactory(precFact,xtraParams,getRequestHandler()));
340  precInvFact->setupParameterListFromRequestHandler();
341  return precInvFact;
342  }
343  else if(isStratSolver) {
344  RCP<Teuchos::ParameterList> solveList = rcp(new Teuchos::ParameterList(*pl));
345  std::string type = solveList->get<std::string>("Linear Solver Type");
346 
347  // get preconditioner name, remove "Use Preconditioner" parameter
348  Teuchos::ParameterList & solveSettings = solveList->sublist("Linear Solver Types").sublist(type);
349  std::string precKeyWord = "Use Preconditioner";
350  std::string precName = "None";
351  if(solveSettings.isParameter(precKeyWord)) {
352  precName = solveSettings.get<std::string>(precKeyWord);
353  solveSettings.remove(precKeyWord);
354  }
355 
356  // build Thyra preconditioner factory
357  RCP<Thyra::PreconditionerFactoryBase<double> > precFactory;
358  if(precName!="None") {
359  // we will manually set the preconditioner, so set this to null
360  solveList->set<std::string>("Preconditioner Type","None");
361 
362  // build inverse that preconditioner corresponds to
363  RCP<PreconditionerInverseFactory> precInvFactory
364  = Teuchos::rcp_dynamic_cast<PreconditionerInverseFactory>(getInverseFactory(precName));
365 
366  // extract preconditioner factory from preconditioner _inverse_ factory
367  precFactory = precInvFactory->getPrecFactory();
368  }
369 
370  // Stratimikos::DefaultLinearSolverBuilder strat;
371  // addToStratimikosBuilder(strat);
372  defaultBuilder_->setParameterList(solveList);
373 
374  // try to build a solver factory
375  RCP<Thyra::LinearOpWithSolveFactoryBase<double> > solveFact = defaultBuilder_->createLinearSolveStrategy(type);
376  if(precFactory!=Teuchos::null)
377  solveFact->setPreconditionerFactory(precFactory,precName);
378 
379  // if its around, build a InverseFactory
380  return rcp(new SolveInverseFactory(solveFact));
381  }
382  else if(isBlockPrecond) {
383  try {
384  std::string type = pl->get<std::string>("Preconditioner Type");
385  const Teuchos::ParameterList & settings = pl->sublist("Preconditioner Settings");
386 
387  // build preconditioner factory from the string
388  RCP<PreconditionerFactory> precFact
389  = PreconditionerFactory::buildPreconditionerFactory(type,settings,Teuchos::rcpFromRef(*this));
390 
391  TEUCHOS_ASSERT(precFact!=Teuchos::null);
392 
393  // return the inverse factory object
394  return rcp(new PreconditionerInverseFactory(precFact,getRequestHandler()));
395  }
396  catch(std::exception & e) {
397  RCP<Teuchos::FancyOStream> out = Teko::getOutputStream();
398 
399  *out << "Teko: \"getInverseFactory\" failed, Parameter List =\n";
400  pl->print(*out);
401 
402  *out << "*** THROWN EXCEPTION ***\n";
403  *out << e.what() << std::endl;
404  *out << "************************\n";
405 
406  throw e;
407  }
408  }
409 
410  TEUCHOS_ASSERT(false);
411 }
412 
414 void InverseLibrary::PrintAvailableInverses(std::ostream & os) const
415 {
416  std::map<std::string,Teuchos::RCP<const Teuchos::ParameterList> >::const_iterator itr;
417 
418  os << "Stratimikos Solvers: " << std::endl;
419  os << "********************************" << std::endl;
420  for(itr=stratSolver_.begin();itr!=stratSolver_.end();++itr) {
421  os << "name = \"" << itr->first << "\"" << std::endl;
422  itr->second->print(os);
423  os << std::endl;
424  }
425 
426  os << "Stratimikos Preconditioners: " << std::endl;
427  os << "********************************" << std::endl;
428  for(itr=stratPrecond_.begin();itr!=stratPrecond_.end();++itr) {
429  os << "name = \"" << itr->first << "\"" << std::endl;
430  itr->second->print(os);
431  os << std::endl;
432  }
433 
434  os << "Teko Preconditioners: " << std::endl;
435  os << "********************************" << std::endl;
436  for(itr=blockPrecond_.begin();itr!=blockPrecond_.end();++itr) {
437  os << "name = \"" << itr->first << "\"" << std::endl;
438  itr->second->print(os);
439  os << std::endl;
440  }
441 }
442 
452 RCP<InverseLibrary> InverseLibrary::buildFromParameterList(const Teuchos::ParameterList & pl,bool useStratDefaults)
453 {
454  // build from Stratimikos or allocate a new inverse library
455  RCP<InverseLibrary> invLib;
456  if(useStratDefaults)
457  invLib = InverseLibrary::buildFromStratimikos();
458  else
459  invLib = rcp(new InverseLibrary());
460 
461  // to convert the void* like entry
462  Teuchos::ParameterList * temp = 0;
463 
464  // loop over all entries in parameter list
465  Teuchos::ParameterList::ConstIterator itr;
466  for(itr=pl.begin();itr!=pl.end();++itr) {
467  // get current entry
468  std::string label = itr->first;
469  Teuchos::ParameterList & list = itr->second.getValue(temp);
470 
471  // add to library
472  invLib->addInverse(label,list);
473  }
474 
475  return invLib;
476 }
477 
488 RCP<InverseLibrary> InverseLibrary::buildFromParameterList(const Teuchos::ParameterList & pl,
489  const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> & strat)
490 {
491  // if strat is set to null, use the defaults
492  if(strat==Teuchos::null)
493  return buildFromParameterList(pl,true);
494 
495  // build from Stratimikos or allocate a new inverse library
496  RCP<InverseLibrary> invLib = InverseLibrary::buildFromStratimikos(strat);
497 
498  // to convert the void* like entry
499  Teuchos::ParameterList * temp = 0;
500 
501  // loop over all entries in parameter list
502  Teuchos::ParameterList::ConstIterator itr;
503  for(itr=pl.begin();itr!=pl.end();++itr) {
504  // get current entry
505  std::string label = itr->first;
506  Teuchos::ParameterList & list = itr->second.getValue(temp);
507 
508  // add to library
509  invLib->addInverse(label,list);
510  }
511 
512  return invLib;
513 }
514 
524 Teuchos::RCP<InverseLibrary> InverseLibrary::buildFromStratimikos(const Stratimikos::DefaultLinearSolverBuilder & strat)
525 {
526  RCP<InverseLibrary> invLib = rcp(new InverseLibrary());
527 
528  // get default inveres in Stratimikos
529  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*strat.getValidParameters()));
530  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
531  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
532 
533  Teuchos::ParameterList::ConstIterator itr;
534  Teuchos::ParameterList * temp = 0;
535 
536  // loop over all entries in solver list
537  for(itr=lst.begin();itr!=lst.end();++itr) {
538  // get current entry
539  std::string label = itr->first;
540  Teuchos::ParameterList & list = itr->second.getValue(temp);
541  list.set("Type",label);
542 
543  // add to library
544  invLib->addInverse(label,list);
545  }
546 
547  // loop over all entries in preconditioner list
548  for(itr=pft.begin();itr!=pft.end();++itr) {
549  // get current entry
550  std::string label = itr->first;
551  Teuchos::ParameterList & list = itr->second.getValue(temp);
552  list.set("Type",label);
553 
554  // add to library
555  invLib->addInverse(label,list);
556  }
557 
558  return invLib;
559 }
560 
570 Teuchos::RCP<InverseLibrary> InverseLibrary::buildFromStratimikos(const Teuchos::RCP<Stratimikos::DefaultLinearSolverBuilder> & strat)
571 {
572  RCP<InverseLibrary> invLib = rcp(new InverseLibrary(strat));
573 
574  // get default inveres in Stratimikos
575  RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList(*strat->getValidParameters()));
576  Teuchos::ParameterList lst(pl->sublist("Linear Solver Types"));
577  Teuchos::ParameterList pft(pl->sublist("Preconditioner Types"));
578 
579  Teuchos::ParameterList::ConstIterator itr;
580  Teuchos::ParameterList * temp = 0;
581 
582  // loop over all entries in solver list
583  for(itr=lst.begin();itr!=lst.end();++itr) {
584  // get current entry
585  std::string label = itr->first;
586  Teuchos::ParameterList & list = itr->second.getValue(temp);
587  list.set("Type",label);
588 
589  // add to library
590  invLib->addInverse(label,list);
591  }
592 
593  // loop over all entries in preconditioner list
594  for(itr=pft.begin();itr!=pft.end();++itr) {
595  // get current entry
596  std::string label = itr->first;
597  Teuchos::ParameterList & list = itr->second.getValue(temp);
598  list.set("Type",label);
599 
600  // add to library
601  invLib->addInverse(label,list);
602  }
603 
604  return invLib;
605 }
606 
607 } // 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).