trilinos_solver.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26#include "trilinos_solver.h"
27
28
29namespace oomph
30{
31 ///////////////////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////////////////
33 // functions for TrilinosAztecOOSolver class
34 ///////////////////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////////////////
36
37
38 //=============================================================================
39 /// Function which uses problem_pt's get_jacobian(...) function to
40 /// generate a linear system which is then solved. This function deletes
41 /// any existing internal data and then generates a new AztecOO solver.
42 //=============================================================================
43 void TrilinosAztecOOSolver::solve(Problem* const& problem_pt,
45 {
46 // MemoryUsage::doc_memory_usage("start of TrilinosAztecOOSolver::solve");
47 // MemoryUsage::insert_comment_to_continous_top(
48 // "start of TrilinosAztecOOSolver::solve");
49
50 // clean up from previous solve
52
53 // if we were previously using a problem based solve then we should delete
54 // the oomphlib matrix as it was created during the last solve
56 {
57 delete Oomph_matrix_pt;
59 }
60
61 // this is a problem based solve
63
64 // store the problem_pt
65 Problem_pt = problem_pt;
66
67 // Get oomph-lib Jacobian matrix and residual vector
68
69 // record the start time
71
72 // MemoryUsage::doc_memory_usage("start of get_jacobian()");
73 // MemoryUsage::insert_comment_to_continous_top("start of
74 // get_jacobian()");
75
76 // create the residual
77 DoubleVector residual;
78
79 // create the jacobian
82 problem_pt->get_jacobian(residual, *cr_matrix_pt);
83 this->build_distribution(residual.distribution_pt());
84
85 // record the end time and compute the matrix setup time
86 double end_t = TimingHelpers::timer();
88 if (this->Doc_time)
89 {
90 oomph_info << "Time to generate Jacobian [sec] : "
91 << Jacobian_setup_time << std::endl;
92 }
93
94
95 // MemoryUsage::doc_memory_usage("after get_jacobian() in trilinos
96 // solver"); MemoryUsage::insert_comment_to_continous_top(
97 // "after get_jacobian() in trilinos solver");
98
99 // store the distribution of the solution vector
100 if (!solution.built())
101 {
102 solution.build(this->distribution_pt(), 0.0);
103 }
105
106 // redistribute the distribution
107 solution.redistribute(this->distribution_pt());
108
109 // MemoryUsage::doc_memory_usage("before trilinos solve");
110 // MemoryUsage::insert_comment_to_continous_top("before trilinos solve ");
111
112 // continue solving using matrix based solve function
113 solve(Oomph_matrix_pt, residual, solution);
114
115
116 // MemoryUsage::doc_memory_usage("after trilinos solve");
117 // MemoryUsage::insert_comment_to_continous_top("after trilinos solve ");
118
119 // return to the original distribution
120 solution.redistribute(&solution_dist);
121
122 // MemoryUsage::doc_memory_usage("end of TrilinosAztecOOSolver::solve");
123 // MemoryUsage::insert_comment_to_continous_top(
124 // "end of TrilinosAztecOOSolver::solve");
125 }
126
127
128 //=============================================================================
129 /// Function to solve the linear system defined by matrix_pt and rhs.
130 /// \b NOTE 1. The matrix has to be of type CRDoubleMatrix or
131 /// DistributedCRDoubleMatrix.
132 /// \b NOTE 2. This function will delete any existing internal data and
133 /// generate a new AztecOO solver.
134 //=============================================================================
136 const DoubleVector& rhs,
138 {
139 // start the timer
140 double start_t = TimingHelpers::timer();
141
142#ifdef PARANOID
143 // check that the matrix is square
144 if (matrix_pt->nrow() != matrix_pt->ncol())
145 {
146 std::ostringstream error_message_stream;
147 error_message_stream << "The matrix at matrix_pt must be square.";
151 }
152 // check that the matrix and the rhs vector have the same nrow()
153 if (matrix_pt->nrow() != rhs.nrow())
154 {
155 std::ostringstream error_message_stream;
157 << "The matrix and the rhs vector must have the same number of rows.";
161 }
162
163 // if the matrix is distributable then it too should have the same
164 // communicator as the rhs vector and should not be distributed
165 CRDoubleMatrix* cr_matrix_pt = dynamic_cast<CRDoubleMatrix*>(matrix_pt);
166 if (cr_matrix_pt != 0)
167 {
168 OomphCommunicator temp_comm(*rhs.distribution_pt()->communicator_pt());
169 if (!(temp_comm == *cr_matrix_pt->distribution_pt()->communicator_pt()))
170 {
171 std::ostringstream error_message_stream;
173 << "The matrix matrix_pt must have the same communicator as the "
174 "vectors"
175 << " rhs and result must have the same communicator";
179 }
180 }
181 else
182 {
183 throw OomphLibError("Matrix must be of type CRDoubleMatrix",
186 }
187
188 // if the result vector is setup then check it is not distributed and has
189 // the same communicator as the rhs vector
190 if (result.built())
191 {
192 if (!(*result.distribution_pt() == *rhs.distribution_pt()))
193 {
194 std::ostringstream error_message_stream;
196 << "The result vector distribution has been setup; it must have the "
197 << "same distribution as the rhs vector.";
201 }
202 }
203#endif
204
205 // build the result if not built
206 if (!result.built())
207 {
208 result.build(rhs.distribution_pt(), 0.0);
209 }
210
212 {
213 // Only call the setup method if this is the first time we call the
214 // solve method
216 {
217 // setup the solver
218 solver_setup(matrix_pt);
219 // Do not call the setup again
221 // Enable resolve since we are not going to build the solver, the
222 // matrix and the wrapper to the preconditioner again
223 Enable_resolve = true;
224 }
225 }
226 else
227 {
228 // setup the solver
229 solver_setup(matrix_pt);
230 }
231
232 // create Epetra version of r
235
236 // create an empty Epetra vector for z
239
241
242 // solve the system
244
246 if (this->Doc_time)
247 {
248 oomph_info << "Time for trilinos solve itself : "
249 << end_t_trilinos - start_t_trilinos << "s" << std::endl;
250 }
251 // Copy result to z
253
254 // clean up memory
255 delete epetra_r_pt;
256 delete epetra_z_pt;
257
258 // delete solver data if required
259 if (!Enable_resolve)
260 {
262 }
263
264 // stop timers and compute solve time
265 double end_t = TimingHelpers::timer();
267
268 // output timings and info
269 if (this->Doc_time)
270 {
271 oomph_info << "Time for complete trilinos solve : "
272 << Linear_solver_solution_time << "s" << std::endl;
273 }
274 }
275
276
277 //=============================================================================
278 /// Helper function for setting up the solver. Converts the oomph-lib
279 /// matrices to Epetra matrices, sets up the preconditioner, creates the
280 /// Trilinos Aztec00 solver and passes in the matrix, preconditioner and
281 /// parameters.
282 //=============================================================================
284 {
285 // clean up the memory
286 // - delete all except Oomph_matrix_pt, which may have been set in the
287 // problem based solve
289
290 // cast to CRDoubleMatrix
291 // note cast check performed in matrix based solve(...) method
292 CRDoubleMatrix* cast_matrix_pt = dynamic_cast<CRDoubleMatrix*>(matrix_pt);
293
294 // store the distribution
295 // distribution of preconditioner is same as matrix
296 this->build_distribution(cast_matrix_pt->distribution_pt());
297
298 // create the new solver
300
301 // if the preconditioner is an oomph-lib preconditioner then we set it up
304 if (trilinos_prec_pt == 0)
305 {
307 {
308 // setup the preconditioner
309 // start of prec setup
311 Preconditioner_pt->setup(matrix_pt);
312 // start of prec setup
314 if (Doc_time)
315 {
317 oomph_info << "Time for preconditioner setup [sec]: " << t_prec_setup
318 << std::endl;
319 }
320#ifdef PARANOID
321 if (*Preconditioner_pt->distribution_pt() != *this->distribution_pt())
322 {
323 std::ostringstream error_message;
324 error_message << "The oomph-lib preconditioner and the solver must "
325 << "have the same distribution";
326 throw OomphLibError(error_message.str(),
329 }
330#endif
331 }
332
333 // wrap the oomphlib preconditioner in the Epetra_Operator derived
334 // OoomphLibPreconditionerEpetraOperator to allow it to be passed to the
335 // trilinos preconditioner
338 }
339
340 // create the matrix
343 {
345 TrilinosEpetraHelpers ::create_distributed_epetra_matrix_for_aztecoo(
347 }
348 else
349 {
351 TrilinosEpetraHelpers ::create_distributed_epetra_matrix(
352 cast_matrix_pt, cast_matrix_pt->distribution_pt());
353 }
354
355 // record the end time and compute the matrix setup time
357 if (trilinos_prec_pt == 0)
358 {
360 {
361 dynamic_cast<CRDoubleMatrix*>(Oomph_matrix_pt)->clear();
362 delete Oomph_matrix_pt;
364 }
365
366 // delete Oomph-lib matrix if requested
367 else if (Delete_matrix)
368 {
369 dynamic_cast<CRDoubleMatrix*>(matrix_pt)->clear();
370 }
371 }
372
373 // output times
374 if (Doc_time)
375 {
376 oomph_info << "Time to generate Trilinos matrix : "
377 << double(end_t_matrix - start_t_matrix) << "s" << std::endl;
378 }
379
380 // set the matrix
381 AztecOO_solver_pt->SetUserMatrix(Epetra_matrix_pt);
382
383 // set the preconditioner
384 if (trilinos_prec_pt == 0)
385 {
387 }
388
389#ifdef PARANOID
390 // paranoid check the preconditioner exists
391 if (Preconditioner_pt == 0)
392 {
393 std::ostringstream error_message;
394 error_message << "Preconditioner_pt == 0. (Remember default "
395 << "preconditioner is IdentityPreconditioner)";
396 throw OomphLibError(
398 }
399#endif
400
401 // if the preconditioner is a trilinos preconditioner then setup the
402 // preconditioner
403 if (trilinos_prec_pt != 0)
404 {
405 // only setup the preconditioner if required
407 {
408 // start of prec setup
410
411 // setup the preconditioner
412 trilinos_prec_pt->set_matrix_pt(matrix_pt);
414
415
416 // set the preconditioner
417 AztecOO_solver_pt->SetPrecOperator(
418 trilinos_prec_pt->epetra_operator_pt());
419
420 // start of prec setup
422 if (Doc_time)
423 {
425 oomph_info << "Time for preconditioner setup [sec]: " << t_prec_setup
426 << std::endl;
427 }
428 }
429
430 // delete the oomph-matrix if required
432 {
433 dynamic_cast<CRDoubleMatrix*>(Oomph_matrix_pt)->clear();
434 delete Oomph_matrix_pt;
436 }
437
438 // delete Oomph-lib matrix if requested
439 else if (Delete_matrix)
440 {
441 dynamic_cast<CRDoubleMatrix*>(matrix_pt)->clear();
442 }
443 }
444
445 // set solver options
446 if (Doc_time)
447 {
448 AztecOO_solver_pt->SetAztecOption(AZ_output, AZ_warnings);
449 }
450 else
451 {
452 AztecOO_solver_pt->SetAztecOption(AZ_output, AZ_none);
453 }
454 AztecOO_solver_pt->SetAztecOption(AZ_kspace, Max_iter);
455
456 // set solver type
457 switch (Solver_type)
458 {
459 case CG:
460 AztecOO_solver_pt->SetAztecOption(AZ_solver, AZ_cg);
461 break;
462
463 case GMRES:
464 AztecOO_solver_pt->SetAztecOption(AZ_solver, AZ_gmres);
465 break;
466
467 case BiCGStab:
468 AztecOO_solver_pt->SetAztecOption(AZ_solver, AZ_bicgstab);
469 break;
470
471 default:
472 std::ostringstream error_message;
473 error_message << "Solver_type set to incorrect value. "
474 << "Acceptable values are " << CG << ", " << GMRES
475 << " and " << BiCGStab << ". Current value is "
476 << Solver_type << ".";
477 throw OomphLibError(error_message.str(),
480 }
481 }
482
483 //=============================================================================
484 /// Function to resolve a linear system using the existing solver
485 /// data, allowing a solve with a new right hand side vector. This
486 /// function must be used after a call to solve(...) with
487 /// enable_resolve set to true.
488 //=============================================================================
491 {
492 // start the timer
493 double start_t = TimingHelpers::timer();
494
495#ifdef PARANOID
496 if (Epetra_matrix_pt->NumGlobalRows() != static_cast<int>(rhs.nrow()))
497 {
498 std::ostringstream error_message;
499 error_message
500 << "The rhs vector and the matrix must have the same number "
501 << "of rows.\n"
502 << "The rhs vector has " << rhs.nrow() << " rows.\n"
503 << "The matrix has " << Epetra_matrix_pt->NumGlobalRows() << " rows.\n";
504 throw OomphLibError(
506 }
507
508 // if the result vector is setup then check it is not distributed and has
509 // the same communicator as the rhs vector
510 if (solution.built())
511 {
512 if (!(*solution.distribution_pt() == *rhs.distribution_pt()))
513 {
514 std::ostringstream error_message_stream;
516 << "The result vector distribution has been setup; it must have the "
517 << "same distribution as the rhs vector.";
521 }
522 }
523#endif
524
525 // build the result if not built
526 if (!solution.built())
527 {
528 solution.build(rhs.distribution_pt(), 0.0);
529 }
530
531
532 // create Epetra version of r
535
536 // create an empty Epetra vector for z
539
540 // solve the system
542
543 // Copy result to z
544 if (!solution.distribution_built())
545 {
546 solution.build(rhs.distribution_pt(), 0.0);
547 }
549
550 // clean up memory
551 delete epetra_r_pt;
552 delete epetra_z_pt;
553
554 double end_t = TimingHelpers::timer();
556
557 // output timings and info
558 if (this->Doc_time)
559 {
560 oomph_info << "Time for resolve : "
561 << Linear_solver_solution_time << "s" << std::endl;
562 }
563 }
564
565
566 //=============================================================================
567 /// Helper function performs the actual solve once the AztecOO
568 /// solver is set up (i.e. solver_setup() is called)
569 //=============================================================================
572 {
573#ifdef PARANOID
574 // check the matrix and rhs are of consistent sizes
575 if (AztecOO_solver_pt == 0)
576 {
577 std::ostringstream error_message;
578 error_message << "Solver must be called with solve(...) "
579 << "before resolve(...) to set it up.\n";
580 throw OomphLibError(
582 }
583#endif
584
585 // set the vectors
586 AztecOO_solver_pt->SetLHS(soln_pt);
587 AztecOO_solver_pt->SetRHS(rhs_pt);
588
589 // perform solve
591
592
593 // output iterations and final norm
594 Iterations = AztecOO_solver_pt->NumIters();
595 if (Doc_time)
596 {
597 double norm = AztecOO_solver_pt->TrueResidual();
598 oomph_info << "Number of iterations to convergence: " << Iterations
599 << std::endl;
600 oomph_info << "Final relative residual norm : " << norm
601 << std::endl;
602 }
603 }
604
605
606 ///////////////////////////////////////////////////////////////////////////////
607 ///////////////////////////////////////////////////////////////////////////////
608 ///////////////////////////////////////////////////////////////////////////////
609
610
611} // namespace oomph
The conjugate gradient method.
The conjugate gradient method.
A class for compressed row matrices. This is a distributable object.
Definition matrices.h:888
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
Abstract base class for matrices of doubles – adds abstract interfaces for solving,...
Definition matrices.h:261
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
A vector in the mathematical sense, initially developed for linear algebra type applications....
The GMRES method.
bool Use_iterative_solver_as_preconditioner
Use the iterative solver as preconditioner.
bool First_time_solve_when_used_as_preconditioner
When the iterative solver is used a preconditioner then we call the setup of solver method only once ...
double Tolerance
Convergence tolerance.
Preconditioner * Preconditioner_pt
Pointer to the preconditioner.
unsigned Max_iter
Maximum number of iterations.
bool Setup_preconditioner_before_solve
indicates whether the preconditioner should be setup before solve. Default = true;
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
bool Doc_time
Boolean flag that indicates whether the time taken.
bool Enable_resolve
Boolean that indicates whether the matrix (or its factors, in the case of direct solver) should be st...
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
An OomphLibError object which should be thrown when an run-time error is encountered....
An Epetra_Operator class for oomph-lib preconditioners. A helper class for TrilinosOomphLibPreconditi...
virtual void setup(DoubleMatrixBase *matrix_pt)
Setup the preconditioner: store the matrix pointer and the communicator pointer then call preconditio...
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
virtual void get_jacobian(DoubleVector &residuals, DenseDoubleMatrix &jacobian)
Return the fully-assembled Jacobian and residuals for the problem Interface for the case when the Jac...
Definition problem.cc:3935
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
bool Using_problem_based_solve
Helper flag keeping track of whether we called the linear algebra or problem-based solve function.
void resolve(const DoubleVector &rhs, DoubleVector &solution)
Function to resolve a linear system using the existing solver data, allowing a solve with a new right...
void solver_setup(DoubleMatrixBase *const &matrix_pt)
Helper function for setting up the solver. Converts the oomph-lib matrices to Epetra matrices,...
unsigned Iterations
Stores number of iterations used.
Epetra_CrsMatrix * Epetra_matrix_pt
A pointer for the linear system matrix in Epetra_CrsMatrix format.
void clean_up_memory()
Clean up method - deletes the solver, the matrices and the preconditioner.
void solve_using_AztecOO(Epetra_Vector *&rhs_pt, Epetra_Vector *&soln_pt)
Helper function performs the actual solve once the AztecOO solver is set up.
bool Delete_matrix
Trilinos copies matrix data from oomph-lib's own CRDoubleMatrix or DistributedCRDoubleMatrix to Trili...
DoubleMatrixBase * Oomph_matrix_pt
Oomph lib matrix pointer.
Epetra_Operator * Epetra_preconditioner_pt
A pointer to the Epetra_Operator for the preconditioner. This is only used if the preconditioner NOT ...
void solve(Problem *const &problem_pt, DoubleVector &solution)
Function which uses problem_pt's get_jacobian(...) function to generate a linear system which is then...
unsigned Solver_type
Defines which solver is set up - available types are defined in AztecOO_solver_types.
double Linear_solver_solution_time
Stores time for the solution (excludes time to set up preconditioner)
Problem * Problem_pt
A pointer to the underlying problem (NULL if MATRIX based solve) The problem_pt is stored here in a p...
AztecOO * AztecOO_solver_pt
Pointer to the AztecOO solver.
bool Use_aztecoo_workaround_for_epetra_matrix_setup
Use workaround for creating of epetra matrix that respects aztecoo's ordering requirements.
double Jacobian_setup_time
Stores set up time for Jacobian.
Base class for Trilinos preconditioners as oomph-lib preconditioner.
double timer()
returns the time in seconds after some point in past
void copy_to_oomphlib_vector(const Epetra_Vector *epetra_vec_pt, DoubleVector &oomph_vec)
Helper function to copy the contents of a Trilinos vector to an oomph-lib distributed vector....
Epetra_Vector * create_distributed_epetra_vector(const DoubleVector &oomph_vec)
create an Epetra_Vector from an oomph-lib DoubleVector. If oomph_vec is NOT distributed (i....
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...