LifeV
LinearSolver.cpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief LinearSolver
30 
31  @author Gwenol Grandperrin <gwenol.grandperrin@epfl.ch>
32  @maintainer Gwenol Grandperrin <gwenol.grandperrin@epfl.ch>
33 
34  @date 03-08-2011
35  */
36 
37 #include <lifev/core/LifeV.hpp>
38 #include <lifev/core/algorithm/LinearSolver.hpp>
39 #include <lifev/core/algorithm/PreconditionerIfpack.hpp>
40 #include <lifev/core/algorithm/PreconditionerML.hpp>
41 #include <lifev/core/util/WallClock.hpp>
42 
43 namespace LifeV
44 {
45 
46 // ===================================================
47 // Constructors & Destructor
48 // ===================================================
50  M_operator (),
51  M_matrix (),
57  M_parameterList (),
58  M_displayer ( new Displayer() ),
59  M_maxItersForReuse ( 0 ),
60  M_reusePreconditioner ( false ),
61  M_quitOnFailure ( false ),
62  M_silent ( false ),
66  M_tolerance ( -1. )
67 {
68 
69 }
70 
71 LinearSolver::LinearSolver ( const std::shared_ptr<Epetra_Comm> commPtr ) :
72  M_operator (),
73  M_matrix (),
79  M_parameterList (),
80  M_displayer ( new Displayer ( commPtr ) ),
81  M_maxItersForReuse ( 0 ),
82  M_reusePreconditioner ( false ),
83  M_quitOnFailure ( false ),
84  M_silent ( false ),
88  M_tolerance ( -1. )
89 {
90 
91 }
92 
94 {
95 
96 }
97 
98 // ===================================================
99 // Methods
100 // ===================================================
101 Int
103 {
104  // Build preconditioners if needed
105  bool retry ( true );
107  {
109 
110  // There will be no retry if the preconditioner is recomputed
111  retry = false;
112  }
113  else
114  {
115  if ( !M_silent )
116  {
117  M_displayer->leaderPrint ( "SLV- Reusing precond ...\n" );
118  }
119  }
120 
121  if ( M_rhs.get() == 0 || M_operator == nullptr )
122  {
123  M_displayer->leaderPrint ( "SLV- ERROR: LinearSolver failed to set up correctly!\n" );
124  return -1;
125  }
126 
127  // Setup the Solver Operator
129 
130  // Reset status informations
131  bool failure = false;
132  this->resetStatus();
133  M_solverOperator->resetStatus();
134 
135  // Solve the linear system
136  WallClock chrono;
137  chrono.start();
138 
139  M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() );
140  M_converged = M_solverOperator->hasConverged();
141  M_lossOfPrecision = M_solverOperator->isLossOfAccuracyDetected();
142  chrono.stop();
143  if ( !M_silent )
144  {
145  M_displayer->leaderPrintMax ( "SLV- Solution time: " , chrono.diff(), " s." );
146  }
147 
148  // Getting informations post-solve
149  Int numIters = M_solverOperator->numIterations();
150 
151  // Second run recomputing the preconditioner
152  // This is done only if the preconditioner has not been
153  // already recomputed and if it is a LifeV preconditioner.
155  && retry
156  && M_preconditioner )
157  {
158  M_displayer->leaderPrint ( "SLV- Iterative solver failed, numiter = " , numIters, "\n" );
159  M_displayer->leaderPrint ( "SLV- retrying:\n" );
160 
162 
163  // Solving again, but only once (retry = false)
164  chrono.start();
165  M_solverOperator->ApplyInverse ( M_rhs->epetraVector(), solutionPtr->epetraVector() );
166  M_converged = M_solverOperator->hasConverged();
167  M_lossOfPrecision = M_solverOperator->isLossOfAccuracyDetected();
168  chrono.stop();
169  if ( !M_silent )
170  {
171  M_displayer->leaderPrintMax ( "SLV- Solution time: " , chrono.diff(), " s." );
172  }
173  }
174 
176  {
177  M_displayer->leaderPrint ( "SLV- WARNING: Loss of accuracy detected!\n" );
178  failure = true;
179  }
180 
182  {
183  if ( !M_silent )
184  {
185  M_displayer->leaderPrint ( "SLV- Convergence in " , numIters, " iterations\n" );
186  }
188  }
189  else
190  {
191  M_displayer->leaderPrint ( "SLV- WARNING: Solver failed to converged to the desired precision!\n" );
193  failure = true;
194  }
195 
196  // If quitOnFailure is enabled and if some problems occur
197  // the simulation is stopped
198  if ( M_quitOnFailure && failure )
199  {
200  exit ( -1 );
201  }
202 
203  // Reset the solver to free the internal pointers
204  M_solverOperator->resetSolver();
205 
206  // If the number of iterations reaches the threshold of maxIterForReuse
207  // we reset the preconditioners to force to solver to recompute it next
208  // time
209  if ( numIters > M_maxItersForReuse )
210  {
212  }
213 
214  return numIters;
215 }
216 
217 Real
219 {
220  if ( !M_operator || !M_rhs )
221  {
222  M_displayer->leaderPrint ( "SLV- WARNING: LinearSolver can not compute the residual if the operator and the RHS are not set!\n" );
223  return -1;
224  }
225 
226  vector_Type Ax ( solutionPtr->map() );
227  vector_Type residual ( *M_rhs );
228 
229  M_operator->Apply ( solutionPtr->epetraVector(), Ax.epetraVector() );
230 
231  residual.epetraVector().Update ( 1, Ax.epetraVector(), -1 );
232 
233  Real residualNorm;
234 
235  residual.norm2 ( &residualNorm );
236 
237  return residualNorm;
238 }
239 
240 std::string
242 {
243  std::ostringstream stat;
244  std::string str;
245 
247  {
248  stat << "Accuracy loss ";
249  }
251  {
252  stat << "Maximum number of iterations reached ";
253  }
255  {
256  stat << "The solver has converged ";
257  }
258  else if ( M_converged == SolverOperator_Type::no )
259  {
260  stat << "The solver has not ";
261  }
262  str = stat.str();
263  return str;
264 }
265 
266 void
267 LinearSolver::setPreconditionerFromGetPot ( const GetPot& dataFile, const std::string& section )
268 {
269  std::string precName = dataFile ( ( section + "/prectype" ).data(), "Ifpack" );
270 
271  M_preconditioner.reset ( PRECFactory::instance().createObject ( precName ) );
272  ASSERT ( M_preconditioner.get() != 0, " Preconditioner not set" );
273 
274  M_preconditioner->setDataFromGetPot ( dataFile, section );
275 }
276 
277 void
279 {
280  WallClock chrono;
281  Real condest ( -1 );
282 
283  if ( M_preconditioner )
284  {
285  if ( M_matrix.get() == 0 )
286  {
287  M_displayer->leaderPrint ( "SLV- ERROR: LinearSolver requires a matrix to build the preconditioner!\n" );
288  exit ( 1 );
289  }
290  else
291  {
292  chrono.start();
293  if ( !M_silent )
294  {
295  M_displayer->leaderPrint ( "SLV- Computing the preconditioner...\n" );
296  }
297  if ( M_baseMatrixForPreconditioner.get() == 0 )
298  {
299  if ( !M_silent )
300  {
301  M_displayer->leaderPrint ( "SLV- Build the preconditioner using the problem matrix\n" );
302  }
303  M_preconditioner->buildPreconditioner ( M_matrix );
304  }
305  else
306  {
307  if ( !M_silent )
308  {
309  M_displayer->leaderPrint ( "SLV- Build the preconditioner using the base matrix provided\n" );
310  }
311  M_preconditioner->buildPreconditioner ( M_baseMatrixForPreconditioner );
312  }
313  condest = M_preconditioner->condest();
314  chrono.stop();
315  if ( !M_silent )
316  {
317  M_displayer->leaderPrintMax ( "SLV- Preconditioner computed in " , chrono.diff(), " s." );
318  }
319  if ( !M_silent )
320  {
321  M_displayer->leaderPrint ( "SLV- Estimated condition number " , condest, "\n" );
322  }
323  }
324  }
325 }
326 
327 void
329 {
330  if ( M_preconditioner )
331  {
332  M_preconditioner->resetPreconditioner();
333  }
334 }
335 
336 bool
338 {
340  {
341  return true;
342  }
343 
344  return M_preconditioner.get() != 0 && M_preconditioner->preconditionerCreated();
345 }
346 
347 void
349 {
353 }
354 
355 void
356 LinearSolver::showMe ( std::ostream& output ) const
357 {
358  if ( M_displayer->isLeader() )
359  {
360  output << "Solver parameters list:" << std::endl;
361  output << "-----------------------------" << std::endl;
362  output << M_parameterList << std::endl;
363  output << "-----------------------------" << std::endl;
364  }
365 }
366 
367 void
369 {
370  // Creation of a solver if there exists any
371  if ( !M_solverOperator )
372  {
373  switch ( M_solverType )
374  {
375  case Belos:
376  M_solverOperator.reset ( Operators::SolverOperatorFactory::instance().createObject ( "Belos" ) );
377  break;
378  case AztecOO:
379  M_solverOperator.reset ( Operators::SolverOperatorFactory::instance().createObject ( "AztecOO" ) );
380  break;
381  default:
382  M_displayer->leaderPrint ( "SLV- ERROR: The type of solver is not recognized!\n" );
383  exit ( 1 );
384  break;
385  }
386  }
387 
388  // Set the preconditioner operator in the SolverOperator object
389  if ( M_preconditioner )
390  {
391  M_solverOperator->setPreconditioner ( M_preconditioner->preconditionerPtr() );
392  }
393  else if ( M_preconditionerOperator )
394  {
395  M_solverOperator->setPreconditioner ( M_preconditionerOperator );
396  }
397 
398  // Set the operator in the SolverOperator object
399  M_solverOperator->setOperator ( M_operator );
400 
401  // Set the tolerance if it has been set
402  if ( M_tolerance > 0 )
403  {
404  M_solverOperator->setTolerance ( M_tolerance );
405  }
406 
407  // Set the parameter inside the solver
408  M_solverOperator->setParameters ( M_parameterList.sublist ( "Solver: Operator List" ) );
409 }
410 
411 // ===================================================
412 // Set Methods
413 // ===================================================
414 void
415 LinearSolver::setSolverType ( const SolverType& solverType )
416 {
417  M_solverType = solverType;
418 }
419 
420 void
421 LinearSolver::setCommunicator ( const std::shared_ptr<Epetra_Comm> commPtr )
422 {
423  M_displayer->setCommunicator ( commPtr );
424 }
425 
427 {
428  M_operator = matrixPtr->matrixPtr();
429  M_matrix = matrixPtr;
430 }
431 
432 void
434 {
435  M_matrix.reset();
436  M_operator = operPtr;
437 }
438 
439 void
441 {
442  M_rhs = rhsPtr;
443 }
444 
445 void
447 {
448  // If a preconditioner operator exists it must be deleted
449  M_preconditionerOperator.reset();
450 
451  M_preconditioner = preconditionerPtr;
452 }
453 
454 void
456 {
457  // If a LifeV::Preconditioner exists it must be deleted
458  M_preconditioner.reset();
459 
460  M_preconditionerOperator = preconditionerPtr;
461 }
462 
463 void
465 {
466  M_baseMatrixForPreconditioner = baseMatrixPtr;
467 }
468 
469 void
470 LinearSolver::setParameters ( const Teuchos::ParameterList& list )
471 {
472  M_parameterList.setParameters ( list );
474  std::string solverName = M_parameterList.get<std::string> ( "Solver Type" );
475  if ( solverName == "Belos" )
476  {
478  }
479  else if ( solverName == "AztecOO" )
480  {
482  }
483 
484  M_reusePreconditioner = M_parameterList.get ( "Reuse Preconditioner" , false );
485  Int maxIter = M_parameterList.get ( "Maximum Iterations" , 200 );
486  M_maxItersForReuse = M_parameterList.get ( "Max Iterations For Reuse" , static_cast<Int> ( maxIter * 8. / 10. ) );
487  M_quitOnFailure = M_parameterList.get ( "Quit On Failure" , false );
488  M_silent = M_parameterList.get ( "Silent" , false );
489 }
490 
491 void
493 {
494  M_parameterList = Teuchos::ParameterList();
495 }
496 
497 void
498 LinearSolver::setReusePreconditioner ( const bool reusePreconditioner )
499 {
500  M_reusePreconditioner = reusePreconditioner;
501 }
502 
503 void
504 LinearSolver::setQuitOnFailure ( const bool enable )
505 {
506  M_quitOnFailure = enable;
507 }
508 
509 void
510 LinearSolver::setTolerance ( const Real& tolerance )
511 {
512  M_tolerance = tolerance;
513 }
514 
515 // ===================================================
516 // Get Methods
517 // ===================================================
518 
519 Int
521 {
522  return M_solverOperator->numIterations();
523 }
524 
525 
526 Real
528 {
529  M_displayer->leaderPrint ( "SLV- WARNING: LinearSoler::recursiveResidual is not yet implemented\n" );
530 
531  /*
532  if ( !M_problem->isProblemSet() )
533  {
534  M_displayer->leaderPrint( "SLV- WARNING: LinearSoler can not compute the residual if the linear system is not set!\n" );
535  return -1;
536  }
537  multiVector_Type res( *( M_problem->getRHS().get() ) );
538  M_problem->computeCurrResVec( &res,M_problem->getLHS().get(), M_problem->getRHS().get() );
539  Real residual;
540  res.Norm2( &residual );
541  return residual;
542  */
543  return 0.;
544 }
545 
548 {
549  return M_preconditioner;
550 }
551 
554 {
555  return M_parameterList;
556 }
557 
560 {
561  return M_solverOperator;
562 }
563 
566 {
567  return M_displayer;
568 }
569 
570 Int
572 {
573  return M_maxItersForReuse;
574 }
575 
576 bool
578 {
579  return M_reusePreconditioner;
580 }
581 
582 bool
584 {
585  return M_quitOnFailure;
586 }
587 
588 bool
590 {
591  return M_silent;
592 }
593 
596 {
597  return M_maxNumItersReached;
598 }
599 
602 {
603  return M_lossOfPrecision;
604 }
605 
608 {
609  return M_converged;
610 }
611 
612 // ===================================================
613 // Private Methods
614 // ===================================================
615 
616 
617 
618 // ===================================================
619 // External functions
620 // ===================================================
621 
623 {
626 {
627  Teuchos::ParameterList defaultList;
628  defaultList.set ( "Reuse Preconditioner" , false );
629  defaultList.set ( "Max Iterations For Reuse", 80 );
630  defaultList.set ( "Quit On Failure" , false );
631  defaultList.set ( "Silent" , false );
632  defaultList.set ( "Solver Type" , "Belos" );
633 
634  Teuchos::ParameterList& operatorList = defaultList.sublist ( "Solver: Operator List" );
635  operatorList.set ( "Solver Manager Type", "BlockGmres" );
636  operatorList.set ( "Preconditioner Side", "Right" );
637 
638  Teuchos::ParameterList& defaultBelos = operatorList.sublist ( "Trilinos: Belos List" );
639  defaultBelos.set ( "Flexible Gmres" , false );
640  defaultBelos.set ( "Convergence Tolerance", 1e-6 );
641  defaultBelos.set ( "Maximum Iterations" , 200 );
642  defaultBelos.set ( "Output Frequency" , 1 );
643  defaultBelos.set ( "Block Size" , 1 );
644  defaultBelos.set ( "Num Blocks" , 200 );
645  defaultBelos.set ( "Maximum Restarts" , 0 );
646  defaultBelos.set ( "Output Style" , 1 );
647  defaultBelos.set ( "Verbosity" , 35 );
648 
649  return defaultList;
650 }
651 
654 {
655  Teuchos::ParameterList defaultList;
656  defaultList.set ( "Reuse Preconditioner" , false );
657  defaultList.set ( "Max Iterations For Reuse", 80 );
658  defaultList.set ( "Quit On Failure" , false );
659  defaultList.set ( "Silent" , false );
660  defaultList.set ( "Solver Type" , "AztecOO" );
661 
662  Teuchos::ParameterList& operatorList = defaultList.sublist ( "Solver: Operator List" );
663 
664  Teuchos::ParameterList& defaultAztecOO = operatorList.sublist ( "Trilinos: AztecOO List" );
665  defaultAztecOO.set ( "solver" , "gmres" );
666  defaultAztecOO.set ( "conv" , "rhs" );
667  defaultAztecOO.set ( "scaling" , "none" );
668  defaultAztecOO.set ( "output" , "all" );
669  defaultAztecOO.set ( "tol" , 1e-6 );
670  defaultAztecOO.set ( "max_iter", 200 );
671  defaultAztecOO.set ( "kspace" , 200 );
672  defaultAztecOO.set ( "orthog" , 0 );
673  defaultAztecOO.set ( "aux_vec" , 0 );
674 
675  return defaultList;
676 }
677 }
678 
679 } // namespace LifeV
SolverOperator_Type::SolverOperatorStatusType hasReachedMaxNumIters() const
Returns if the maximum number of iterations has been reached.
std::shared_ptr< SolverOperator_Type > SolverOperatorPtr_Type
Real computeResidual(vectorPtr_Type solutionPtr)
Compute the residual.
Operators::SolverOperator SolverOperator_Type
bool quitOnFailure() const
Returns if the application should stop if a problem occurs.
std::string printStatus()
return the solver status
bool isPreconditionerSet() const
Return true if preconditioner has been setted.
bool silent() const
Returns if the solver is in silent mode.
vectorPtr_Type M_rhs
SolverOperator_Type::SolverOperatorStatusType hasConverged() const
Returns if the convergence has been achieved.
Wall clock timer class.
Definition: WallClock.hpp:48
SolverOperator_Type::SolverOperatorStatusType M_converged
Int numIterations() const
Return the total number of iterations.
Real recursiveResidual()
Return the recursive residual.
void setReusePreconditioner(const bool reusePreconditioner)
Specify if the preconditioner should be reuse or not.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
void resetPreconditioner()
Reset the stored preconditioner.
void resetStatus()
Reset the status for the state of convergence and loss of accuracy.
void setQuitOnFailure(const bool enable)
Specify if the application should stop when problems occur in the iterations.
VectorEpetra vector_Type
void updateInverseJacobian(const UInt &iQuadPt)
operatorPtr_Type M_operator
Teuchos::ParameterList aztecOOParameterList()
Returns a default parameter list to initialize the LinearSolver class with AztecOO.
void setParameters(const Teuchos::ParameterList &list)
Method to setup the solver using Teuchos::ParameterList.
SolverOperatorPtr_Type M_solverOperator
std::shared_ptr< Displayer > displayer()
Return a shared pointer on the displayer.
void norm2(Real *result) const
Compute and store the norm 2 in the given pointed variable.
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
void setSolverType(const SolverType &solverType)
Set the solver which should be used.
preconditionerPtr_Type & preconditioner()
Method to get a shared pointer to the preconditioner.
LinearSolver - Class to wrap linear solver.
void setOperator(operatorPtr_Type operPtr)
Method to set a general linear operator (of class derived from Epetra_Operator) defining the linear s...
SolverOperatorPtr_Type solver()
Return a pointer on the Belos solver manager.
void setRightHandSide(const vectorPtr_Type rhsPtr)
Method to set the right hand side (rhs) of the linear system.
void resetParameters()
Method to reset the parameters list of the solver.
matrixPtr_Type M_matrix
void setTolerance(const Real &tolerance)
Set the tolerance of the solver.
SolverOperator_Type::SolverOperatorStatusType M_lossOfPrecision
std::shared_ptr< operator_Type > operatorPtr_Type
Int maxItersForReuse() const
Returns the maximum of iterations tolerate to avoid recomputing the preconditioner.
SolverOperator_Type::SolverOperatorStatusType M_maxNumItersReached
double Real
Generic real data.
Definition: LifeV.hpp:175
void setPreconditioner(operatorPtr_Type preconditionerPtr)
Method to set a general Epetra_Operator as preconditioner.
Teuchos::ParameterList belosParameterList()
Returns a default parameter list to initialize the LinearSolver class with Belos. ...
void setCommunicator(const std::shared_ptr< Epetra_Comm > commPtr)
Method to set communicator for Displayer (for empty constructor)
std::shared_ptr< VectorEpetra > vectorPtr_Type
void setupSolverOperator()
Setup the solver operator to be used.
void setBaseMatrixForPreconditioner(matrixPtr_Type baseMatrixPtr)
Method to set a matrix on which the preconditioner should be created.
Teuchos::ParameterList & parametersList()
Return a Teuchos parameters list.
Int solve(vectorPtr_Type solutionPtr)
Solves the system and returns the number of iterations.
std::shared_ptr< preconditioner_Type > preconditionerPtr_Type
std::shared_ptr< matrix_Type > matrixPtr_Type
SolverOperator_Type::SolverOperatorStatusType isLossOfAccuracyDetected() const
Returns if a loss of precision has been detected.
void showMe(std::ostream &output=std::cout) const
Print informations about the solver.
void buildPreconditioner()
Builds the preconditioner starting from the matrix "baseMatrixForPreconditioner". ...
void setPreconditionerFromGetPot(const GetPot &dataFile, const std::string &section)
Setup the preconditioner from a GetPot file.
LinearSolver(const std::shared_ptr< Epetra_Comm > commPtr)
Constructor.
~LinearSolver()
Destructor.
matrixPtr_Type M_baseMatrixForPreconditioner
bool reusePreconditioner() const
Returns if the preconditioner can be reused.
operatorPtr_Type M_preconditionerOperator
preconditionerPtr_Type M_preconditioner
LinearSolver()
Empty constructor.