deal.II version GIT relicensing-6839-g338455934c 2026-10-02 12:10:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
trilinos_solver.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2008 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
14
15#ifdef DEAL_II_TRILINOS_WITH_EPETRA
16
18
22
24
25# include <AztecOO_StatusTest.h>
26# include <AztecOO_StatusTestCombo.h>
27# include <AztecOO_StatusTestMaxIters.h>
28# include <AztecOO_StatusTestResNorm.h>
29# include <AztecOO_StatusType.h>
30
32
33# include <cmath>
34# include <limits>
35# include <memory>
36
37
38#endif // DEAL_II_TRILINOS_WITH_EPETRA
39
41
42#ifdef DEAL_II_TRILINOS_WITH_EPETRA
43
44namespace TrilinosWrappers
45{
47 const bool output_solver_details,
48 const unsigned int gmres_restart_parameter)
49 : output_solver_details(output_solver_details)
50 , gmres_restart_parameter(gmres_restart_parameter)
51 {}
52
53
54
60
61
62
64 SolverControl &cn,
65 const AdditionalData &data)
66 : solver_name(solver_name)
67 , solver_control(cn)
68 , additional_data(data)
69 {}
70
71
72
75 {
76 return solver_control;
77 }
78
79
80
81 void
83 MPI::Vector &x,
84 const MPI::Vector &b,
85 const PreconditionBase &preconditioner)
86 {
87 // We need an Epetra_LinearProblem object to let the AztecOO solver know
88 // about the matrix and vectors.
89 linear_problem = std::make_unique<Epetra_LinearProblem>(
90 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()),
91 &x.trilinos_vector(),
92 const_cast<Epetra_MultiVector *>(&b.trilinos_vector()));
93
94 do_solve(preconditioner);
95 }
96
97
98
99 // Note: "A" is set as a constant reference so that all patterns for ::solve
100 // can be used by the inverse_operator of LinearOperator
101 void
103 MPI::Vector &x,
104 const MPI::Vector &b,
105 const PreconditionBase &preconditioner)
106 {
107 // We need an Epetra_LinearProblem object to let the AztecOO solver know
108 // about the matrix and vectors.
110 std::make_unique<Epetra_LinearProblem>(const_cast<Epetra_Operator *>(&A),
111 &x.trilinos_vector(),
112 const_cast<Epetra_MultiVector *>(
113 &b.trilinos_vector()));
114
115 do_solve(preconditioner);
116 }
117
118
119
120 // Note: "A" is set as a constant reference so that all patterns for ::solve
121 // can be used by the inverse_operator of LinearOperator
122 void
124 MPI::Vector &x,
125 const MPI::Vector &b,
126 const Epetra_Operator &preconditioner)
127 {
128 // We need an Epetra_LinearProblem object to let the AztecOO solver know
129 // about the matrix and vectors.
131 std::make_unique<Epetra_LinearProblem>(const_cast<Epetra_Operator *>(&A),
132 &x.trilinos_vector(),
133 const_cast<Epetra_MultiVector *>(
134 &b.trilinos_vector()));
135
136 do_solve(preconditioner);
137 }
138
139
140
141 // Note: "A" is set as a constant reference so that all patterns for ::solve
142 // can be used by the inverse_operator of LinearOperator
143 void
145 Epetra_MultiVector &x,
146 const Epetra_MultiVector &b,
147 const PreconditionBase &preconditioner)
148 {
149 // We need an Epetra_LinearProblem object to let the AztecOO solver know
150 // about the matrix and vectors.
152 std::make_unique<Epetra_LinearProblem>(const_cast<Epetra_Operator *>(&A),
153 &x,
154 const_cast<Epetra_MultiVector *>(
155 &b));
156
157 do_solve(preconditioner);
158 }
159
160
161
162 // Note: "A" is set as a constant reference so that all patterns for ::solve
163 // can be used by the inverse_operator of LinearOperator
164 void
166 Epetra_MultiVector &x,
167 const Epetra_MultiVector &b,
168 const Epetra_Operator &preconditioner)
169 {
170 // We need an Epetra_LinearProblem object to let the AztecOO solver know
171 // about the matrix and vectors.
173 std::make_unique<Epetra_LinearProblem>(const_cast<Epetra_Operator *>(&A),
174 &x,
175 const_cast<Epetra_MultiVector *>(
176 &b));
177
178 do_solve(preconditioner);
179 }
180
181
182
183 void
186 const ::Vector<double> &b,
187 const PreconditionBase &preconditioner)
188 {
189 // In case we call the solver with deal.II vectors, we create views of the
190 // vectors in Epetra format.
191 Assert(x.size() == A.n(), ExcDimensionMismatch(x.size(), A.n()));
192 Assert(b.size() == A.m(), ExcDimensionMismatch(b.size(), A.m()));
193 Assert(A.local_range().second == A.m(),
194 ExcMessage("Can only work in serial when using deal.II vectors."));
195 Assert(A.trilinos_matrix().Filled(),
196 ExcMessage("Matrix is not compressed. Call compress() method."));
197
198 Epetra_Vector ep_x(View, A.trilinos_matrix().DomainMap(), x.begin());
199 Epetra_Vector ep_b(View,
200 A.trilinos_matrix().RangeMap(),
201 const_cast<double *>(b.begin()));
202
203 // We need an Epetra_LinearProblem object to let the AztecOO solver know
204 // about the matrix and vectors.
205 linear_problem = std::make_unique<Epetra_LinearProblem>(
206 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()), &ep_x, &ep_b);
207
208 do_solve(preconditioner);
209 }
210
211
212
213 void
216 const ::Vector<double> &b,
217 const PreconditionBase &preconditioner)
218 {
219 Epetra_Vector ep_x(View, A.OperatorDomainMap(), x.begin());
220 Epetra_Vector ep_b(View,
221 A.OperatorRangeMap(),
222 const_cast<double *>(b.begin()));
223
224 // We need an Epetra_LinearProblem object to let the AztecOO solver know
225 // about the matrix and vectors.
226 linear_problem = std::make_unique<Epetra_LinearProblem>(&A, &ep_x, &ep_b);
227
228 do_solve(preconditioner);
229 }
230
231
232
233 void
236 const ::LinearAlgebra::distributed::Vector<double> &b,
237 const PreconditionBase &preconditioner)
238 {
239 // In case we call the solver with deal.II vectors, we create views of the
240 // vectors in Epetra format.
242 A.trilinos_matrix().DomainMap().NumMyElements());
243 AssertDimension(b.locally_owned_size(),
244 A.trilinos_matrix().RangeMap().NumMyElements());
245
246 Epetra_Vector ep_x(View, A.trilinos_matrix().DomainMap(), x.begin());
247 Epetra_Vector ep_b(View,
248 A.trilinos_matrix().RangeMap(),
249 const_cast<double *>(b.begin()));
250
251 // We need an Epetra_LinearProblem object to let the AztecOO solver know
252 // about the matrix and vectors.
253 linear_problem = std::make_unique<Epetra_LinearProblem>(
254 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()), &ep_x, &ep_b);
255
256 do_solve(preconditioner);
257 }
258
259
260
261 void
264 const ::LinearAlgebra::distributed::Vector<double> &b,
265 const PreconditionBase &preconditioner)
266 {
268 A.OperatorDomainMap().NumMyElements());
269 AssertDimension(b.locally_owned_size(),
270 A.OperatorRangeMap().NumMyElements());
271
272 Epetra_Vector ep_x(View, A.OperatorDomainMap(), x.begin());
273 Epetra_Vector ep_b(View,
274 A.OperatorRangeMap(),
275 const_cast<double *>(b.begin()));
276
277 // We need an Epetra_LinearProblem object to let the AztecOO solver know
278 // about the matrix and vectors.
279 linear_problem = std::make_unique<Epetra_LinearProblem>(&A, &ep_x, &ep_b);
280
281 do_solve(preconditioner);
282 }
283
284
285 namespace internal
286 {
287 namespace
288 {
289 double
290 compute_residual(const Epetra_MultiVector *const residual_vector)
291 {
292 Assert(residual_vector->NumVectors() == 1,
293 ExcMessage("Residual multivector holds more than one vector"));
294 TrilinosScalar res_l2_norm = 0.0;
295 const int ierr = residual_vector->Norm2(&res_l2_norm);
296 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
297 return res_l2_norm;
298 }
299
300 class TrilinosReductionControl : public AztecOO_StatusTest
301 {
302 public:
303 TrilinosReductionControl(const int max_steps,
304 const double tolerance,
305 const double reduction,
306 const Epetra_LinearProblem &linear_problem);
307
308 virtual ~TrilinosReductionControl() override = default;
309
310 virtual bool
311 ResidualVectorRequired() const override
312 {
313 return status_test_collection->ResidualVectorRequired();
314 }
315
316 virtual AztecOO_StatusType
317 CheckStatus(int CurrentIter,
318 Epetra_MultiVector *CurrentResVector,
319 double CurrentResNormEst,
320 bool SolutionUpdated) override
321 {
322 // Note: CurrentResNormEst is set to -1.0 if no estimate of the
323 // residual value is available
325 (CurrentResNormEst < 0.0 ? compute_residual(CurrentResVector) :
326 CurrentResNormEst);
327 if (CurrentIter == 0)
329
330 return status_test_collection->CheckStatus(CurrentIter,
331 CurrentResVector,
332 CurrentResNormEst,
333 SolutionUpdated);
334 }
335
336 virtual AztecOO_StatusType
337 GetStatus() const override
338 {
339 return status_test_collection->GetStatus();
340 }
341
342 virtual std::ostream &
343 Print(std::ostream &stream, int indent = 0) const override
344 {
345 return status_test_collection->Print(stream, indent);
346 }
347
348 double
349 get_initial_residual() const
350 {
351 return initial_residual;
352 }
353
354 double
355 get_current_residual() const
356 {
357 return current_residual;
358 }
359
360 private:
363 std::unique_ptr<AztecOO_StatusTestCombo> status_test_collection;
364 std::unique_ptr<AztecOO_StatusTestMaxIters> status_test_max_steps;
365 std::unique_ptr<AztecOO_StatusTestResNorm> status_test_abs_tol;
366 std::unique_ptr<AztecOO_StatusTestResNorm> status_test_rel_tol;
367 };
368
369
370 TrilinosReductionControl::TrilinosReductionControl(
371 const int max_steps,
372 const double tolerance,
373 const double reduction,
374 const Epetra_LinearProblem &linear_problem)
375 : initial_residual(std::numeric_limits<double>::max())
376 , current_residual(std::numeric_limits<double>::max())
377 // Consider linear problem converged if any of the collection of
378 // criterion are met
379 , status_test_collection(std::make_unique<AztecOO_StatusTestCombo>(
380 AztecOO_StatusTestCombo::OR))
381 {
382 // Maximum number of iterations
383 Assert(max_steps >= 0, ExcInternalError());
385 std::make_unique<AztecOO_StatusTestMaxIters>(max_steps);
387
388 Assert(linear_problem.GetRHS()->NumVectors() == 1,
389 ExcMessage("RHS multivector holds more than one vector"));
390
391 // Residual norm is below some absolute value
392 status_test_abs_tol = std::make_unique<AztecOO_StatusTestResNorm>(
393 *linear_problem.GetOperator(),
394 *(linear_problem.GetLHS()->operator()(0)),
395 *(linear_problem.GetRHS()->operator()(0)),
396 tolerance);
397 status_test_abs_tol->DefineResForm(AztecOO_StatusTestResNorm::Explicit,
398 AztecOO_StatusTestResNorm::TwoNorm);
399 status_test_abs_tol->DefineScaleForm(
400 AztecOO_StatusTestResNorm::None, AztecOO_StatusTestResNorm::TwoNorm);
402
403 // Residual norm, scaled by some initial value, is below some threshold
404 status_test_rel_tol = std::make_unique<AztecOO_StatusTestResNorm>(
405 *linear_problem.GetOperator(),
406 *(linear_problem.GetLHS()->operator()(0)),
407 *(linear_problem.GetRHS()->operator()(0)),
408 reduction);
409 status_test_rel_tol->DefineResForm(AztecOO_StatusTestResNorm::Explicit,
410 AztecOO_StatusTestResNorm::TwoNorm);
411 status_test_rel_tol->DefineScaleForm(
412 AztecOO_StatusTestResNorm::NormOfInitRes,
413 AztecOO_StatusTestResNorm::TwoNorm);
415 }
416
417 } // namespace
418 } // namespace internal
419
420
421 template <typename Preconditioner>
422 void
423 SolverBase::do_solve(const Preconditioner &preconditioner)
424 {
425 int ierr;
426
427 // Next we can allocate the AztecOO solver...
428 solver.SetProblem(*linear_problem);
429
430 // ... and we can specify the solver to be used.
431 switch (solver_name)
432 {
433 case cg:
434 solver.SetAztecOption(AZ_solver, AZ_cg);
435 break;
436 case cgs:
437 solver.SetAztecOption(AZ_solver, AZ_cgs);
438 break;
439 case gmres:
440 solver.SetAztecOption(AZ_solver, AZ_gmres);
441 solver.SetAztecOption(AZ_kspace,
442 additional_data.gmres_restart_parameter);
443 break;
444 case bicgstab:
445 solver.SetAztecOption(AZ_solver, AZ_bicgstab);
446 break;
447 case tfqmr:
448 solver.SetAztecOption(AZ_solver, AZ_tfqmr);
449 break;
450 default:
452 }
453
454 // Set the preconditioner
455 set_preconditioner(solver, preconditioner);
456
457 // ... set some options, ...
458 solver.SetAztecOption(AZ_output,
459 additional_data.output_solver_details ? AZ_all :
460 AZ_none);
461 solver.SetAztecOption(AZ_conv, AZ_noscaled);
462
463 // By default, the Trilinos solver chooses convergence criterion based on
464 // the number of iterations made and an absolute tolerance.
465 // This implies that the use of the standard Trilinos convergence test
466 // actually coincides with ::IterationNumberControl because the
467 // solver, unless explicitly told otherwise, will Iterate() until a number
468 // of max_steps() are taken or an absolute tolerance() is attained.
469 // It is therefore suitable for use with both SolverControl or
470 // IterationNumberControl. The final check at the end will determine whether
471 // failure to converge to the defined residual norm constitutes failure
472 // (SolverControl) or is alright (IterationNumberControl).
473 // In the case that the SolverControl wants to perform ReductionControl,
474 // then we have to do a little extra something by prescribing a custom
475 // status test.
476 if (!status_test)
477 {
478 if (const ReductionControl *const reduction_control =
479 dynamic_cast<const ReductionControl *>(&solver_control))
480 {
481 status_test = std::make_unique<internal::TrilinosReductionControl>(
482 reduction_control->max_steps(),
483 reduction_control->tolerance(),
484 reduction_control->reduction(),
485 *linear_problem);
486 solver.SetStatusTest(status_test.get());
487 }
488 }
489
490 // ... and then solve!
491 ierr =
492 solver.Iterate(solver_control.max_steps(), solver_control.tolerance());
493
494 // report errors in more detail than just by checking whether the return
495 // status is zero or greater. the error strings are taken from the
496 // implementation of the AztecOO::Iterate function
497 switch (ierr)
498 {
499 case -1:
500 AssertThrow(false,
501 ExcMessage("AztecOO::Iterate error code -1: "
502 "option not implemented"));
503 break;
504 case -2:
505 AssertThrow(false,
506 ExcMessage("AztecOO::Iterate error code -2: "
507 "numerical breakdown"));
508 break;
509 case -3:
510 AssertThrow(false,
511 ExcMessage("AztecOO::Iterate error code -3: "
512 "loss of precision"));
513 break;
514 case -4:
515 AssertThrow(false,
516 ExcMessage("AztecOO::Iterate error code -4: "
517 "GMRES Hessenberg ill-conditioned"));
518 break;
519 default:
520 AssertThrow(ierr >= 0, ExcTrilinosError(ierr));
521 }
522
523 // Finally, let the deal.II SolverControl object know what has
524 // happened. If the solve succeeded, the status of the solver control will
525 // turn into SolverControl::success.
526 // If the residual is not computed/stored by the solver, as can happen for
527 // certain choices of solver or if a custom status test is set, then the
528 // result returned by TrueResidual() is equal to -1. In this case we must
529 // compute it ourself.
530 if (const internal::TrilinosReductionControl
531 *const reduction_control_status =
532 dynamic_cast<const internal::TrilinosReductionControl *>(
533 status_test.get()))
534 {
535 Assert(dynamic_cast<const ReductionControl *>(&solver_control),
537
538 // Check to see if solver converged in one step
539 // This can happen if the matrix is diagonal and a non-trivial
540 // preconditioner is used.
541 if (solver.NumIters() > 0)
542 {
543 // For ReductionControl, we must first register the initial residual
544 // value. This is the basis from which it will determine whether the
545 // current residual corresponds to a converged state.
546 solver_control.check(
547 0, reduction_control_status->get_initial_residual());
548 solver_control.check(
549 solver.NumIters(),
550 reduction_control_status->get_current_residual());
551 }
552 else
553 solver_control.check(
554 solver.NumIters(),
555 reduction_control_status->get_current_residual());
556 }
557 else
558 {
559 Assert(solver.TrueResidual() >= 0.0, ExcInternalError());
560 solver_control.check(solver.NumIters(), solver.TrueResidual());
561 }
562
563 if (solver_control.last_check() != SolverControl::success)
564 AssertThrow(false,
565 SolverControl::NoConvergence(solver_control.last_step(),
566 solver_control.last_value()));
567 }
568
569
570
571 template <>
572 void
573 SolverBase::set_preconditioner(AztecOO &solver,
574 const PreconditionBase &preconditioner)
575 {
576 // Introduce the preconditioner, if the identity preconditioner is used,
577 // the precondioner is set to none, ...
578 if (preconditioner.preconditioner.strong_count() != 0)
579 {
580 const int ierr = solver.SetPrecOperator(
581 const_cast<Epetra_Operator *>(preconditioner.preconditioner.get()));
582 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
583 }
584 else
585 solver.SetAztecOption(AZ_precond, AZ_none);
586 }
587
588
589 template <>
590 void
591 SolverBase::set_preconditioner(AztecOO &solver,
592 const Epetra_Operator &preconditioner)
593 {
594 const int ierr =
595 solver.SetPrecOperator(const_cast<Epetra_Operator *>(&preconditioner));
596 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
597 }
598
599
600 /* ---------------------- SolverCG ------------------------ */
601
605
606
607 /* ---------------------- SolverGMRES ------------------------ */
608
612
613
614 /* ---------------------- SolverBicgstab ------------------------ */
615
619
620
621 /* ---------------------- SolverCGS ------------------------ */
622
626
627
628 /* ---------------------- SolverTFQMR ------------------------ */
629
633
634
635
636 /* ---------------------- SolverDirect ------------------------ */
637
638 SolverDirect::AdditionalData::AdditionalData(const bool output_solver_details,
639 const std::string &solver_type)
640 : output_solver_details(output_solver_details)
641 , solver_type(solver_type)
642 {}
643
644
645
648 , additional_data(data.output_solver_details, data.solver_type)
649 {}
650
651
652
654 : solver_control(cn)
655 , additional_data(data.output_solver_details, data.solver_type)
656 {}
657
658
659
662 {
663 return solver_control;
664 }
665
666
667
668 void
670 {
671 // We need an Epetra_LinearProblem object to let the Amesos solver know
672 // about the matrix and vectors.
673 linear_problem = std::make_unique<Epetra_LinearProblem>();
674
675 // Assign the matrix operator to the Epetra_LinearProblem object
676 linear_problem->SetOperator(
677 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()));
678
679 // Fetch return value of Amesos Solver functions
680 int ierr;
681
682 // First set whether we want to print the solver information to screen or
683 // not.
684 ConditionalOStream verbose_cout(std::cout,
686
687 // Next allocate the Amesos solver, this is done in two steps, first we
688 // create a solver Factory and generate with that the concrete Amesos
689 // solver, if possible.
690 Amesos Factory;
691
692 AssertThrow(Factory.Query(additional_data.solver_type.c_str()),
694 "You tried to select the solver type <" +
696 "> but this solver is not supported by Trilinos either "
697 "because it does not exist, or because Trilinos was not "
698 "configured for its use."));
699
700 solver.reset(
701 Factory.Create(additional_data.solver_type.c_str(), *linear_problem));
702
703 verbose_cout << "Starting symbolic factorization" << std::endl;
704 ierr = solver->SymbolicFactorization();
705 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
706
707 verbose_cout << "Starting numeric factorization" << std::endl;
708 ierr = solver->NumericFactorization();
709 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
710 }
711
712
713
714 void
716 {
717 this->additional_data = data;
718
719 this->initialize(A);
720 }
721
722
723 void
725 {
726 this->vmult(x, b);
727 }
728
729
730
731 void
734 const ::LinearAlgebra::distributed::Vector<double> &b)
735 {
736 this->vmult(x, b);
737 }
738
739
740 void
742 {
743 // Assign the empty LHS vector to the Epetra_LinearProblem object
744 linear_problem->SetLHS(&x.trilinos_vector());
745
746 // Assign the RHS vector to the Epetra_LinearProblem object
747 linear_problem->SetRHS(
748 const_cast<Epetra_MultiVector *>(&b.trilinos_vector()));
749
750 // First set whether we want to print the solver information to screen or
751 // not.
752 ConditionalOStream verbose_cout(std::cout,
754
755
756 verbose_cout << "Starting solve" << std::endl;
757
758 // Fetch return value of Amesos Solver functions
759 int ierr = solver->Solve();
760 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
761
762 // Finally, force the SolverControl object to report convergence
763 solver_control.check(0, 0);
764 }
765
766
767
768 void
771 const ::LinearAlgebra::distributed::Vector<double> &b) const
772 {
773 Epetra_Vector ep_x(View,
774 linear_problem->GetOperator()->OperatorDomainMap(),
775 x.begin());
776 Epetra_Vector ep_b(View,
777 linear_problem->GetOperator()->OperatorRangeMap(),
778 const_cast<double *>(b.begin()));
779
780 // Assign the empty LHS vector to the Epetra_LinearProblem object
781 linear_problem->SetLHS(&ep_x);
782
783 // Assign the RHS vector to the Epetra_LinearProblem object
784 linear_problem->SetRHS(&ep_b);
785
786 // First set whether we want to print the solver information to screen or
787 // not.
788 ConditionalOStream verbose_cout(std::cout,
790
791 verbose_cout << "Starting solve" << std::endl;
792
793 // Fetch return value of Amesos Solver functions
794 int ierr = solver->Solve();
795 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
796
797 // Finally, force the SolverControl object to report convergence
798 solver_control.check(0, 0);
799 }
800
801
802
803 void
805 {
806 // Fetch return value of Amesos Solver functions
807 int ierr;
808
809 // First set whether we want to print the solver information to screen or
810 // not.
811 ConditionalOStream verbose_cout(std::cout,
813
814 // Next allocate the Amesos solver, this is done in two steps, first we
815 // create a solver Factory and generate with that the concrete Amesos
816 // solver, if possible.
817 Amesos Factory;
818
819 AssertThrow(Factory.Query(additional_data.solver_type.c_str()),
821 "You tried to select the solver type <" +
823 "> but this solver is not supported by Trilinos either "
824 "because it does not exist, or because Trilinos was not "
825 "configured for its use."));
826
827 solver.reset(
828 Factory.Create(additional_data.solver_type.c_str(), *linear_problem));
829
830 verbose_cout << "Starting symbolic factorization" << std::endl;
831 ierr = solver->SymbolicFactorization();
832 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
833
834 verbose_cout << "Starting numeric factorization" << std::endl;
835 ierr = solver->NumericFactorization();
836 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
837
838 verbose_cout << "Starting solve" << std::endl;
839 ierr = solver->Solve();
840 AssertThrow(ierr == 0, ExcTrilinosError(ierr));
841
842 // Finally, let the deal.II SolverControl object know what has
843 // happened. If the solve succeeded, the status of the solver control will
844 // turn into SolverControl::success.
845 solver_control.check(0, 0);
846
848 AssertThrow(false,
851 }
852
853
854 void
856 Epetra_MultiVector &x,
857 const Epetra_MultiVector &b)
858 {
859 // We need an Epetra_LinearProblem object to let the Amesos solver know
860 // about the matrix and vectors.
862 std::make_unique<Epetra_LinearProblem>(const_cast<Epetra_Operator *>(&A),
863 &x,
864 const_cast<Epetra_MultiVector *>(
865 &b));
866
867 do_solve();
868 }
869
870
871 void
872 SolverDirect::solve(const SparseMatrix &sparse_matrix,
873 FullMatrix<double> &solution,
874 const FullMatrix<double> &rhs)
875 {
876 Assert(sparse_matrix.m() == sparse_matrix.n(), ExcInternalError());
877 Assert(rhs.m() == sparse_matrix.m(), ExcInternalError());
878 Assert(rhs.m() == solution.m(), ExcInternalError());
879 Assert(rhs.n() == solution.n(), ExcInternalError());
880
881 const unsigned int m = rhs.m();
882 const unsigned int n = rhs.n();
883
884 FullMatrix<double> rhs_t(n, m);
885 FullMatrix<double> solution_t(n, m);
886
887 rhs_t.copy_transposed(rhs);
888 solution_t.copy_transposed(solution);
889
890 std::vector<double *> rhs_ptrs(n);
891 std::vector<double *> sultion_ptrs(n);
892
893 for (unsigned int i = 0; i < n; ++i)
894 {
895 rhs_ptrs[i] = &rhs_t[i][0];
896 sultion_ptrs[i] = &solution_t[i][0];
897 }
898
899 const Epetra_CrsMatrix &mat = sparse_matrix.trilinos_matrix();
900
901 Epetra_MultiVector trilinos_dst(View,
902 mat.OperatorRangeMap(),
903 sultion_ptrs.data(),
904 sultion_ptrs.size());
905 Epetra_MultiVector trilinos_src(View,
906 mat.OperatorDomainMap(),
907 rhs_ptrs.data(),
908 rhs_ptrs.size());
909
910 this->initialize(sparse_matrix);
911 this->solve(mat, trilinos_dst, trilinos_src);
912
913 solution.copy_transposed(solution_t);
914 }
915
916
917 void
919 MPI::Vector &x,
920 const MPI::Vector &b)
921 {
922 // We need an Epetra_LinearProblem object to let the Amesos solver know
923 // about the matrix and vectors.
924 linear_problem = std::make_unique<Epetra_LinearProblem>(
925 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()),
926 &x.trilinos_vector(),
927 const_cast<Epetra_MultiVector *>(&b.trilinos_vector()));
928
929 do_solve();
930 }
931
932
933
934 void
937 const ::Vector<double> &b)
938 {
939 // In case we call the solver with deal.II vectors, we create views of the
940 // vectors in Epetra format.
941 Assert(x.size() == A.n(), ExcDimensionMismatch(x.size(), A.n()));
942 Assert(b.size() == A.m(), ExcDimensionMismatch(b.size(), A.m()));
943 Assert(A.local_range().second == A.m(),
944 ExcMessage("Can only work in serial when using deal.II vectors."));
945 Epetra_Vector ep_x(View, A.trilinos_matrix().DomainMap(), x.begin());
946 Epetra_Vector ep_b(View,
947 A.trilinos_matrix().RangeMap(),
948 const_cast<double *>(b.begin()));
949
950 // We need an Epetra_LinearProblem object to let the Amesos solver know
951 // about the matrix and vectors.
952 linear_problem = std::make_unique<Epetra_LinearProblem>(
953 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()), &ep_x, &ep_b);
954
955 do_solve();
956 }
957
958
959
960 void
962 const SparseMatrix &A,
964 const ::LinearAlgebra::distributed::Vector<double> &b)
965 {
967 A.trilinos_matrix().DomainMap().NumMyElements());
968 AssertDimension(b.locally_owned_size(),
969 A.trilinos_matrix().RangeMap().NumMyElements());
970 Epetra_Vector ep_x(View, A.trilinos_matrix().DomainMap(), x.begin());
971 Epetra_Vector ep_b(View,
972 A.trilinos_matrix().RangeMap(),
973 const_cast<double *>(b.begin()));
974
975 // We need an Epetra_LinearProblem object to let the Amesos solver know
976 // about the matrix and vectors.
977 linear_problem = std::make_unique<Epetra_LinearProblem>(
978 const_cast<Epetra_CrsMatrix *>(&A.trilinos_matrix()), &ep_x, &ep_b);
979
980 do_solve();
981 }
982} // namespace TrilinosWrappers
983
984
985// explicit instantiations
986// TODO: put these instantiations into generic file
987namespace TrilinosWrappers
988{
989 template void
990 SolverBase::do_solve(const PreconditionBase &preconditioner);
991
992 template void
993 SolverBase::do_solve(const Epetra_Operator &preconditioner);
994} // namespace TrilinosWrappers
995
996
997#endif // DEAL_II_TRILINOS_WITH_EPETRA
size_type n() const
void copy_transposed(const MatrixType &)
size_type m() const
size_type locally_owned_size() const
SolverCG(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
State last_check() const
unsigned int last_step() const
double last_value() const
virtual State check(const unsigned int step, const double check_value)
@ success
Stop iteration, goal reached.
const Epetra_MultiVector & trilinos_vector() const
Teuchos::RCP< Epetra_Operator > preconditioner
SolverControl & control() const
void solve(const SparseMatrix &A, MPI::Vector &x, const MPI::Vector &b, const PreconditionBase &preconditioner)
const AdditionalData additional_data
void do_solve(const Preconditioner &preconditioner)
std::unique_ptr< Epetra_LinearProblem > linear_problem
SolverBase(SolverControl &cn, const AdditionalData &data=AdditionalData())
enum TrilinosWrappers::SolverBase::SolverName solver_name
SolverBicgstab(SolverControl &cn, const AdditionalData &data=AdditionalData())
SolverCGS(SolverControl &cn, const AdditionalData &data=AdditionalData())
void initialize(const SparseMatrix &A)
void vmult(MPI::Vector &x, const MPI::Vector &b) const
std::unique_ptr< Amesos_BaseSolver > solver
void solve(MPI::Vector &x, const MPI::Vector &b)
std::unique_ptr< Epetra_LinearProblem > linear_problem
SolverControl & control() const
SolverDirect(const AdditionalData &data=AdditionalData())
SolverGMRES(SolverControl &cn, const AdditionalData &data=AdditionalData())
SolverTFQMR(SolverControl &cn, const AdditionalData &data=AdditionalData())
const Epetra_CrsMatrix & trilinos_matrix() const
virtual size_type size() const override
iterator begin()
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition config.h:636
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition config.h:680
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcTrilinosError(int arg1)
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcTrilinosError(int arg1)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::vector< index_type > data
Definition mpi.cc:734
STL namespace.
AdditionalData(const bool output_solver_details=false, const unsigned int gmres_restart_parameter=30)
AdditionalData(const bool output_solver_details=false, const std::string &solver_type="Amesos_Klu")
double initial_residual
std::unique_ptr< AztecOO_StatusTestResNorm > status_test_abs_tol
std::unique_ptr< AztecOO_StatusTestResNorm > status_test_rel_tol
std::unique_ptr< AztecOO_StatusTestMaxIters > status_test_max_steps
std::unique_ptr< AztecOO_StatusTestCombo > status_test_collection
double current_residual
double TrilinosScalar
Definition types.h:188