deal.II version GIT relicensing-6963-gc25d64af46 2026-10-23 04:50: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_precondition.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
14
15#ifdef DEAL_II_WITH_PETSC
16
18
24
25# include <petscconf.h>
26
27# include <cmath>
28
29
30#endif // DEAL_II_WITH_PETSC
31
33
34#ifdef DEAL_II_WITH_PETSC
35
36namespace PETScWrappers
37{
43
45 : pc(nullptr)
46 {}
47
49 {
50 try
51 {
52 clear();
53 }
54 catch (...)
55 {}
56 }
57
58 void
60 {
61 if (pc)
62 {
63 PetscErrorCode ierr = PCDestroy(&pc);
64 AssertThrow(ierr == 0, ExcPETScError(ierr));
65 }
66 }
67
68 void
70 {
72
73 PetscErrorCode ierr = PCApply(pc, src, dst);
74 AssertThrow(ierr == 0, ExcPETScError(ierr));
75 }
76
77 void
79 {
81
82 PetscErrorCode ierr = PCApplyTranspose(pc, src, dst);
83 AssertThrow(ierr == 0, ExcPETScError(ierr));
84 }
85
86 void
88 {
90
91 PetscErrorCode ierr = PCSetUp(pc);
92 AssertThrow(ierr == 0, ExcPETScError(ierr));
93 }
94
97 {
98 return PetscObjectComm(reinterpret_cast<PetscObject>(pc));
99 }
100
101 void
103 {
104 // only allow the creation of the
105 // preconditioner once
107
109 PetscErrorCode ierr = PetscObjectGetComm(
110 reinterpret_cast<PetscObject>(static_cast<const Mat &>(matrix)), &comm);
111 AssertThrow(ierr == 0, ExcPETScError(ierr));
112
114
115 ierr = PCSetOperators(pc, matrix, matrix);
116 AssertThrow(ierr == 0, ExcPETScError(ierr));
117 }
118
119 void
121 {
122 clear();
123 PetscErrorCode ierr = PCCreate(comm, &pc);
124 AssertThrow(ierr == 0, ExcPETScError(ierr));
125 }
126
127 const PC &
129 {
130 return pc;
131 }
132
133
134 /* ----------------- PreconditionJacobi -------------------- */
135
139
140
141
143 const AdditionalData &additional_data_)
145 {
146 additional_data = additional_data_;
147
148 PetscErrorCode ierr = PCCreate(comm, &pc);
149 AssertThrow(ierr == 0, ExcPETScError(ierr));
150
151 initialize();
152 }
153
154
155
157 const AdditionalData &additional_data)
158 : PreconditionBase(matrix.get_mpi_communicator())
159 {
161 }
162
163
164
165 void
167 {
169
170 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCJACOBI));
171 AssertThrow(ierr == 0, ExcPETScError(ierr));
172
173 ierr = PCSetFromOptions(pc);
174 AssertThrow(ierr == 0, ExcPETScError(ierr));
175 }
176
177
178
179 void
181 const AdditionalData &additional_data_)
182 {
183 clear();
184
185 additional_data = additional_data_;
186
187 create_pc_with_mat(matrix_);
188 initialize();
189 }
190
191
192 /* ----------------- PreconditionBlockJacobi -------------------- */
193
197
199 const MPI_Comm comm,
200 const AdditionalData &additional_data_)
202 {
203 additional_data = additional_data_;
204
205 PetscErrorCode ierr = PCCreate(comm, &pc);
206 AssertThrow(ierr == 0, ExcPETScError(ierr));
207
208 initialize();
209 }
210
211
212
214 const MatrixBase &matrix,
215 const AdditionalData &additional_data)
216 : PreconditionBase(matrix.get_mpi_communicator())
217 {
219 }
220
221
222
223 void
225 {
226 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCBJACOBI));
227 AssertThrow(ierr == 0, ExcPETScError(ierr));
228
229 ierr = PCSetFromOptions(pc);
230 AssertThrow(ierr == 0, ExcPETScError(ierr));
231 }
232
233
234
235 void
237 const AdditionalData &additional_data_)
238 {
239 clear();
240
241 additional_data = additional_data_;
242
243 create_pc_with_mat(matrix_);
244 initialize();
245 }
246
247
248 /* ----------------- PreconditionSOR -------------------- */
249
253
254
255
257 : omega(omega)
258 {}
259
260
261
268
269
270 void
272 const AdditionalData &additional_data_)
273 {
274 clear();
275
276 additional_data = additional_data_;
277
278 create_pc_with_mat(matrix_);
279
280 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCSOR));
281 AssertThrow(ierr == 0, ExcPETScError(ierr));
282
283 // then set flags as given
284 ierr = PCSORSetOmega(pc, additional_data.omega);
285 AssertThrow(ierr == 0, ExcPETScError(ierr));
286
287 ierr = PCSetFromOptions(pc);
288 AssertThrow(ierr == 0, ExcPETScError(ierr));
289 }
290
291
292 /* ----------------- PreconditionSSOR -------------------- */
293
297
298
299
301 : omega(omega)
302 {}
303
304
305
312
313
314 void
316 const AdditionalData &additional_data_)
317 {
318 clear();
319
320 additional_data = additional_data_;
321
322 create_pc_with_mat(matrix_);
323
324 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCSOR));
325 AssertThrow(ierr == 0, ExcPETScError(ierr));
326
327 // then set flags as given
328 ierr = PCSORSetOmega(pc, additional_data.omega);
329 AssertThrow(ierr == 0, ExcPETScError(ierr));
330
331 // convert SOR to SSOR
332 ierr = PCSORSetSymmetric(pc, SOR_SYMMETRIC_SWEEP);
333 AssertThrow(ierr == 0, ExcPETScError(ierr));
334
335 ierr = PCSetFromOptions(pc);
336 AssertThrow(ierr == 0, ExcPETScError(ierr));
337 }
338
339
340 /* ----------------- PreconditionICC -------------------- */
341
345
346
347
349 : levels(levels)
350 {}
351
352
353
360
361
362 void
364 const AdditionalData &additional_data_)
365 {
366 clear();
367
368 additional_data = additional_data_;
369
370 create_pc_with_mat(matrix_);
371
372 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCICC));
373 AssertThrow(ierr == 0, ExcPETScError(ierr));
374
375 // then set flags
376 ierr = PCFactorSetLevels(pc, additional_data.levels);
377 AssertThrow(ierr == 0, ExcPETScError(ierr));
378
379 ierr = PCSetFromOptions(pc);
380 AssertThrow(ierr == 0, ExcPETScError(ierr));
381 }
382
383
384 /* ----------------- PreconditionILU -------------------- */
385
389
390
391
393 : levels(levels)
394 {}
395
396
397
404
405
406 void
408 const AdditionalData &additional_data_)
409 {
410 clear();
411
412 additional_data = additional_data_;
413
414 create_pc_with_mat(matrix_);
415
416 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCILU));
417 AssertThrow(ierr == 0, ExcPETScError(ierr));
418
419 // then set flags
420 ierr = PCFactorSetLevels(pc, additional_data.levels);
421 AssertThrow(ierr == 0, ExcPETScError(ierr));
422
423 ierr = PCSetFromOptions(pc);
424 AssertThrow(ierr == 0, ExcPETScError(ierr));
425 }
426
427
428 /* ----------------- PreconditionBoomerAMG -------------------- */
429
431 const bool symmetric_operator,
432 const double strong_threshold,
433 const double max_row_sum,
434 const unsigned int aggressive_coarsening_num_levels,
435 const bool output_details,
436 const RelaxationType relaxation_type_up,
437 const RelaxationType relaxation_type_down,
438 const RelaxationType relaxation_type_coarse,
439 const unsigned int n_sweeps_coarse,
440 const double tol,
441 const unsigned int max_iter,
442 const bool w_cycle)
443 : symmetric_operator(symmetric_operator)
444 , strong_threshold(strong_threshold)
445 , max_row_sum(max_row_sum)
446 , aggressive_coarsening_num_levels(aggressive_coarsening_num_levels)
447 , output_details(output_details)
448 , relaxation_type_up(relaxation_type_up)
449 , relaxation_type_down(relaxation_type_down)
450 , relaxation_type_coarse(relaxation_type_coarse)
451 , n_sweeps_coarse(n_sweeps_coarse)
452 , tol(tol)
453 , max_iter(max_iter)
454 , w_cycle(w_cycle)
455 {}
456
457
458
459# ifdef DEAL_II_PETSC_WITH_HYPRE
460 namespace
461 {
466 std::string
467 to_string(
469 {
470 std::string string_type;
471
472 switch (relaxation_type)
473 {
475 string_type = "Jacobi";
476 break;
479 string_type = "sequential-Gauss-Seidel";
480 break;
483 string_type = "seqboundary-Gauss-Seidel";
484 break;
486 string_type = "SOR/Jacobi";
487 break;
490 string_type = "backward-SOR/Jacobi";
491 break;
494 string_type = "symmetric-SOR/Jacobi";
495 break;
498 string_type = " l1scaled-SOR/Jacobi";
499 break;
502 string_type = "Gaussian-elimination";
503 break;
506 string_type = "l1-Gauss-Seidel";
507 break;
510 string_type = "backward-l1-Gauss-Seidel";
511 break;
513 string_type = "CG";
514 break;
516 string_type = "Chebyshev";
517 break;
519 string_type = "FCF-Jacobi";
520 break;
523 string_type = "l1scaled-Jacobi";
524 break;
526 string_type = "None";
527 break;
528 default:
530 }
531 return string_type;
532 }
533 } // namespace
534# endif
535
536
537
541
542
543
545 const MPI_Comm comm,
546 const AdditionalData &additional_data_)
548 {
549 additional_data = additional_data_;
550
551 PetscErrorCode ierr = PCCreate(comm, &pc);
552 AssertThrow(ierr == 0, ExcPETScError(ierr));
553
554# ifdef DEAL_II_PETSC_WITH_HYPRE
555 initialize();
556# else // DEAL_II_PETSC_WITH_HYPRE
557 Assert(false,
558 ExcMessage("Your PETSc installation does not include a copy of "
559 "the hypre package necessary for this preconditioner."));
560# endif
561 }
562
563
564
566 const MatrixBase &matrix,
567 const AdditionalData &additional_data)
568 : PreconditionBase(matrix.get_mpi_communicator())
569 {
571 }
572
573
574
575 void
577 {
578# ifdef DEAL_II_PETSC_WITH_HYPRE
579 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCHYPRE));
580 AssertThrow(ierr == 0, ExcPETScError(ierr));
581
582 ierr = PCHYPRESetType(pc, "boomeramg");
583 AssertThrow(ierr == 0, ExcPETScError(ierr));
584
586 {
587 set_option_value("-pc_hypre_boomeramg_print_statistics", "1");
588 }
589
590 set_option_value("-pc_hypre_boomeramg_agg_nl",
591 std::to_string(
593
594 set_option_value("-pc_hypre_boomeramg_max_row_sum",
595 std::to_string(additional_data.max_row_sum));
596
597 set_option_value("-pc_hypre_boomeramg_strong_threshold",
598 std::to_string(additional_data.strong_threshold));
599
600 // change to symmetric SOR/Jacobi when using a symmetric operator for
601 // backward compatibility
605 {
608 }
609
613 {
616 }
617
621 {
624 }
625
626 auto relaxation_type_is_symmetric =
627 [](AdditionalData::RelaxationType relaxation_type) {
628 return relaxation_type == AdditionalData::RelaxationType::Jacobi ||
629 relaxation_type ==
631 relaxation_type ==
633 relaxation_type == AdditionalData::RelaxationType::None ||
634 relaxation_type ==
636 relaxation_type == AdditionalData::RelaxationType::CG ||
638 };
639
641 !relaxation_type_is_symmetric(additional_data.relaxation_type_up))
642 Assert(false,
643 ExcMessage("Use a symmetric smoother for relaxation_type_up"));
644
646 !relaxation_type_is_symmetric(additional_data.relaxation_type_down))
647 Assert(false,
648 ExcMessage("Use a symmetric smoother for relaxation_type_down"));
649
651 !relaxation_type_is_symmetric(additional_data.relaxation_type_coarse))
652 Assert(false,
653 ExcMessage("Use a symmetric smoother for relaxation_type_coarse"));
654
655 set_option_value("-pc_hypre_boomeramg_relax_type_up",
657 set_option_value("-pc_hypre_boomeramg_relax_type_down",
659 set_option_value("-pc_hypre_boomeramg_relax_type_coarse",
661 set_option_value("-pc_hypre_boomeramg_grid_sweeps_coarse",
662 std::to_string(additional_data.n_sweeps_coarse));
663
664 set_option_value("-pc_hypre_boomeramg_tol",
665 std::to_string(additional_data.tol));
666 set_option_value("-pc_hypre_boomeramg_max_iter",
667 std::to_string(additional_data.max_iter));
668
670 {
671 set_option_value("-pc_hypre_boomeramg_cycle_type", "W");
672 }
673
674 ierr = PCSetFromOptions(pc);
675 AssertThrow(ierr == 0, ExcPETScError(ierr));
676# else
677 Assert(false,
678 ExcMessage("Your PETSc installation does not include a copy of "
679 "the hypre package necessary for this preconditioner."));
680# endif
681 }
682
683
684
685 void
687 const AdditionalData &additional_data_)
688 {
689# ifdef DEAL_II_PETSC_WITH_HYPRE
690 clear();
691
692 additional_data = additional_data_;
693
694 create_pc_with_mat(matrix_);
695 initialize();
696
697# else // DEAL_II_PETSC_WITH_HYPRE
698 (void)matrix_;
699 (void)additional_data_;
700 Assert(false,
701 ExcMessage("Your PETSc installation does not include a copy of "
702 "the hypre package necessary for this preconditioner."));
703# endif
704 }
705
706
707 /* ----------------- PreconditionParaSails -------------------- */
708
710 const unsigned int symmetric,
711 const unsigned int n_levels,
712 const double threshold,
713 const double filter,
714 const bool output_details)
715 : symmetric(symmetric)
716 , n_levels(n_levels)
717 , threshold(threshold)
718 , filter(filter)
719 , output_details(output_details)
720 {}
721
722
723
727
728
729
731 const MatrixBase &matrix,
732 const AdditionalData &additional_data)
733 : PreconditionBase(matrix.get_mpi_communicator())
734 {
736 }
737
738
739 void
741 const AdditionalData &additional_data_)
742 {
743 clear();
744
745 additional_data = additional_data_;
746
747# ifdef DEAL_II_PETSC_WITH_HYPRE
748 create_pc_with_mat(matrix_);
749
750 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCHYPRE));
751 AssertThrow(ierr == 0, ExcPETScError(ierr));
752
753 ierr = PCHYPRESetType(pc, "parasails");
754 AssertThrow(ierr == 0, ExcPETScError(ierr));
755
757 {
758 set_option_value("-pc_hypre_parasails_logging", "1");
759 }
760
764 "ParaSails parameter symmetric can only be equal to 0, 1, 2!"));
765
766 std::stringstream ssStream;
767
769 {
770 case 0:
771 {
772 ssStream << "nonsymmetric";
773 break;
774 }
775
776 case 1:
777 {
778 ssStream << "SPD";
779 break;
780 }
781
782 case 2:
783 {
784 ssStream << "nonsymmetric,SPD";
785 break;
786 }
787
788 default:
789 Assert(
790 false,
792 "ParaSails parameter symmetric can only be equal to 0, 1, 2!"));
793 }
794
795 set_option_value("-pc_hypre_parasails_sym", ssStream.str());
796
797 set_option_value("-pc_hypre_parasails_nlevels",
798 std::to_string(additional_data.n_levels));
799
800 ssStream.str(""); // empty the stringstream
801 ssStream << additional_data.threshold;
802 set_option_value("-pc_hypre_parasails_thresh", ssStream.str());
803
804 ssStream.str(""); // empty the stringstream
805 ssStream << additional_data.filter;
806 set_option_value("-pc_hypre_parasails_filter", ssStream.str());
807
808 ierr = PCSetFromOptions(pc);
809 AssertThrow(ierr == 0, ExcPETScError(ierr));
810
811# else // DEAL_II_PETSC_WITH_HYPRE
812 (void)matrix_;
813 Assert(false,
814 ExcMessage("Your PETSc installation does not include a copy of "
815 "the hypre package necessary for this preconditioner."));
816# endif
817 }
818
819
820 /* ----------------- PreconditionNone ------------------------- */
821
825
826
827
829 const AdditionalData &additional_data)
830 : PreconditionBase(matrix.get_mpi_communicator())
831 {
833 }
834
835
836 void
838 const AdditionalData &additional_data_)
839 {
840 clear();
841
842 additional_data = additional_data_;
843
844 create_pc_with_mat(matrix_);
845
846 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCNONE));
847 AssertThrow(ierr == 0, ExcPETScError(ierr));
848
849 ierr = PCSetFromOptions(pc);
850 AssertThrow(ierr == 0, ExcPETScError(ierr));
851 }
852
853
854 /* ----------------- PreconditionLU -------------------- */
855
857 const double zero_pivot,
858 const double damping)
859 : pivoting(pivoting)
860 , zero_pivot(zero_pivot)
861 , damping(damping)
862 {}
863
864
865
869
870
871
873 const AdditionalData &additional_data)
874 : PreconditionBase(matrix.get_mpi_communicator())
875 {
877 }
878
879
880 void
882 const AdditionalData &additional_data_)
883 {
884 clear();
885
886 additional_data = additional_data_;
887
888 create_pc_with_mat(matrix_);
889
890 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCLU));
891 AssertThrow(ierr == 0, ExcPETScError(ierr));
892
893 // set flags as given
894 ierr = PCFactorSetColumnPivot(pc, additional_data.pivoting);
895 AssertThrow(ierr == 0, ExcPETScError(ierr));
896
897 ierr = PCFactorSetZeroPivot(pc, additional_data.zero_pivot);
898 AssertThrow(ierr == 0, ExcPETScError(ierr));
899
900 ierr = PCFactorSetShiftAmount(pc, additional_data.damping);
901 AssertThrow(ierr == 0, ExcPETScError(ierr));
902
903 ierr = PCSetFromOptions(pc);
904 AssertThrow(ierr == 0, ExcPETScError(ierr));
905 }
906
907 /* ----------------- PreconditionBDDC -------------------- */
908
909 template <int dim>
911 const bool use_vertices,
912 const bool use_edges,
913 const bool use_faces,
914 const bool symmetric,
915 const std::vector<Point<dim>> coords)
916 : use_vertices(use_vertices)
917 , use_edges(use_edges)
918 , use_faces(use_faces)
919 , symmetric(symmetric)
920 , coords(coords)
921 {}
922
923
924
925 template <int dim>
929
930
931
932 template <int dim>
934 const MPI_Comm comm,
935 const AdditionalData &additional_data_)
937 {
938 additional_data = additional_data_;
939
940 PetscErrorCode ierr = PCCreate(comm, &pc);
941 AssertThrow(ierr == 0, ExcPETScError(ierr));
942
943 initialize();
944 }
945
946
947
948 template <int dim>
950 const AdditionalData &additional_data)
951 : PreconditionBase(matrix.get_mpi_communicator())
952 {
954 }
955
956
957
958 template <int dim>
959 void
961 {
962# if DEAL_II_PETSC_VERSION_GTE(3, 10, 0)
963 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCBDDC));
964 AssertThrow(ierr == 0, ExcPETScError(ierr));
965
966 // The matrix must be of IS type. We check for this to avoid the PETSc error
967 // in order to suggest the correct matrix reinit method.
968 {
969 MatType current_type;
970 Mat A, P;
971 PetscBool flg;
972
973 ierr = PCGetOperators(pc, &A, &P);
974 AssertThrow(ierr == 0, ExcPETScError(ierr));
975 ierr = PCGetUseAmat(pc, &flg);
976 AssertThrow(ierr == 0, ExcPETScError(ierr));
977
978 ierr = MatGetType(flg ? A : P, &current_type);
979 AssertThrow(ierr == 0, ExcPETScError(ierr));
981 strcmp(current_type, MATIS) == 0,
983 "Matrix must be of IS type. For this, the variant of reinit that includes the active dofs must be used."));
984 }
985
986
987 std::stringstream ssStream;
988
989 if (additional_data.use_vertices)
990 set_option_value("-pc_bddc_use_vertices", "true");
991 else
992 set_option_value("-pc_bddc_use_vertices", "false");
993 if (additional_data.use_edges)
994 set_option_value("-pc_bddc_use_edges", "true");
995 else
996 set_option_value("-pc_bddc_use_edges", "false");
997 if (additional_data.use_faces)
998 set_option_value("-pc_bddc_use_faces", "true");
999 else
1000 set_option_value("-pc_bddc_use_faces", "false");
1001 if (additional_data.symmetric)
1002 set_option_value("-pc_bddc_symmetric", "true");
1003 else
1004 set_option_value("-pc_bddc_symmetric", "false");
1005 if (additional_data.coords.size() > 0)
1006 {
1007 set_option_value("-pc_bddc_corner_selection", "true");
1008 // Convert coords vector to PETSc data array
1009 std::vector<PetscReal> coords_petsc(additional_data.coords.size() *
1010 dim);
1011 for (unsigned int i = 0, j = 0; i < additional_data.coords.size(); ++i)
1012 {
1013 for (j = 0; j < dim; ++j)
1014 coords_petsc[dim * i + j] = additional_data.coords[i][j];
1015 }
1016
1017 ierr = PCSetCoordinates(pc,
1018 dim,
1019 additional_data.coords.size(),
1020 coords_petsc.data());
1021 AssertThrow(ierr == 0, ExcPETScError(ierr));
1022 }
1023 else
1024 {
1025 set_option_value("-pc_bddc_corner_selection", "false");
1026 ierr = PCSetCoordinates(pc, 0, 0, nullptr);
1027 AssertThrow(ierr == 0, ExcPETScError(ierr));
1028 }
1029
1030
1031 ierr = PCSetFromOptions(pc);
1032 AssertThrow(ierr == 0, ExcPETScError(ierr));
1033# else
1035 false, ExcMessage("BDDC preconditioner requires PETSc 3.10.0 or newer"));
1036# endif
1037 }
1038
1039
1040
1041 template <int dim>
1042 void
1044 const AdditionalData &additional_data_)
1045 {
1046 clear();
1047
1048 additional_data = additional_data_;
1049
1050 create_pc_with_mat(matrix_);
1051 initialize();
1052 }
1053
1054
1055
1056 /* ----------------- PreconditionASM -------------------- */
1057
1059 const unsigned int overlap,
1060 const ASMType type,
1061 const LocalSubdomains &local_subdomains)
1062 : overlap(overlap)
1063 , type(type)
1064 , local_subdomains(local_subdomains)
1065 {}
1066
1067
1068
1072
1073
1074
1076 const AdditionalData &additional_data)
1077 : PreconditionBase(matrix.get_mpi_communicator())
1078 {
1079 initialize(matrix, additional_data);
1080 }
1081
1082
1083 void
1085 const AdditionalData &additional_data_)
1086 {
1087 clear();
1088
1089 additional_data = additional_data_;
1090
1091 create_pc_with_mat(matrix_);
1092
1093 PetscErrorCode ierr = PCSetType(pc, const_cast<char *>(PCASM));
1094 AssertThrow(ierr == 0, ExcPETScError(ierr));
1095
1096 // set the amount of overlap between the subdomains
1097 ierr = PCASMSetOverlap(pc, additional_data.overlap);
1098 AssertThrow(ierr == 0, ExcPETScError(ierr));
1099
1100 // If the user provided explicit subdomains, hand them over to PETSc
1101 // PCASMSetLocalSubdomains() routine. Indices are in global numbering.
1102 // Each processor may own an arbitrary number of subdomains (or patches),
1103 // for example one vertex-star per vertex owned by this processor.
1104 //
1105 // The index sets describing the local subdomains are sequential,
1106 // process-local objects (created on PETSC_COMM_SELF) even though they hold
1107 // global indices. This is required because each processor may contribute a
1108 // different number of subdomains, so creating them on the parallel
1109 // communicator would lead to mismatched collective calls.
1111 {
1112 const std::vector<std::vector<PetscInt>> &outer_indices =
1114 const std::vector<std::vector<PetscInt>> &inner_indices =
1116
1117 // The number of (overlapping) subdomains owned by this processor.
1118 const PetscInt n_local_subdomains =
1119 static_cast<PetscInt>(outer_indices.size());
1120
1121 // The inner (non-overlapping) subdomains are optional. If provided,
1122 // there must be exactly one inner subdomain per outer subdomain.
1123 const bool have_local_index_set = inner_indices.size() > 0;
1125 !have_local_index_set || inner_indices.size() == outer_indices.size(),
1126 ExcMessage(
1127 "If local (inner) subdomains are provided, there must be exactly "
1128 "one of them for each outer subdomain."));
1129
1130 // Build one PETSc index set per subdomain.
1131 std::vector<IS> is_subdomain(n_local_subdomains, nullptr);
1132 std::vector<IS> is_local(have_local_index_set ? n_local_subdomains : 0,
1133 nullptr);
1134
1135 for (PetscInt i = 0; i < n_local_subdomains; ++i)
1136 {
1137 // The inner (non-overlapping) subdomain is a subset of the outer
1138 // (overlapping) one, hence it can never contain more indices.
1140 !have_local_index_set ||
1141 inner_indices[i].size() <= outer_indices[i].size(),
1142 ExcMessage(
1143 "The local (inner) subdomain cannot be larger than the outer "
1144 "subdomain."));
1145
1146 ierr =
1147 ISCreateGeneral(PETSC_COMM_SELF,
1148 static_cast<PetscInt>(outer_indices[i].size()),
1149 outer_indices[i].data(),
1150 PETSC_COPY_VALUES,
1151 &is_subdomain[i]);
1152 AssertThrow(ierr == 0, ExcPETScError(ierr));
1153
1154 if (have_local_index_set)
1155 {
1156 ierr = ISCreateGeneral(PETSC_COMM_SELF,
1157 static_cast<PetscInt>(
1158 inner_indices[i].size()),
1159 inner_indices[i].data(),
1160 PETSC_COPY_VALUES,
1161 &is_local[i]);
1162 AssertThrow(ierr == 0, ExcPETScError(ierr));
1163 }
1164 }
1165
1166 ierr = PCASMSetLocalSubdomains(pc,
1167 n_local_subdomains,
1168 is_subdomain.data(),
1169 have_local_index_set ? is_local.data() :
1170 nullptr);
1171 AssertThrow(ierr == 0, ExcPETScError(ierr));
1172
1173 // PETSc increases the reference count of the index sets internally, so
1174 // we release our own references again.
1175 for (PetscInt i = 0; i < n_local_subdomains; ++i)
1176 {
1177 ierr = ISDestroy(&is_subdomain[i]);
1178 AssertThrow(ierr == 0, ExcPETScError(ierr));
1179 if (have_local_index_set)
1180 {
1181 ierr = ISDestroy(&is_local[i]);
1182 AssertThrow(ierr == 0, ExcPETScError(ierr));
1183 }
1184 }
1185 }
1186
1187 // set the variant of the additive Schwarz method
1188 PCASMType asm_type = PC_ASM_RESTRICT;
1189 switch (additional_data.type)
1190 {
1191 case ASMType::basic:
1192 asm_type = PC_ASM_BASIC;
1193 break;
1194 case ASMType::restrict:
1195 asm_type = PC_ASM_RESTRICT;
1196 break;
1198 asm_type = PC_ASM_INTERPOLATE;
1199 break;
1200 case ASMType::none:
1201 asm_type = PC_ASM_NONE;
1202 break;
1203 default:
1205 }
1206
1207 ierr = PCASMSetType(pc, asm_type);
1208 AssertThrow(ierr == 0, ExcPETScError(ierr));
1209
1210 ierr = PCSetFromOptions(pc);
1211 AssertThrow(ierr == 0, ExcPETScError(ierr));
1212
1213 ierr = PCSetUp(pc);
1214 AssertThrow(ierr == 0, ExcPETScError(ierr));
1215
1216 // set local solvers for all patches. By default, each patch solve is done
1217 // through a direct LU (KSPPREONLY + PCLU).
1218 // TODO: allow iterative solver on each patch.
1219 PetscInt n_local_subdomains = 0, first_subdomain = 0;
1220 // get the array of local sub-solvers
1221 KSP *sub_ksp = nullptr;
1222 ierr = PCASMGetSubKSP(pc, &n_local_subdomains, &first_subdomain, &sub_ksp);
1223 AssertThrow(ierr == 0, ExcPETScError(ierr));
1224 for (PetscInt i = 0; i < n_local_subdomains; ++i)
1225 {
1226 ierr = KSPSetType(sub_ksp[i], KSPPREONLY);
1227 AssertThrow(ierr == 0, ExcPETScError(ierr));
1228
1229 PC sub_pc;
1230 ierr = KSPGetPC(sub_ksp[i], &sub_pc);
1231 AssertThrow(ierr == 0, ExcPETScError(ierr));
1232 ierr = PCSetType(sub_pc, PCLU);
1233 AssertThrow(ierr == 0, ExcPETScError(ierr));
1234 }
1235 }
1236
1237 /* ----------------- PreconditionShell -------------------- */
1238
1240 {
1241 initialize(matrix);
1242 }
1243
1248
1249 void
1251 {
1252 PetscErrorCode ierr;
1253 if (pc)
1254 {
1255 ierr = PCDestroy(&pc);
1256 AssertThrow(ierr == 0, ExcPETScError(ierr));
1257 }
1259
1260 ierr = PCSetType(pc, PCSHELL);
1261 AssertThrow(ierr == 0, ExcPETScError(ierr));
1262 ierr = PCShellSetContext(pc, static_cast<void *>(this));
1263 AssertThrow(ierr == 0, ExcPETScError(ierr));
1264 ierr = PCShellSetSetUp(pc, PreconditionShell::pcsetup);
1265 AssertThrow(ierr == 0, ExcPETScError(ierr));
1266 ierr = PCShellSetApply(pc, PreconditionShell::pcapply);
1267 AssertThrow(ierr == 0, ExcPETScError(ierr));
1268 ierr = PCShellSetApplyTranspose(pc, PreconditionShell::pcapply_transpose);
1269 AssertThrow(ierr == 0, ExcPETScError(ierr));
1270 ierr = PCShellSetName(pc, "deal.II user solve");
1271 AssertThrow(ierr == 0, ExcPETScError(ierr));
1272 }
1273
1274 void
1276 {
1277 initialize(matrix.get_mpi_communicator());
1278 PetscErrorCode ierr;
1279 ierr = PCSetOperators(pc, matrix, matrix);
1280 AssertThrow(ierr == 0, ExcPETScError(ierr));
1281 }
1282
1283# ifndef PetscCall
1284# define PetscCall(code) \
1285 do \
1286 { \
1287 PetscErrorCode ierr = (code); \
1288 CHKERRQ(ierr); \
1289 } \
1290 while (false)
1291# endif
1292
1293 PetscErrorCode
1295 {
1296 PetscFunctionBeginUser;
1297 // Failed reason is not reset uniformly within the
1298 // interface code of PCSetUp in PETSc.
1299 // We handle it here.
1300 PetscCall(pc_set_failed_reason(ppc, PC_NOERROR));
1301 PetscFunctionReturn(PETSC_SUCCESS);
1302 }
1303
1304 PetscErrorCode
1305 PreconditionShell::pcapply(PC ppc, Vec x, Vec y)
1306 {
1307 void *ctx;
1308
1309 PetscFunctionBeginUser;
1310 PetscCall(PCShellGetContext(ppc, &ctx));
1311
1312 auto *user = static_cast<PreconditionShell *>(ctx);
1313 if (!user->vmult)
1314 SETERRQ(
1315 PetscObjectComm((PetscObject)ppc),
1316 PETSC_ERR_LIB,
1317 "Failure in ::PETScWrappers::PreconditionShell::pcapply. Missing std::function vmult");
1318
1319 VectorBase src(x);
1320 VectorBase dst(y);
1321 const int lineno = __LINE__;
1322 try
1323 {
1324 user->vmult(dst, src);
1325 }
1326 catch (const RecoverableUserCallbackError &)
1327 {
1328 PetscCall(pc_set_failed_reason(ppc, PC_SUBPC_ERROR));
1329 }
1330 catch (...)
1331 {
1332 return PetscError(
1333 PetscObjectComm((PetscObject)ppc),
1334 lineno + 3,
1335 "vmult",
1336 __FILE__,
1337 PETSC_ERR_LIB,
1338 PETSC_ERROR_INITIAL,
1339 "Failure in pcapply from ::PETScWrappers::NonlinearSolver");
1340 }
1342 PetscFunctionReturn(PETSC_SUCCESS);
1343 }
1344
1345 PetscErrorCode
1347 {
1348 void *ctx;
1349
1350 PetscFunctionBeginUser;
1351 PetscCall(PCShellGetContext(ppc, &ctx));
1352
1353 auto *user = static_cast<PreconditionShell *>(ctx);
1354 if (!user->vmultT)
1355 SETERRQ(
1356 PetscObjectComm((PetscObject)ppc),
1357 PETSC_ERR_LIB,
1358 "Failure in ::PETScWrappers::PreconditionShell::pcapply_transpose. Missing std::function vmultT");
1359
1360 VectorBase src(x);
1361 VectorBase dst(y);
1362 const int lineno = __LINE__;
1363 try
1364 {
1365 user->vmultT(dst, src);
1366 }
1367 catch (const RecoverableUserCallbackError &)
1368 {
1369 PetscCall(pc_set_failed_reason(ppc, PC_SUBPC_ERROR));
1370 }
1371 catch (...)
1372 {
1373 return PetscError(
1374 PetscObjectComm((PetscObject)ppc),
1375 lineno + 3,
1376 "vmultT",
1377 __FILE__,
1378 PETSC_ERR_LIB,
1379 PETSC_ERROR_INITIAL,
1380 "Failure in pcapply_transpose from ::PETScWrappers::NonlinearSolver");
1381 }
1383 PetscFunctionReturn(PETSC_SUCCESS);
1384 }
1385
1386
1387} // namespace PETScWrappers
1388
1391
1392
1393#endif // DEAL_II_WITH_PETSC
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void Tvmult(VectorBase &dst, const VectorBase &src) const
void vmult(VectorBase &dst, const VectorBase &src) const
void create_pc_with_mat(const MatrixBase &)
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const MatrixBase &matrix, const AdditionalData &additional_data=AdditionalData())
static PetscErrorCode pcapply_transpose(PC pc, Vec src, Vec dst)
static PetscErrorCode pcsetup(PC pc)
void initialize(const MPI_Comm comm)
static PetscErrorCode pcapply(PC pc, Vec src, Vec dst)
Definition point.h:111
#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 & ExcInvalidState()
static ::ExceptionBase & RecoverableUserCallbackError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
const MPI_Comm comm
Definition mpi.cc:912
void set_option_value(const std::string &name, const std::string &value)
PetscErrorCode pc_set_failed_reason(PC pc, PCFailedReason reason)
void petsc_increment_state_counter(Vec v)
#define PetscCall(code)
AdditionalData(const unsigned int overlap=1, const ASMType type=ASMType::restrict, const LocalSubdomains &local_subdomains=LocalSubdomains({}, {}))
AdditionalData(const bool use_vertices=true, const bool use_edges=false, const bool use_faces=false, const bool symmetric=false, const std::vector< Point< dim > > coords={})
AdditionalData(const bool symmetric_operator=false, const double strong_threshold=0.25, const double max_row_sum=0.9, const unsigned int aggressive_coarsening_num_levels=0, const bool output_details=false, const RelaxationType relaxation_type_up=RelaxationType::SORJacobi, const RelaxationType relaxation_type_down=RelaxationType::SORJacobi, const RelaxationType relaxation_type_coarse=RelaxationType::GaussianElimination, const unsigned int n_sweeps_coarse=1, const double tol=0.0, const unsigned int max_iter=1, const bool w_cycle=false)
AdditionalData(const double pivoting=1.e-6, const double zero_pivot=1.e-12, const double damping=0.0)
AdditionalData(const unsigned int symmetric=1, const unsigned int n_levels=1, const double threshold=0.1, const double filter=0.05, const bool output_details=false)