deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20: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
petsc_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) 2004 - 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
13
15
17
18#ifdef DEAL_II_WITH_PETSC
19
25
26// Shorthand notation for PETSc error codes.
27# define AssertPETSc(code) \
28 do \
29 { \
30 PetscErrorCode ierr = (code); \
31 AssertThrow(ierr == 0, ExcPETScError(ierr)); \
32 } \
33 while (false)
34
35
36#endif // DEAL_II_WITH_PETSC
37
39
40#ifdef DEAL_II_WITH_PETSC
41
42namespace PETScWrappers
43{
45 : ksp(nullptr)
46 , solver_control(nullptr)
47 {}
48
49
51 : ksp(nullptr)
52 , solver_control(&cn)
53 {}
54
55
56
57 void
59 {}
60
61
62
64 {
65 AssertPETSc(KSPDestroy(&ksp));
66 }
67
68
69
70 KSP
72 {
73 return ksp;
74 }
75
76
77
78 SolverBase::operator KSP() const
79 {
80 return ksp;
81 }
82
83
84
85 void
87 VectorBase &x,
88 const VectorBase &b,
89 const PreconditionBase &preconditioner)
90 {
91 // first create a solver object if this
92 // is necessary
93 if (ksp == nullptr)
94 {
95 initialize_ksp_with_comm(A.get_mpi_communicator());
96
97 // let derived classes set the solver
98 // type, and the preconditioning
99 // object set the type of
100 // preconditioner
102
103 AssertPETSc(KSPSetPC(ksp, preconditioner.get_pc()));
104
105 /*
106 * by default we set up the preconditioner only once.
107 * this can be overridden by command line.
108 */
109 AssertPETSc(KSPSetReusePreconditioner(ksp, PETSC_TRUE));
110 }
111
112 // setting the preconditioner overwrites the used matrices.
113 // hence, we need to set the matrices after the preconditioner.
114 Mat B;
115 AssertPETSc(KSPGetOperators(ksp, nullptr, &B));
116 AssertPETSc(KSPSetOperators(ksp, A, B));
117
118 // set the command line option prefix name
119 AssertPETSc(KSPSetOptionsPrefix(ksp, prefix_name.c_str()));
120
121 // set the command line options provided
122 // by the user to override the defaults
123 AssertPETSc(KSPSetFromOptions(ksp));
124
125 // then do the real work: set up solver
126 // internal data and solve the
127 // system.
128 AssertPETSc(KSPSetUp(ksp));
129
130 AssertPETSc(KSPSolve(ksp, b, x));
131
132 // in case of failure: throw
133 // exception
134 if (solver_control &&
135 solver_control->last_check() != SolverControl::success)
136 AssertThrow(false,
138 solver_control->last_value()));
139 // otherwise exit as normal
140 }
141
142
143 void
144 SolverBase::set_prefix(const std::string &prefix)
145 {
146 prefix_name = prefix;
147 }
148
149
150 void
152 {
153 AssertPETSc(KSPDestroy(&ksp));
154 }
155
156
159 {
163 "You need to create the solver with a SolverControl object if you want to call the function that returns it."));
164 return *solver_control;
165 }
166
167
168 PetscErrorCode
170 const PetscInt iteration,
171 const PetscReal residual_norm,
172 KSPConvergedReason *reason,
173 void *solver_control_x)
174 {
175 PetscFunctionBeginUser;
177 *reinterpret_cast<SolverControl *>(solver_control_x);
178
179 const SolverControl::State state =
180 solver_control.check(iteration, residual_norm);
181
182 switch (state)
183 {
184 case ::SolverControl::iterate:
185 *reason = KSP_CONVERGED_ITERATING;
186 break;
187
188 case ::SolverControl::success:
189 *reason = KSP_CONVERGED_RTOL;
190 break;
191
192 case ::SolverControl::failure:
193 if (solver_control.last_step() > solver_control.max_steps())
194 *reason = KSP_DIVERGED_ITS;
195 else
196 *reason = KSP_DIVERGED_DTOL;
197 break;
198
199 default:
201 }
202
203 PetscFunctionReturn(PETSC_SUCCESS);
204 }
205
206
207
208 void
210 {
211 // Create the PETSc KSP object
212 AssertPETSc(KSPCreate(comm, &ksp));
213
214 // then a convergence monitor
215 // function that simply
216 // checks with the solver_control
217 // object we have in this object for
218 // convergence
220 }
221
222
223
224 void
226 {
227 if (ksp && solver_control)
229 KSPSetConvergenceTest(ksp, &convergence_test, solver_control, nullptr));
230 }
231
232
233 void
235 {
237
238 // let derived classes set the solver
239 // type, and the preconditioning
240 // object set the type of
241 // preconditioner
243
244 // set the command line options provided
245 // by the user to override the defaults
246 AssertPETSc(KSPSetFromOptions(ksp));
247 }
248
249
250
251 /* ---------------------- SolverRichardson ------------------------ */
252
254 : omega(omega)
255 {}
256
257
258
264
265
266
267 void
269 {
270 AssertPETSc(KSPSetType(ksp, KSPRICHARDSON));
271
272 // set the damping factor from the data
273 AssertPETSc(KSPRichardsonSetScale(ksp, additional_data.omega));
274
275 // in the deal.II solvers, we always
276 // honor the initial guess in the
277 // solution vector. do so here as well:
278 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
279
280 // Hand over the absolute
281 // tolerance and the maximum
282 // iteration number to the PETSc
283 // convergence criterion. The
284 // custom deal.II SolverControl
285 // object is ignored by the PETSc
286 // Richardson method (when no
287 // PETSc monitoring is present),
288 // since in this case PETSc
289 // uses a faster version of
290 // the Richardson iteration,
291 // where no residual is
292 // available.
293 AssertPETSc(KSPSetTolerances(ksp,
294 PETSC_DEFAULT,
295 this->solver_control->tolerance(),
296 PETSC_DEFAULT,
297 this->solver_control->max_steps() + 1));
298 }
299
300
301 /* ---------------------- SolverChebychev ------------------------ */
302
304 const AdditionalData &data)
305 : SolverBase(cn)
306 , additional_data(data)
307 {}
308
309
310 void
312 {
313 AssertPETSc(KSPSetType(ksp, KSPCHEBYSHEV));
314
315 // in the deal.II solvers, we always
316 // honor the initial guess in the
317 // solution vector. do so here as well:
318 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
319 }
320
321
322 /* ---------------------- SolverCG ------------------------ */
323
325 : SolverBase(cn)
326 , additional_data(data)
327 {}
328
329
330 void
332 {
333 AssertPETSc(KSPSetType(ksp, KSPCG));
334
335 // in the deal.II solvers, we always
336 // honor the initial guess in the
337 // solution vector. do so here as well:
338 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
339
340 // Use the unpreconditioned residual norm for the convergence check, to
341 // match the behavior of deal.II's own SolverCG. Users can still override
342 // this via the -ksp_norm_type command-line option.
343 AssertPETSc(KSPSetNormType(ksp, KSP_NORM_UNPRECONDITIONED));
344 }
345
346
347 /* ---------------------- SolverBiCG ------------------------ */
348
350 : SolverBase(cn)
351 , additional_data(data)
352 {}
353
354
355
356 void
358 {
359 AssertPETSc(KSPSetType(ksp, KSPBICG));
360
361 // in the deal.II solvers, we always
362 // honor the initial guess in the
363 // solution vector. do so here as well:
364 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
365 }
366
367
368 /* ---------------------- SolverGMRES ------------------------ */
369
371 const unsigned int restart_parameter,
372 const bool right_preconditioning)
373 : restart_parameter(restart_parameter)
374 , right_preconditioning(right_preconditioning)
375 {}
376
377
378
383
384
385
386 void
388 {
389 AssertPETSc(KSPSetType(ksp, KSPGMRES));
390
391 AssertPETSc(KSPGMRESSetRestart(ksp, additional_data.restart_parameter));
392
393 // Set preconditioning side to right
395 {
396 AssertPETSc(KSPSetPCSide(ksp, PC_RIGHT));
397 }
398
399 // in the deal.II solvers, we always
400 // honor the initial guess in the
401 // solution vector. do so here as well:
402 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
403 }
404
405
406 /* ---------------------- SolverBicgstab ------------------------ */
407
409 : SolverBase(cn)
410 , additional_data(data)
411 {}
412
413
414 void
416 {
417 AssertPETSc(KSPSetType(ksp, KSPBCGS));
418
419 // in the deal.II solvers, we always
420 // honor the initial guess in the
421 // solution vector. do so here as well:
422 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
423 }
424
425
426 /* ---------------------- SolverCGS ------------------------ */
427
429 : SolverBase(cn)
430 , additional_data(data)
431 {}
432
433
434 void
436 {
437 AssertPETSc(KSPSetType(ksp, KSPCGS));
438
439 // in the deal.II solvers, we always
440 // honor the initial guess in the
441 // solution vector. do so here as well:
442 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
443 }
444
445
446 /* ---------------------- SolverTFQMR ------------------------ */
447
449 : SolverBase(cn)
450 , additional_data(data)
451 {}
452
453
454 void
456 {
457 AssertPETSc(KSPSetType(ksp, KSPTFQMR));
458
459 // in the deal.II solvers, we always
460 // honor the initial guess in the
461 // solution vector. do so here as well:
462 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
463 }
464
465
466 /* ---------------------- SolverTCQMR ------------------------ */
467
469 : SolverBase(cn)
470 , additional_data(data)
471 {}
472
473
474 void
476 {
477 AssertPETSc(KSPSetType(ksp, KSPTCQMR));
478
479 // in the deal.II solvers, we always
480 // honor the initial guess in the
481 // solution vector. do so here as well:
482 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
483 }
484
485
486 /* ---------------------- SolverCR ------------------------ */
487
489 : SolverBase(cn)
490 , additional_data(data)
491 {}
492
493
494 void
496 {
497 AssertPETSc(KSPSetType(ksp, KSPCR));
498
499 // in the deal.II solvers, we always
500 // honor the initial guess in the
501 // solution vector. do so here as well:
502 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
503 }
504
505
506 /* ---------------------- SolverLSQR ------------------------ */
507
509 : SolverBase(cn)
510 , additional_data(data)
511 {}
512
513
514
515 void
517 {
518 AssertPETSc(KSPSetType(ksp, KSPLSQR));
519
520 // in the deal.II solvers, we always
521 // honor the initial guess in the
522 // solution vector. do so here as well:
523 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
524
525 // The KSPLSQR implementation overwrites the user-defined
526 // convergence test at creation (i.e. KSPSetType) time.
527 // This is probably a bad design decision in PETSc.
528 // Anyway, here we make sure we use our own convergence
529 // test.
531 }
532
533
534 /* ---------------------- SolverPreOnly ------------------------ */
535
537 : SolverBase(cn)
538 , additional_data(data)
539 {}
540
541
542
543 void
545 {
546 AssertPETSc(KSPSetType(ksp, KSPPREONLY));
547
548 // The KSPPREONLY solver of
549 // PETSc never calls the convergence
550 // monitor, which leads to failure
551 // even when everything was ok.
552 // Therefore the SolverControl status
553 // is set to some nice values, which
554 // guarantee a nice result at the end
555 // of the solution process.
556 solver_control->check(1, 0.0);
557
558 // Using the PREONLY solver with
559 // a nonzero initial guess leads
560 // PETSc to produce some error messages.
561 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_FALSE));
562 }
563
564
565 /* ---------------------- SparseDirectMUMPS------------------------ */
566
568 const AdditionalData &data)
569 : SolverBase(cn)
570 , additional_data(data)
571 , symmetric_mode(false)
572 {}
573
574
575
576 void
578 {
579 /*
580 * KSPPREONLY implements a stub method that applies only the
581 * preconditioner. Its use is due to SparseDirectMUMPS being a direct
582 * (rather than iterative) solver
583 */
584 AssertPETSc(KSPSetType(ksp, KSPPREONLY));
585
586 /*
587 * The KSPPREONLY solver of PETSc never calls the convergence monitor,
588 * which leads to failure even when everything was ok. Therefore, the
589 * SolverControl status is set to some nice values, which guarantee a
590 * nice result at the end of the solution process.
591 */
592 solver_control->check(1, 0.0);
593
594 /*
595 * Using a PREONLY solver with a nonzero initial guess leads PETSc to
596 * produce some error messages.
597 */
598 AssertPETSc(KSPSetInitialGuessNonzero(ksp, PETSC_FALSE));
599 }
600
601 void
603 VectorBase &x,
604 const VectorBase &b)
605 {
606# ifdef DEAL_II_PETSC_WITH_MUMPS
607 /*
608 * creating a solver object if this is necessary
609 */
610 if (ksp == nullptr)
611 {
612 initialize_ksp_with_comm(A.get_mpi_communicator());
613
614 /*
615 * setting the solver type
616 */
618
619 /*
620 * set the matrices involved. the last argument is irrelevant here,
621 * since we use the solver only once anyway
622 */
623 AssertPETSc(KSPSetOperators(ksp, A, A));
624
625 /*
626 * getting the associated preconditioner context
627 */
628 PC pc;
629 AssertPETSc(KSPGetPC(ksp, &pc));
630
631 /*
632 * build PETSc PC for particular PCLU or PCCHOLESKY preconditioner
633 * depending on whether the symmetric mode has been set
634 */
635 if (symmetric_mode)
636 AssertPETSc(PCSetType(pc, PCCHOLESKY));
637 else
638 AssertPETSc(PCSetType(pc, PCLU));
639
640 /*
641 * set the software that is to be used to perform the lu
642 * factorization here we start to see differences with the base
643 * class solve function
644 */
645# if DEAL_II_PETSC_VERSION_LT(3, 9, 0)
646 AssertPETSc(PCFactorSetMatSolverPackage(pc, MATSOLVERMUMPS));
647# else
648 AssertPETSc(PCFactorSetMatSolverType(pc, MATSOLVERMUMPS));
649# endif
650
651 /*
652 * set up the package to call for the factorization
653 */
654# if DEAL_II_PETSC_VERSION_LT(3, 9, 0)
655 AssertPETSc(PCFactorSetUpMatSolverPackage(pc));
656# else
657 AssertPETSc(PCFactorSetUpMatSolverType(pc));
658# endif
659
660 /*
661 * get the factored matrix F from the preconditioner context.
662 */
663 Mat F;
664 AssertPETSc(PCFactorGetMatrix(pc, &F));
665
666 /*
667 * pass control parameters to MUMPS.
668 * Setting entry 7 of MUMPS ICNTL array to a value
669 * of 2. This sets use of Approximate Minimum Fill (AMF)
670 */
671 AssertPETSc(MatMumpsSetIcntl(F, 7, 2));
672
673 /*
674 * by default we set up the preconditioner only once.
675 * this can be overridden by command line.
676 */
677 AssertPETSc(KSPSetReusePreconditioner(ksp, PETSC_TRUE));
678 }
679
680 /*
681 * set the matrices involved. the last argument is irrelevant here,
682 * since we use the solver only once anyway
683 */
684 AssertPETSc(KSPSetOperators(ksp, A, A));
685
686 /*
687 * set the command line option prefix name
688 */
689 AssertPETSc(KSPSetOptionsPrefix(ksp, prefix_name.c_str()));
690
691 /*
692 * set the command line options provided by the user to override
693 * the defaults
694 */
695 AssertPETSc(KSPSetFromOptions(ksp));
696
697 /*
698 * solve the linear system
699 */
700 AssertPETSc(KSPSolve(ksp, b, x));
701
702 /*
703 * in case of failure throw exception
704 */
705 if (solver_control &&
706 solver_control->last_check() != SolverControl::success)
707 {
708 AssertThrow(false,
710 solver_control->last_value()));
711 }
712
713# else // DEAL_II_PETSC_WITH_MUMPS
714 Assert(
715 false,
717 "Your PETSc installation does not include a copy of "
718 "the MUMPS package necessary for this solver. You will need to configure "
719 "PETSc so that it includes MUMPS, recompile it, and then re-configure "
720 "and recompile deal.II as well."));
721 (void)A;
722 (void)x;
723 (void)b;
724# endif
725 }
726
727
728
729 void
730 SparseDirectMUMPS::set_symmetric_mode(const bool matrix_is_symmetric)
731 {
732 symmetric_mode = matrix_is_symmetric;
733 }
734
735} // namespace PETScWrappers
736
737
738#endif // DEAL_II_WITH_PETSC
SolverControl & control() const
ObserverPointer< SolverControl, SolverBase > solver_control
void initialize(const PreconditionBase &preconditioner)
void perhaps_set_convergence_test() const
static PetscErrorCode convergence_test(KSP ksp, const PetscInt iteration, const PetscReal residual_norm, KSPConvergedReason *reason, void *solver_control)
void set_prefix(const std::string &prefix)
void initialize_ksp_with_comm(const MPI_Comm comm)
void solve(const MatrixBase &A, VectorBase &x, const VectorBase &b, const PreconditionBase &preconditioner)
virtual void set_solver_type(KSP &ksp) const
SolverBiCG(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
virtual void set_solver_type(KSP &ksp) const override
SolverBicgstab(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
SolverCGS(SolverControl &cn, const AdditionalData &data=AdditionalData())
SolverCG(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
virtual void set_solver_type(KSP &ksp) const override
SolverCR(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
SolverChebychev(SolverControl &cn, const AdditionalData &data=AdditionalData())
const AdditionalData additional_data
virtual void set_solver_type(KSP &ksp) const override
SolverGMRES(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
SolverLSQR(SolverControl &cn, const AdditionalData &data=AdditionalData())
SolverPreOnly(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
virtual void set_solver_type(KSP &ksp) const override
const AdditionalData additional_data
SolverRichardson(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
SolverTCQMR(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
SolverTFQMR(SolverControl &cn, const AdditionalData &data=AdditionalData())
void solve(const MatrixBase &A, VectorBase &x, const VectorBase &b)
SparseDirectMUMPS(SolverControl &cn, const AdditionalData &data=AdditionalData())
virtual void set_solver_type(KSP &ksp) const override
void set_symmetric_mode(const bool matrix_is_symmetric)
virtual State check(const unsigned int step, const double check_value)
@ success
Stop iteration, goal reached.
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
#define Assert(cond, exc)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::vector< index_type > data
Definition mpi.cc:734
const MPI_Comm comm
Definition mpi.cc:912
#define AssertPETSc(code)
AdditionalData(const unsigned int restart_parameter=30, const bool right_preconditioning=false)