xref: /petsc/src/ksp/pc/impls/bddc/bddc.c (revision da023ba9cb99603dcfcbdb93311b77bc106095e0)
1 /* TODOLIST
2 
3    Solvers
4    - Add support for cholesky for coarse solver (similar to local solvers)
5    - Propagate ksp prefixes for solvers to mat objects?
6 
7    User interface
8    - ** DM attached to pc?
9 
10    Debugging output
11    - * Better management of verbosity levels of debugging output
12 
13    Extra
14    - *** Is it possible to work with PCBDDCGraph on boundary indices only (less memory consumed)?
15    - BDDC with MG framework?
16 
17    MATIS related operations contained in BDDC code
18    - Provide general case for subassembling
19 
20 */
21 
22 #include <petsc/private/pcbddcimpl.h> /*I "petscpc.h" I*/ /* header file for Fortran wrappers */
23 #include <petsc/private/pcbddcprivateimpl.h>
24 #include <petscblaslapack.h>
25 
26 static PetscBool PCBDDCPackageInitialized = PETSC_FALSE;
27 
28 static PetscBool  cited      = PETSC_FALSE;
29 static const char citation[] = "@article{ZampiniPCBDDC,\n"
30                                "author = {Stefano Zampini},\n"
31                                "title = {{PCBDDC}: A Class of Robust Dual-Primal Methods in {PETS}c},\n"
32                                "journal = {SIAM Journal on Scientific Computing},\n"
33                                "volume = {38},\n"
34                                "number = {5},\n"
35                                "pages = {S282-S306},\n"
36                                "year = {2016},\n"
37                                "doi = {10.1137/15M1025785},\n"
38                                "URL = {http://dx.doi.org/10.1137/15M1025785},\n"
39                                "eprint = {http://dx.doi.org/10.1137/15M1025785}\n"
40                                "}\n";
41 
42 PetscLogEvent PC_BDDC_Topology[PETSC_PCBDDC_MAXLEVELS];
43 PetscLogEvent PC_BDDC_LocalSolvers[PETSC_PCBDDC_MAXLEVELS];
44 PetscLogEvent PC_BDDC_LocalWork[PETSC_PCBDDC_MAXLEVELS];
45 PetscLogEvent PC_BDDC_CorrectionSetUp[PETSC_PCBDDC_MAXLEVELS];
46 PetscLogEvent PC_BDDC_ApproxSetUp[PETSC_PCBDDC_MAXLEVELS];
47 PetscLogEvent PC_BDDC_ApproxApply[PETSC_PCBDDC_MAXLEVELS];
48 PetscLogEvent PC_BDDC_CoarseSetUp[PETSC_PCBDDC_MAXLEVELS];
49 PetscLogEvent PC_BDDC_CoarseSolver[PETSC_PCBDDC_MAXLEVELS];
50 PetscLogEvent PC_BDDC_AdaptiveSetUp[PETSC_PCBDDC_MAXLEVELS];
51 PetscLogEvent PC_BDDC_Scaling[PETSC_PCBDDC_MAXLEVELS];
52 PetscLogEvent PC_BDDC_Schurs[PETSC_PCBDDC_MAXLEVELS];
53 PetscLogEvent PC_BDDC_Solves[PETSC_PCBDDC_MAXLEVELS][3];
54 
55 const char *const PCBDDCInterfaceExtTypes[] = {"DIRICHLET", "LUMP", "PCBDDCInterfaceExtType", "PC_BDDC_INTERFACE_EXT_", NULL};
56 
57 static PetscErrorCode PCApply_BDDC(PC, Vec, Vec);
58 
59 static PetscErrorCode PCSetFromOptions_BDDC(PC pc, PetscOptionItems *PetscOptionsObject)
60 {
61   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
62   PetscInt nt, i;
63 
64   PetscFunctionBegin;
65   PetscOptionsHeadBegin(PetscOptionsObject, "BDDC options");
66   /* Verbose debugging */
67   PetscCall(PetscOptionsInt("-pc_bddc_check_level", "Verbose output for PCBDDC (intended for debug)", "none", pcbddc->dbg_flag, &pcbddc->dbg_flag, NULL));
68   /* Approximate solvers */
69   PetscCall(PetscOptionsEnum("-pc_bddc_interface_ext_type", "Use DIRICHLET or LUMP to extend interface corrections to interior", "PCBDDCSetInterfaceExtType", PCBDDCInterfaceExtTypes, (PetscEnum)pcbddc->interface_extension, (PetscEnum *)&pcbddc->interface_extension, NULL));
70   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_DIRICHLET) {
71     PetscCall(PetscOptionsBool("-pc_bddc_dirichlet_approximate", "Inform PCBDDC that we are using approximate Dirichlet solvers", "none", pcbddc->NullSpace_corr[0], &pcbddc->NullSpace_corr[0], NULL));
72     PetscCall(PetscOptionsBool("-pc_bddc_dirichlet_approximate_scale", "Inform PCBDDC that we need to scale the Dirichlet solve", "none", pcbddc->NullSpace_corr[1], &pcbddc->NullSpace_corr[1], NULL));
73   } else {
74     /* This flag is needed/implied by lumping */
75     pcbddc->switch_static = PETSC_TRUE;
76   }
77   PetscCall(PetscOptionsBool("-pc_bddc_neumann_approximate", "Inform PCBDDC that we are using approximate Neumann solvers", "none", pcbddc->NullSpace_corr[2], &pcbddc->NullSpace_corr[2], NULL));
78   PetscCall(PetscOptionsBool("-pc_bddc_neumann_approximate_scale", "Inform PCBDDC that we need to scale the Neumann solve", "none", pcbddc->NullSpace_corr[3], &pcbddc->NullSpace_corr[3], NULL));
79   /* Primal space customization */
80   PetscCall(PetscOptionsBool("-pc_bddc_use_local_mat_graph", "Use or not adjacency graph of local mat for interface analysis", "none", pcbddc->use_local_adj, &pcbddc->use_local_adj, NULL));
81   PetscCall(PetscOptionsInt("-pc_bddc_graph_maxcount", "Maximum number of shared subdomains for a connected component", "none", pcbddc->graphmaxcount, &pcbddc->graphmaxcount, NULL));
82   PetscCall(PetscOptionsBool("-pc_bddc_corner_selection", "Activates face-based corner selection", "none", pcbddc->corner_selection, &pcbddc->corner_selection, NULL));
83   PetscCall(PetscOptionsBool("-pc_bddc_use_vertices", "Use or not corner dofs in coarse space", "none", pcbddc->use_vertices, &pcbddc->use_vertices, NULL));
84   PetscCall(PetscOptionsBool("-pc_bddc_use_edges", "Use or not edge constraints in coarse space", "none", pcbddc->use_edges, &pcbddc->use_edges, NULL));
85   PetscCall(PetscOptionsBool("-pc_bddc_use_faces", "Use or not face constraints in coarse space", "none", pcbddc->use_faces, &pcbddc->use_faces, NULL));
86   PetscCall(PetscOptionsInt("-pc_bddc_vertex_size", "Connected components smaller or equal to vertex size will be considered as primal vertices", "none", pcbddc->vertex_size, &pcbddc->vertex_size, NULL));
87   PetscCall(PetscOptionsBool("-pc_bddc_use_nnsp", "Use near null space attached to the matrix to compute constraints", "none", pcbddc->use_nnsp, &pcbddc->use_nnsp, NULL));
88   PetscCall(PetscOptionsBool("-pc_bddc_use_nnsp_true", "Use near null space attached to the matrix to compute constraints as is", "none", pcbddc->use_nnsp_true, &pcbddc->use_nnsp_true, NULL));
89   PetscCall(PetscOptionsBool("-pc_bddc_use_qr_single", "Use QR factorization for single constraints on cc (QR is always used when multiple constraints are present)", "none", pcbddc->use_qr_single, &pcbddc->use_qr_single, NULL));
90   /* Change of basis */
91   PetscCall(PetscOptionsBool("-pc_bddc_use_change_of_basis", "Use or not internal change of basis on local edge nodes", "none", pcbddc->use_change_of_basis, &pcbddc->use_change_of_basis, NULL));
92   PetscCall(PetscOptionsBool("-pc_bddc_use_change_on_faces", "Use or not internal change of basis on local face nodes", "none", pcbddc->use_change_on_faces, &pcbddc->use_change_on_faces, NULL));
93   if (!pcbddc->use_change_of_basis) pcbddc->use_change_on_faces = PETSC_FALSE;
94   /* Switch between M_2 (default) and M_3 preconditioners (as defined by C. Dohrmann in the ref. article) */
95   PetscCall(PetscOptionsBool("-pc_bddc_switch_static", "Switch on static condensation ops around the interface preconditioner", "none", pcbddc->switch_static, &pcbddc->switch_static, NULL));
96   PetscCall(PetscOptionsInt("-pc_bddc_coarse_eqs_per_proc", "Target number of equations per process for coarse problem redistribution (significant only at the coarsest level)", "none", pcbddc->coarse_eqs_per_proc, &pcbddc->coarse_eqs_per_proc, NULL));
97   i = pcbddc->coarsening_ratio;
98   PetscCall(PetscOptionsInt("-pc_bddc_coarsening_ratio", "Set coarsening ratio used in multilevel coarsening", "PCBDDCSetCoarseningRatio", i, &i, NULL));
99   PetscCall(PCBDDCSetCoarseningRatio(pc, i));
100   i = pcbddc->max_levels;
101   PetscCall(PetscOptionsInt("-pc_bddc_levels", "Set maximum number of levels for multilevel", "PCBDDCSetLevels", i, &i, NULL));
102   PetscCall(PCBDDCSetLevels(pc, i));
103   PetscCall(PetscOptionsInt("-pc_bddc_coarse_eqs_limit", "Set maximum number of equations on coarsest grid to aim for", "none", pcbddc->coarse_eqs_limit, &pcbddc->coarse_eqs_limit, NULL));
104   PetscCall(PetscOptionsBool("-pc_bddc_use_coarse_estimates", "Use estimated eigenvalues for coarse problem", "none", pcbddc->use_coarse_estimates, &pcbddc->use_coarse_estimates, NULL));
105   PetscCall(PetscOptionsBool("-pc_bddc_use_deluxe_scaling", "Use deluxe scaling for BDDC", "none", pcbddc->use_deluxe_scaling, &pcbddc->use_deluxe_scaling, NULL));
106   PetscCall(PetscOptionsBool("-pc_bddc_schur_rebuild", "Whether or not the interface graph for Schur principal minors has to be rebuilt (i.e. define the interface without any adjacency)", "none", pcbddc->sub_schurs_rebuild, &pcbddc->sub_schurs_rebuild, NULL));
107   PetscCall(PetscOptionsInt("-pc_bddc_schur_layers", "Number of dofs' layers for the computation of principal minors (i.e. -1 uses all dofs)", "none", pcbddc->sub_schurs_layers, &pcbddc->sub_schurs_layers, NULL));
108   PetscCall(PetscOptionsBool("-pc_bddc_schur_use_useradj", "Whether or not the CSR graph specified by the user should be used for computing successive layers (default is to use adj of local mat)", "none", pcbddc->sub_schurs_use_useradj, &pcbddc->sub_schurs_use_useradj, NULL));
109   PetscCall(PetscOptionsBool("-pc_bddc_schur_exact", "Whether or not to use the exact Schur complement instead of the reduced one (which excludes size 1 cc)", "none", pcbddc->sub_schurs_exact_schur, &pcbddc->sub_schurs_exact_schur, NULL));
110   PetscCall(PetscOptionsBool("-pc_bddc_deluxe_zerorows", "Zero rows and columns of deluxe operators associated with primal dofs", "none", pcbddc->deluxe_zerorows, &pcbddc->deluxe_zerorows, NULL));
111   PetscCall(PetscOptionsBool("-pc_bddc_deluxe_singlemat", "Collapse deluxe operators", "none", pcbddc->deluxe_singlemat, &pcbddc->deluxe_singlemat, NULL));
112   PetscCall(PetscOptionsBool("-pc_bddc_adaptive_userdefined", "Use user-defined constraints (should be attached via MatSetNearNullSpace to pmat) in addition to those adaptively generated", "none", pcbddc->adaptive_userdefined, &pcbddc->adaptive_userdefined, NULL));
113   nt = 2;
114   PetscCall(PetscOptionsRealArray("-pc_bddc_adaptive_threshold", "Thresholds to be used for adaptive selection of constraints", "none", pcbddc->adaptive_threshold, &nt, NULL));
115   if (nt == 1) pcbddc->adaptive_threshold[1] = pcbddc->adaptive_threshold[0];
116   PetscCall(PetscOptionsInt("-pc_bddc_adaptive_nmin", "Minimum number of constraints per connected components", "none", pcbddc->adaptive_nmin, &pcbddc->adaptive_nmin, NULL));
117   PetscCall(PetscOptionsInt("-pc_bddc_adaptive_nmax", "Maximum number of constraints per connected components", "none", pcbddc->adaptive_nmax, &pcbddc->adaptive_nmax, NULL));
118   PetscCall(PetscOptionsBool("-pc_bddc_symmetric", "Symmetric computation of primal basis functions", "none", pcbddc->symmetric_primal, &pcbddc->symmetric_primal, NULL));
119   PetscCall(PetscOptionsInt("-pc_bddc_coarse_adj", "Number of processors where to map the coarse adjacency list", "none", pcbddc->coarse_adj_red, &pcbddc->coarse_adj_red, NULL));
120   PetscCall(PetscOptionsBool("-pc_bddc_benign_trick", "Apply the benign subspace trick to saddle point problems with discontinuous pressures", "none", pcbddc->benign_saddle_point, &pcbddc->benign_saddle_point, NULL));
121   PetscCall(PetscOptionsBool("-pc_bddc_benign_change", "Compute the pressure change of basis explicitly", "none", pcbddc->benign_change_explicit, &pcbddc->benign_change_explicit, NULL));
122   PetscCall(PetscOptionsBool("-pc_bddc_benign_compute_correction", "Compute the benign correction during PreSolve", "none", pcbddc->benign_compute_correction, &pcbddc->benign_compute_correction, NULL));
123   PetscCall(PetscOptionsBool("-pc_bddc_nonetflux", "Automatic computation of no-net-flux quadrature weights", "none", pcbddc->compute_nonetflux, &pcbddc->compute_nonetflux, NULL));
124   PetscCall(PetscOptionsBool("-pc_bddc_detect_disconnected", "Detects disconnected subdomains", "none", pcbddc->detect_disconnected, &pcbddc->detect_disconnected, NULL));
125   PetscCall(PetscOptionsBool("-pc_bddc_detect_disconnected_filter", "Filters out small entries in the local matrix when detecting disconnected subdomains", "none", pcbddc->detect_disconnected_filter, &pcbddc->detect_disconnected_filter, NULL));
126   PetscCall(PetscOptionsBool("-pc_bddc_eliminate_dirichlet", "Whether or not we want to eliminate dirichlet dofs during presolve", "none", pcbddc->eliminate_dirdofs, &pcbddc->eliminate_dirdofs, NULL));
127   PetscOptionsHeadEnd();
128   PetscFunctionReturn(PETSC_SUCCESS);
129 }
130 
131 static PetscErrorCode PCView_BDDC(PC pc, PetscViewer viewer)
132 {
133   PC_BDDC     *pcbddc = (PC_BDDC *)pc->data;
134   PC_IS       *pcis   = (PC_IS *)pc->data;
135   PetscBool    isascii;
136   PetscSubcomm subcomm;
137   PetscViewer  subviewer;
138 
139   PetscFunctionBegin;
140   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
141   /* ASCII viewer */
142   if (isascii) {
143     PetscMPIInt color, rank, size;
144     PetscInt64  loc[7], gsum[6], gmax[6], gmin[6], totbenign;
145     PetscScalar interface_size;
146     PetscReal   ratio1 = 0., ratio2 = 0.;
147     Vec         counter;
148 
149     if (!pc->setupcalled) PetscCall(PetscViewerASCIIPrintf(viewer, "  Partial information available: preconditioner has not been setup yet\n"));
150     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use verbose output: %" PetscInt_FMT "\n", pcbddc->dbg_flag));
151     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use user-defined CSR: %d\n", !!pcbddc->mat_graph->nvtxs_csr));
152     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use local mat graph: %d\n", pcbddc->use_local_adj && !pcbddc->mat_graph->nvtxs_csr));
153     if (pcbddc->mat_graph->twodim) {
154       PetscCall(PetscViewerASCIIPrintf(viewer, "  Connectivity graph topological dimension: 2\n"));
155     } else {
156       PetscCall(PetscViewerASCIIPrintf(viewer, "  Connectivity graph topological dimension: 3\n"));
157     }
158     if (pcbddc->graphmaxcount != PETSC_MAX_INT) PetscCall(PetscViewerASCIIPrintf(viewer, "  Graph max count: %" PetscInt_FMT "\n", pcbddc->graphmaxcount));
159     PetscCall(PetscViewerASCIIPrintf(viewer, "  Corner selection: %d (selected %d)\n", pcbddc->corner_selection, pcbddc->corner_selected));
160     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use vertices: %d (vertex size %" PetscInt_FMT ")\n", pcbddc->use_vertices, pcbddc->vertex_size));
161     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use edges: %d\n", pcbddc->use_edges));
162     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use faces: %d\n", pcbddc->use_faces));
163     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use true near null space: %d\n", pcbddc->use_nnsp_true));
164     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use QR for single constraints on cc: %d\n", pcbddc->use_qr_single));
165     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use change of basis on local edge nodes: %d\n", pcbddc->use_change_of_basis));
166     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use change of basis on local face nodes: %d\n", pcbddc->use_change_on_faces));
167     PetscCall(PetscViewerASCIIPrintf(viewer, "  User defined change of basis matrix: %d\n", !!pcbddc->user_ChangeOfBasisMatrix));
168     PetscCall(PetscViewerASCIIPrintf(viewer, "  Has change of basis matrix: %d\n", !!pcbddc->ChangeOfBasisMatrix));
169     PetscCall(PetscViewerASCIIPrintf(viewer, "  Eliminate dirichlet boundary dofs: %d\n", pcbddc->eliminate_dirdofs));
170     PetscCall(PetscViewerASCIIPrintf(viewer, "  Switch on static condensation ops around the interface preconditioner: %d\n", pcbddc->switch_static));
171     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use exact dirichlet trick: %d\n", pcbddc->use_exact_dirichlet_trick));
172     PetscCall(PetscViewerASCIIPrintf(viewer, "  Interface extension: %s\n", PCBDDCInterfaceExtTypes[pcbddc->interface_extension]));
173     PetscCall(PetscViewerASCIIPrintf(viewer, "  Multilevel max levels: %" PetscInt_FMT "\n", pcbddc->max_levels));
174     PetscCall(PetscViewerASCIIPrintf(viewer, "  Multilevel coarsening ratio: %" PetscInt_FMT "\n", pcbddc->coarsening_ratio));
175     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use estimated eigs for coarse problem: %d\n", pcbddc->use_coarse_estimates));
176     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use deluxe scaling: %d\n", pcbddc->use_deluxe_scaling));
177     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use deluxe zerorows: %d\n", pcbddc->deluxe_zerorows));
178     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use deluxe singlemat: %d\n", pcbddc->deluxe_singlemat));
179     PetscCall(PetscViewerASCIIPrintf(viewer, "  Rebuild interface graph for Schur principal minors: %d\n", pcbddc->sub_schurs_rebuild));
180     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of dofs' layers for the computation of principal minors: %" PetscInt_FMT "\n", pcbddc->sub_schurs_layers));
181     PetscCall(PetscViewerASCIIPrintf(viewer, "  Use user CSR graph to compute successive layers: %d\n", pcbddc->sub_schurs_use_useradj));
182     if (pcbddc->adaptive_threshold[1] != pcbddc->adaptive_threshold[0]) {
183       PetscCall(PetscViewerASCIIPrintf(viewer, "  Adaptive constraint selection thresholds (active %d, userdefined %d): %g,%g\n", pcbddc->adaptive_selection, pcbddc->adaptive_userdefined, (double)pcbddc->adaptive_threshold[0], (double)pcbddc->adaptive_threshold[1]));
184     } else {
185       PetscCall(PetscViewerASCIIPrintf(viewer, "  Adaptive constraint selection threshold (active %d, userdefined %d): %g\n", pcbddc->adaptive_selection, pcbddc->adaptive_userdefined, (double)pcbddc->adaptive_threshold[0]));
186     }
187     PetscCall(PetscViewerASCIIPrintf(viewer, "  Min constraints / connected component: %" PetscInt_FMT "\n", pcbddc->adaptive_nmin));
188     PetscCall(PetscViewerASCIIPrintf(viewer, "  Max constraints / connected component: %" PetscInt_FMT "\n", pcbddc->adaptive_nmax));
189     PetscCall(PetscViewerASCIIPrintf(viewer, "  Invert exact Schur complement for adaptive selection: %d\n", pcbddc->sub_schurs_exact_schur));
190     PetscCall(PetscViewerASCIIPrintf(viewer, "  Symmetric computation of primal basis functions: %d\n", pcbddc->symmetric_primal));
191     PetscCall(PetscViewerASCIIPrintf(viewer, "  Num. Procs. to map coarse adjacency list: %" PetscInt_FMT "\n", pcbddc->coarse_adj_red));
192     PetscCall(PetscViewerASCIIPrintf(viewer, "  Coarse eqs per proc (significant at the coarsest level): %" PetscInt_FMT "\n", pcbddc->coarse_eqs_per_proc));
193     PetscCall(PetscViewerASCIIPrintf(viewer, "  Detect disconnected: %d (filter %d)\n", pcbddc->detect_disconnected, pcbddc->detect_disconnected_filter));
194     PetscCall(PetscViewerASCIIPrintf(viewer, "  Benign subspace trick: %d (change explicit %d)\n", pcbddc->benign_saddle_point, pcbddc->benign_change_explicit));
195     PetscCall(PetscViewerASCIIPrintf(viewer, "  Benign subspace trick is active: %d\n", pcbddc->benign_have_null));
196     PetscCall(PetscViewerASCIIPrintf(viewer, "  Algebraic computation of no-net-flux: %d\n", pcbddc->compute_nonetflux));
197     if (!pc->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
198 
199     /* compute interface size */
200     PetscCall(VecSet(pcis->vec1_B, 1.0));
201     PetscCall(MatCreateVecs(pc->pmat, &counter, NULL));
202     PetscCall(VecSet(counter, 0.0));
203     PetscCall(VecScatterBegin(pcis->global_to_B, pcis->vec1_B, counter, INSERT_VALUES, SCATTER_REVERSE));
204     PetscCall(VecScatterEnd(pcis->global_to_B, pcis->vec1_B, counter, INSERT_VALUES, SCATTER_REVERSE));
205     PetscCall(VecSum(counter, &interface_size));
206     PetscCall(VecDestroy(&counter));
207 
208     /* compute some statistics on the domain decomposition */
209     gsum[0] = 1;
210     gsum[1] = gsum[2] = gsum[3] = gsum[4] = gsum[5] = 0;
211     loc[0]                                          = !!pcis->n;
212     loc[1]                                          = pcis->n - pcis->n_B;
213     loc[2]                                          = pcis->n_B;
214     loc[3]                                          = pcbddc->local_primal_size;
215     loc[4]                                          = pcis->n;
216     loc[5]                                          = pcbddc->n_local_subs > 0 ? pcbddc->n_local_subs : (pcis->n ? 1 : 0);
217     loc[6]                                          = pcbddc->benign_n;
218     PetscCallMPI(MPI_Reduce(loc, gsum, 6, MPIU_INT64, MPI_SUM, 0, PetscObjectComm((PetscObject)pc)));
219     if (!loc[0]) loc[1] = loc[2] = loc[3] = loc[4] = loc[5] = -1;
220     PetscCallMPI(MPI_Reduce(loc, gmax, 6, MPIU_INT64, MPI_MAX, 0, PetscObjectComm((PetscObject)pc)));
221     if (!loc[0]) loc[1] = loc[2] = loc[3] = loc[4] = loc[5] = PETSC_MAX_INT;
222     PetscCallMPI(MPI_Reduce(loc, gmin, 6, MPIU_INT64, MPI_MIN, 0, PetscObjectComm((PetscObject)pc)));
223     PetscCallMPI(MPI_Reduce(&loc[6], &totbenign, 1, MPIU_INT64, MPI_SUM, 0, PetscObjectComm((PetscObject)pc)));
224     if (pcbddc->coarse_size) {
225       ratio1 = pc->pmat->rmap->N / (1. * pcbddc->coarse_size);
226       ratio2 = PetscRealPart(interface_size) / pcbddc->coarse_size;
227     }
228     PetscCall(PetscViewerASCIIPrintf(viewer, "********************************** STATISTICS AT LEVEL %" PetscInt_FMT " **********************************\n", pcbddc->current_level));
229     PetscCall(PetscViewerASCIIPrintf(viewer, "  Global dofs sizes: all %" PetscInt_FMT " interface %" PetscInt_FMT " coarse %" PetscInt_FMT "\n", pc->pmat->rmap->N, (PetscInt)PetscRealPart(interface_size), pcbddc->coarse_size));
230     PetscCall(PetscViewerASCIIPrintf(viewer, "  Coarsening ratios: all/coarse %" PetscInt_FMT " interface/coarse %" PetscInt_FMT "\n", (PetscInt)ratio1, (PetscInt)ratio2));
231     PetscCall(PetscViewerASCIIPrintf(viewer, "  Active processes : %" PetscInt_FMT "\n", (PetscInt)gsum[0]));
232     PetscCall(PetscViewerASCIIPrintf(viewer, "  Total subdomains : %" PetscInt_FMT "\n", (PetscInt)gsum[5]));
233     if (pcbddc->benign_have_null) PetscCall(PetscViewerASCIIPrintf(viewer, "  Benign subs      : %" PetscInt_FMT "\n", (PetscInt)totbenign));
234     PetscCall(PetscViewerASCIIPrintf(viewer, "  Dofs type        :\tMIN\tMAX\tMEAN\n"));
235     PetscCall(PetscViewerASCIIPrintf(viewer, "  Interior  dofs   :\t%" PetscInt_FMT "\t%" PetscInt_FMT "\t%" PetscInt_FMT "\n", (PetscInt)gmin[1], (PetscInt)gmax[1], (PetscInt)(gsum[1] / gsum[0])));
236     PetscCall(PetscViewerASCIIPrintf(viewer, "  Interface dofs   :\t%" PetscInt_FMT "\t%" PetscInt_FMT "\t%" PetscInt_FMT "\n", (PetscInt)gmin[2], (PetscInt)gmax[2], (PetscInt)(gsum[2] / gsum[0])));
237     PetscCall(PetscViewerASCIIPrintf(viewer, "  Primal    dofs   :\t%" PetscInt_FMT "\t%" PetscInt_FMT "\t%" PetscInt_FMT "\n", (PetscInt)gmin[3], (PetscInt)gmax[3], (PetscInt)(gsum[3] / gsum[0])));
238     PetscCall(PetscViewerASCIIPrintf(viewer, "  Local     dofs   :\t%" PetscInt_FMT "\t%" PetscInt_FMT "\t%" PetscInt_FMT "\n", (PetscInt)gmin[4], (PetscInt)gmax[4], (PetscInt)(gsum[4] / gsum[0])));
239     PetscCall(PetscViewerASCIIPrintf(viewer, "  Local     subs   :\t%" PetscInt_FMT "\t%" PetscInt_FMT "\n", (PetscInt)gmin[5], (PetscInt)gmax[5]));
240     PetscCall(PetscViewerFlush(viewer));
241 
242     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
243 
244     /* local solvers */
245     PetscCall(PetscViewerGetSubViewer(viewer, PetscObjectComm((PetscObject)pcbddc->ksp_D), &subviewer));
246     if (rank == 0) {
247       PetscCall(PetscViewerASCIIPrintf(subviewer, "--- Interior solver (rank 0)\n"));
248       PetscCall(PetscViewerASCIIPushTab(subviewer));
249       PetscCall(KSPView(pcbddc->ksp_D, subviewer));
250       PetscCall(PetscViewerASCIIPopTab(subviewer));
251       PetscCall(PetscViewerASCIIPrintf(subviewer, "--- Correction solver (rank 0)\n"));
252       PetscCall(PetscViewerASCIIPushTab(subviewer));
253       PetscCall(KSPView(pcbddc->ksp_R, subviewer));
254       PetscCall(PetscViewerASCIIPopTab(subviewer));
255       PetscCall(PetscViewerFlush(subviewer));
256     }
257     PetscCall(PetscViewerRestoreSubViewer(viewer, PetscObjectComm((PetscObject)pcbddc->ksp_D), &subviewer));
258     /* the coarse problem can be handled by a different communicator */
259     if (pcbddc->coarse_ksp) color = 1;
260     else color = 0;
261     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
262     PetscCall(PetscSubcommCreate(PetscObjectComm((PetscObject)pc), &subcomm));
263     PetscCall(PetscSubcommSetNumber(subcomm, PetscMin(size, 2)));
264     PetscCall(PetscSubcommSetTypeGeneral(subcomm, color, rank));
265     PetscCall(PetscViewerGetSubViewer(viewer, PetscSubcommChild(subcomm), &subviewer));
266     if (color == 1) {
267       PetscCall(PetscViewerASCIIPrintf(subviewer, "--- Coarse solver\n"));
268       PetscCall(PetscViewerASCIIPushTab(subviewer));
269       PetscCall(KSPView(pcbddc->coarse_ksp, subviewer));
270       PetscCall(PetscViewerASCIIPopTab(subviewer));
271       PetscCall(PetscViewerFlush(subviewer));
272     }
273     PetscCall(PetscViewerRestoreSubViewer(viewer, PetscSubcommChild(subcomm), &subviewer));
274     PetscCall(PetscSubcommDestroy(&subcomm));
275     PetscCall(PetscViewerFlush(viewer));
276   }
277   PetscFunctionReturn(PETSC_SUCCESS);
278 }
279 
280 static PetscErrorCode PCBDDCSetDiscreteGradient_BDDC(PC pc, Mat G, PetscInt order, PetscInt field, PetscBool global, PetscBool conforming)
281 {
282   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
283 
284   PetscFunctionBegin;
285   PetscCall(PetscObjectReference((PetscObject)G));
286   PetscCall(MatDestroy(&pcbddc->discretegradient));
287   pcbddc->discretegradient = G;
288   pcbddc->nedorder         = order > 0 ? order : -order;
289   pcbddc->nedfield         = field;
290   pcbddc->nedglobal        = global;
291   pcbddc->conforming       = conforming;
292   PetscFunctionReturn(PETSC_SUCCESS);
293 }
294 
295 /*@
296   PCBDDCSetDiscreteGradient - Sets the discrete gradient to be used by the `PCBDDC` preconditioner
297 
298   Collective
299 
300   Input Parameters:
301 + pc         - the preconditioning context
302 . G          - the discrete gradient matrix (in `MATAIJ` format)
303 . order      - the order of the Nedelec space (1 for the lowest order)
304 . field      - the field id of the Nedelec dofs (not used if the fields have not been specified)
305 . global     - the type of global ordering for the rows of `G`
306 - conforming - whether the mesh is conforming or not
307 
308   Level: advanced
309 
310   Note:
311   The discrete gradient matrix `G` is used to analyze the subdomain edges, and it should not contain any zero entry.
312   For variable order spaces, the order should be set to zero.
313   If `global` is `PETSC_TRUE`, the rows of `G` should be given in global ordering for the whole dofs;
314   if `PETSC_FALSE`, the ordering should be global for the Nedelec field.
315   In the latter case, it should hold gid[i] < gid[j] iff geid[i] < geid[j], with gid the global orderding for all the dofs
316   and geid the one for the Nedelec field.
317 
318 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDofsSplitting()`, `PCBDDCSetDofsSplittingLocal()`, `MATAIJ`, `PCBDDCSetDivergenceMat()`
319 @*/
320 PetscErrorCode PCBDDCSetDiscreteGradient(PC pc, Mat G, PetscInt order, PetscInt field, PetscBool global, PetscBool conforming)
321 {
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
324   PetscValidHeaderSpecific(G, MAT_CLASSID, 2);
325   PetscValidLogicalCollectiveInt(pc, order, 3);
326   PetscValidLogicalCollectiveInt(pc, field, 4);
327   PetscValidLogicalCollectiveBool(pc, global, 5);
328   PetscValidLogicalCollectiveBool(pc, conforming, 6);
329   PetscCheckSameComm(pc, 1, G, 2);
330   PetscTryMethod(pc, "PCBDDCSetDiscreteGradient_C", (PC, Mat, PetscInt, PetscInt, PetscBool, PetscBool), (pc, G, order, field, global, conforming));
331   PetscFunctionReturn(PETSC_SUCCESS);
332 }
333 
334 static PetscErrorCode PCBDDCSetDivergenceMat_BDDC(PC pc, Mat divudotp, PetscBool trans, IS vl2l)
335 {
336   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
337 
338   PetscFunctionBegin;
339   PetscCall(PetscObjectReference((PetscObject)divudotp));
340   PetscCall(MatDestroy(&pcbddc->divudotp));
341   pcbddc->divudotp          = divudotp;
342   pcbddc->divudotp_trans    = trans;
343   pcbddc->compute_nonetflux = PETSC_TRUE;
344   if (vl2l) {
345     PetscCall(PetscObjectReference((PetscObject)vl2l));
346     PetscCall(ISDestroy(&pcbddc->divudotp_vl2l));
347     pcbddc->divudotp_vl2l = vl2l;
348   }
349   PetscFunctionReturn(PETSC_SUCCESS);
350 }
351 
352 /*@
353   PCBDDCSetDivergenceMat - Sets the linear operator representing \int_\Omega \div {\bf u} \cdot p dx for the `PCBDDC` preconditioner
354 
355   Collective
356 
357   Input Parameters:
358 + pc       - the preconditioning context
359 . divudotp - the matrix (must be of type `MATIS`)
360 . trans    - if `PETSC_FALSE` (resp. `PETSC_TRUE`), then pressures are in the test (trial) space and velocities are in the trial (test) space.
361 - vl2l     - optional index set describing the local (wrt the local matrix in `divudotp`) to local (wrt the local matrix
362    in the preconditioning matrix) map for the velocities
363 
364   Level: advanced
365 
366   Notes:
367   This auxiliary matrix is used to compute quadrature weights representing the net-flux across subdomain boundaries
368 
369   If `vl2l` is `NULL`, the local ordering for velocities in `divudotp` should match that of the preconditioning matrix
370 
371 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDiscreteGradient()`
372 @*/
373 PetscErrorCode PCBDDCSetDivergenceMat(PC pc, Mat divudotp, PetscBool trans, IS vl2l)
374 {
375   PetscBool ismatis;
376 
377   PetscFunctionBegin;
378   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
379   PetscValidHeaderSpecific(divudotp, MAT_CLASSID, 2);
380   PetscCheckSameComm(pc, 1, divudotp, 2);
381   PetscValidLogicalCollectiveBool(pc, trans, 3);
382   if (vl2l) PetscValidHeaderSpecific(vl2l, IS_CLASSID, 4);
383   PetscCall(PetscObjectTypeCompare((PetscObject)divudotp, MATIS, &ismatis));
384   PetscCheck(ismatis, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Divergence matrix needs to be of type MATIS");
385   PetscTryMethod(pc, "PCBDDCSetDivergenceMat_C", (PC, Mat, PetscBool, IS), (pc, divudotp, trans, vl2l));
386   PetscFunctionReturn(PETSC_SUCCESS);
387 }
388 
389 static PetscErrorCode PCBDDCSetChangeOfBasisMat_BDDC(PC pc, Mat change, PetscBool interior)
390 {
391   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
392 
393   PetscFunctionBegin;
394   PetscCall(PetscObjectReference((PetscObject)change));
395   PetscCall(MatDestroy(&pcbddc->user_ChangeOfBasisMatrix));
396   pcbddc->user_ChangeOfBasisMatrix = change;
397   pcbddc->change_interior          = interior;
398   PetscFunctionReturn(PETSC_SUCCESS);
399 }
400 
401 /*@
402   PCBDDCSetChangeOfBasisMat - Set user defined change of basis for dofs
403 
404   Collective
405 
406   Input Parameters:
407 + pc       - the preconditioning context
408 . change   - the change of basis matrix
409 - interior - whether or not the change of basis modifies interior dofs
410 
411   Level: intermediate
412 
413 .seealso: [](ch_ksp), `PCBDDC`
414 @*/
415 PetscErrorCode PCBDDCSetChangeOfBasisMat(PC pc, Mat change, PetscBool interior)
416 {
417   PetscFunctionBegin;
418   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
419   PetscValidHeaderSpecific(change, MAT_CLASSID, 2);
420   PetscCheckSameComm(pc, 1, change, 2);
421   if (pc->mat) {
422     PetscInt rows_c, cols_c, rows, cols;
423     PetscCall(MatGetSize(pc->mat, &rows, &cols));
424     PetscCall(MatGetSize(change, &rows_c, &cols_c));
425     PetscCheck(rows_c == rows, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Invalid number of rows for change of basis matrix! %" PetscInt_FMT " != %" PetscInt_FMT, rows_c, rows);
426     PetscCheck(cols_c == cols, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Invalid number of columns for change of basis matrix! %" PetscInt_FMT " != %" PetscInt_FMT, cols_c, cols);
427     PetscCall(MatGetLocalSize(pc->mat, &rows, &cols));
428     PetscCall(MatGetLocalSize(change, &rows_c, &cols_c));
429     PetscCheck(rows_c == rows, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Invalid number of local rows for change of basis matrix! %" PetscInt_FMT " != %" PetscInt_FMT, rows_c, rows);
430     PetscCheck(cols_c == cols, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Invalid number of local columns for change of basis matrix! %" PetscInt_FMT " != %" PetscInt_FMT, cols_c, cols);
431   }
432   PetscTryMethod(pc, "PCBDDCSetChangeOfBasisMat_C", (PC, Mat, PetscBool), (pc, change, interior));
433   PetscFunctionReturn(PETSC_SUCCESS);
434 }
435 
436 static PetscErrorCode PCBDDCSetPrimalVerticesIS_BDDC(PC pc, IS PrimalVertices)
437 {
438   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
439   PetscBool isequal = PETSC_FALSE;
440 
441   PetscFunctionBegin;
442   PetscCall(PetscObjectReference((PetscObject)PrimalVertices));
443   if (pcbddc->user_primal_vertices) PetscCall(ISEqual(PrimalVertices, pcbddc->user_primal_vertices, &isequal));
444   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
445   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
446   pcbddc->user_primal_vertices = PrimalVertices;
447   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
448   PetscFunctionReturn(PETSC_SUCCESS);
449 }
450 
451 /*@
452   PCBDDCSetPrimalVerticesIS - Set additional user defined primal vertices in `PCBDDC`
453 
454   Collective
455 
456   Input Parameters:
457 + pc             - the preconditioning context
458 - PrimalVertices - index set of primal vertices in global numbering (can be empty)
459 
460   Level: intermediate
461 
462   Note:
463   Any process can list any global node
464 
465 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCGetPrimalVerticesIS()`, `PCBDDCSetPrimalVerticesLocalIS()`, `PCBDDCGetPrimalVerticesLocalIS()`
466 @*/
467 PetscErrorCode PCBDDCSetPrimalVerticesIS(PC pc, IS PrimalVertices)
468 {
469   PetscFunctionBegin;
470   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
471   PetscValidHeaderSpecific(PrimalVertices, IS_CLASSID, 2);
472   PetscCheckSameComm(pc, 1, PrimalVertices, 2);
473   PetscTryMethod(pc, "PCBDDCSetPrimalVerticesIS_C", (PC, IS), (pc, PrimalVertices));
474   PetscFunctionReturn(PETSC_SUCCESS);
475 }
476 
477 static PetscErrorCode PCBDDCGetPrimalVerticesIS_BDDC(PC pc, IS *is)
478 {
479   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
480 
481   PetscFunctionBegin;
482   *is = pcbddc->user_primal_vertices;
483   PetscFunctionReturn(PETSC_SUCCESS);
484 }
485 
486 /*@
487   PCBDDCGetPrimalVerticesIS - Get user defined primal vertices set with `PCBDDCSetPrimalVerticesIS()`
488 
489   Collective
490 
491   Input Parameter:
492 . pc - the preconditioning context
493 
494   Output Parameter:
495 . is - index set of primal vertices in global numbering (`NULL` if not set)
496 
497   Level: intermediate
498 
499 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetPrimalVerticesIS()`, `PCBDDCSetPrimalVerticesLocalIS()`, `PCBDDCGetPrimalVerticesLocalIS()`
500 @*/
501 PetscErrorCode PCBDDCGetPrimalVerticesIS(PC pc, IS *is)
502 {
503   PetscFunctionBegin;
504   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
505   PetscAssertPointer(is, 2);
506   PetscUseMethod(pc, "PCBDDCGetPrimalVerticesIS_C", (PC, IS *), (pc, is));
507   PetscFunctionReturn(PETSC_SUCCESS);
508 }
509 
510 static PetscErrorCode PCBDDCSetPrimalVerticesLocalIS_BDDC(PC pc, IS PrimalVertices)
511 {
512   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
513   PetscBool isequal = PETSC_FALSE;
514 
515   PetscFunctionBegin;
516   PetscCall(PetscObjectReference((PetscObject)PrimalVertices));
517   if (pcbddc->user_primal_vertices_local) PetscCall(ISEqual(PrimalVertices, pcbddc->user_primal_vertices_local, &isequal));
518   PetscCall(ISDestroy(&pcbddc->user_primal_vertices));
519   PetscCall(ISDestroy(&pcbddc->user_primal_vertices_local));
520   pcbddc->user_primal_vertices_local = PrimalVertices;
521   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
522   PetscFunctionReturn(PETSC_SUCCESS);
523 }
524 
525 /*@
526   PCBDDCSetPrimalVerticesLocalIS - Set additional user defined primal vertices in `PCBDDC`
527 
528   Collective
529 
530   Input Parameters:
531 + pc             - the preconditioning context
532 - PrimalVertices - index set of primal vertices in local numbering (can be empty)
533 
534   Level: intermediate
535 
536 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetPrimalVerticesIS()`, `PCBDDCGetPrimalVerticesIS()`, `PCBDDCGetPrimalVerticesLocalIS()`
537 @*/
538 PetscErrorCode PCBDDCSetPrimalVerticesLocalIS(PC pc, IS PrimalVertices)
539 {
540   PetscFunctionBegin;
541   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
542   PetscValidHeaderSpecific(PrimalVertices, IS_CLASSID, 2);
543   PetscCheckSameComm(pc, 1, PrimalVertices, 2);
544   PetscTryMethod(pc, "PCBDDCSetPrimalVerticesLocalIS_C", (PC, IS), (pc, PrimalVertices));
545   PetscFunctionReturn(PETSC_SUCCESS);
546 }
547 
548 static PetscErrorCode PCBDDCGetPrimalVerticesLocalIS_BDDC(PC pc, IS *is)
549 {
550   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
551 
552   PetscFunctionBegin;
553   *is = pcbddc->user_primal_vertices_local;
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 /*@
558   PCBDDCGetPrimalVerticesLocalIS - Get user defined primal vertices set with `PCBDDCSetPrimalVerticesLocalIS()`
559 
560   Collective
561 
562   Input Parameter:
563 . pc - the preconditioning context
564 
565   Output Parameter:
566 . is - index set of primal vertices in local numbering (`NULL` if not set)
567 
568   Level: intermediate
569 
570 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetPrimalVerticesIS()`, `PCBDDCGetPrimalVerticesIS()`, `PCBDDCSetPrimalVerticesLocalIS()`
571 @*/
572 PetscErrorCode PCBDDCGetPrimalVerticesLocalIS(PC pc, IS *is)
573 {
574   PetscFunctionBegin;
575   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
576   PetscAssertPointer(is, 2);
577   PetscUseMethod(pc, "PCBDDCGetPrimalVerticesLocalIS_C", (PC, IS *), (pc, is));
578   PetscFunctionReturn(PETSC_SUCCESS);
579 }
580 
581 static PetscErrorCode PCBDDCSetCoarseningRatio_BDDC(PC pc, PetscInt k)
582 {
583   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
584 
585   PetscFunctionBegin;
586   pcbddc->coarsening_ratio = k;
587   PetscFunctionReturn(PETSC_SUCCESS);
588 }
589 
590 /*@
591   PCBDDCSetCoarseningRatio - Set coarsening ratio used in the multi-level version of `PCBDDC`
592 
593   Logically Collective
594 
595   Input Parameters:
596 + pc - the preconditioning context
597 - k  - coarsening ratio (H/h at the coarser level)
598 
599   Options Database Key:
600 . -pc_bddc_coarsening_ratio <int> - Set the coarsening ratio used in multi-level coarsening
601 
602   Level: intermediate
603 
604   Note:
605   Approximately `k` subdomains at the finer level will be aggregated into a single subdomain at the coarser level
606 
607 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetLevels()`
608 @*/
609 PetscErrorCode PCBDDCSetCoarseningRatio(PC pc, PetscInt k)
610 {
611   PetscFunctionBegin;
612   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
613   PetscValidLogicalCollectiveInt(pc, k, 2);
614   PetscTryMethod(pc, "PCBDDCSetCoarseningRatio_C", (PC, PetscInt), (pc, k));
615   PetscFunctionReturn(PETSC_SUCCESS);
616 }
617 
618 /* The following functions (PCBDDCSetUseExactDirichlet PCBDDCSetLevel) are not public */
619 static PetscErrorCode PCBDDCSetUseExactDirichlet_BDDC(PC pc, PetscBool flg)
620 {
621   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
622 
623   PetscFunctionBegin;
624   pcbddc->use_exact_dirichlet_trick = flg;
625   PetscFunctionReturn(PETSC_SUCCESS);
626 }
627 
628 PetscErrorCode PCBDDCSetUseExactDirichlet(PC pc, PetscBool flg)
629 {
630   PetscFunctionBegin;
631   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
632   PetscValidLogicalCollectiveBool(pc, flg, 2);
633   PetscTryMethod(pc, "PCBDDCSetUseExactDirichlet_C", (PC, PetscBool), (pc, flg));
634   PetscFunctionReturn(PETSC_SUCCESS);
635 }
636 
637 static PetscErrorCode PCBDDCSetLevel_BDDC(PC pc, PetscInt level)
638 {
639   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
640 
641   PetscFunctionBegin;
642   pcbddc->current_level = level;
643   PetscFunctionReturn(PETSC_SUCCESS);
644 }
645 
646 PetscErrorCode PCBDDCSetLevel(PC pc, PetscInt level)
647 {
648   PetscFunctionBegin;
649   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
650   PetscValidLogicalCollectiveInt(pc, level, 2);
651   PetscTryMethod(pc, "PCBDDCSetLevel_C", (PC, PetscInt), (pc, level));
652   PetscFunctionReturn(PETSC_SUCCESS);
653 }
654 
655 static PetscErrorCode PCBDDCSetLevels_BDDC(PC pc, PetscInt levels)
656 {
657   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
658 
659   PetscFunctionBegin;
660   PetscCheck(levels < PETSC_PCBDDC_MAXLEVELS, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Maximum number of additional levels for BDDC is %d", PETSC_PCBDDC_MAXLEVELS - 1);
661   pcbddc->max_levels = levels;
662   PetscFunctionReturn(PETSC_SUCCESS);
663 }
664 
665 /*@
666   PCBDDCSetLevels - Sets the maximum number of additional levels allowed for multilevel `PCBDDC`
667 
668   Logically Collective
669 
670   Input Parameters:
671 + pc     - the preconditioning context
672 - levels - the maximum number of levels
673 
674   Options Database Key:
675 . -pc_bddc_levels <int> - Set maximum number of levels for multilevel
676 
677   Level: intermediate
678 
679   Note:
680   The default value is 0, that gives the classical two-levels BDDC algorithm
681 
682 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetCoarseningRatio()`
683 @*/
684 PetscErrorCode PCBDDCSetLevels(PC pc, PetscInt levels)
685 {
686   PetscFunctionBegin;
687   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
688   PetscValidLogicalCollectiveInt(pc, levels, 2);
689   PetscTryMethod(pc, "PCBDDCSetLevels_C", (PC, PetscInt), (pc, levels));
690   PetscFunctionReturn(PETSC_SUCCESS);
691 }
692 
693 static PetscErrorCode PCBDDCSetDirichletBoundaries_BDDC(PC pc, IS DirichletBoundaries)
694 {
695   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
696   PetscBool isequal = PETSC_FALSE;
697 
698   PetscFunctionBegin;
699   PetscCall(PetscObjectReference((PetscObject)DirichletBoundaries));
700   if (pcbddc->DirichletBoundaries) PetscCall(ISEqual(DirichletBoundaries, pcbddc->DirichletBoundaries, &isequal));
701   /* last user setting takes precedence -> destroy any other customization */
702   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
703   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
704   pcbddc->DirichletBoundaries = DirichletBoundaries;
705   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
706   PetscFunctionReturn(PETSC_SUCCESS);
707 }
708 
709 /*@
710   PCBDDCSetDirichletBoundaries - Set the `IS` defining Dirichlet boundaries for the global problem.
711 
712   Collective
713 
714   Input Parameters:
715 + pc                  - the preconditioning context
716 - DirichletBoundaries - parallel `IS` defining the Dirichlet boundaries
717 
718   Level: intermediate
719 
720   Note:
721   Provide the information if you used `MatZeroRows()` or `MatZeroRowsColumns()`. Any process can list any global node
722 
723 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDirichletBoundariesLocal()`, `MatZeroRows()`, `MatZeroRowsColumns()`
724 @*/
725 PetscErrorCode PCBDDCSetDirichletBoundaries(PC pc, IS DirichletBoundaries)
726 {
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
729   PetscValidHeaderSpecific(DirichletBoundaries, IS_CLASSID, 2);
730   PetscCheckSameComm(pc, 1, DirichletBoundaries, 2);
731   PetscTryMethod(pc, "PCBDDCSetDirichletBoundaries_C", (PC, IS), (pc, DirichletBoundaries));
732   PetscFunctionReturn(PETSC_SUCCESS);
733 }
734 
735 static PetscErrorCode PCBDDCSetDirichletBoundariesLocal_BDDC(PC pc, IS DirichletBoundaries)
736 {
737   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
738   PetscBool isequal = PETSC_FALSE;
739 
740   PetscFunctionBegin;
741   PetscCall(PetscObjectReference((PetscObject)DirichletBoundaries));
742   if (pcbddc->DirichletBoundariesLocal) PetscCall(ISEqual(DirichletBoundaries, pcbddc->DirichletBoundariesLocal, &isequal));
743   /* last user setting takes precedence -> destroy any other customization */
744   PetscCall(ISDestroy(&pcbddc->DirichletBoundariesLocal));
745   PetscCall(ISDestroy(&pcbddc->DirichletBoundaries));
746   pcbddc->DirichletBoundariesLocal = DirichletBoundaries;
747   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
748   PetscFunctionReturn(PETSC_SUCCESS);
749 }
750 
751 /*@
752   PCBDDCSetDirichletBoundariesLocal - Set the `IS` defining Dirichlet boundaries for the global problem in local ordering.
753 
754   Collective
755 
756   Input Parameters:
757 + pc                  - the preconditioning context
758 - DirichletBoundaries - parallel `IS` defining the Dirichlet boundaries (in local ordering)
759 
760   Level: intermediate
761 
762 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDirichletBoundaries()`, `MatZeroRows()`, `MatZeroRowsColumns()`
763 @*/
764 PetscErrorCode PCBDDCSetDirichletBoundariesLocal(PC pc, IS DirichletBoundaries)
765 {
766   PetscFunctionBegin;
767   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
768   PetscValidHeaderSpecific(DirichletBoundaries, IS_CLASSID, 2);
769   PetscCheckSameComm(pc, 1, DirichletBoundaries, 2);
770   PetscTryMethod(pc, "PCBDDCSetDirichletBoundariesLocal_C", (PC, IS), (pc, DirichletBoundaries));
771   PetscFunctionReturn(PETSC_SUCCESS);
772 }
773 
774 static PetscErrorCode PCBDDCSetNeumannBoundaries_BDDC(PC pc, IS NeumannBoundaries)
775 {
776   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
777   PetscBool isequal = PETSC_FALSE;
778 
779   PetscFunctionBegin;
780   PetscCall(PetscObjectReference((PetscObject)NeumannBoundaries));
781   if (pcbddc->NeumannBoundaries) PetscCall(ISEqual(NeumannBoundaries, pcbddc->NeumannBoundaries, &isequal));
782   /* last user setting takes precedence -> destroy any other customization */
783   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
784   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
785   pcbddc->NeumannBoundaries = NeumannBoundaries;
786   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
787   PetscFunctionReturn(PETSC_SUCCESS);
788 }
789 
790 /*@
791   PCBDDCSetNeumannBoundaries - Set the `IS` defining Neumann boundaries for the global problem.
792 
793   Collective
794 
795   Input Parameters:
796 + pc                - the preconditioning context
797 - NeumannBoundaries - parallel `IS` defining the Neumann boundaries
798 
799   Level: intermediate
800 
801   Note:
802   Any process can list any global node
803 
804 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetNeumannBoundariesLocal()`
805 @*/
806 PetscErrorCode PCBDDCSetNeumannBoundaries(PC pc, IS NeumannBoundaries)
807 {
808   PetscFunctionBegin;
809   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
810   PetscValidHeaderSpecific(NeumannBoundaries, IS_CLASSID, 2);
811   PetscCheckSameComm(pc, 1, NeumannBoundaries, 2);
812   PetscTryMethod(pc, "PCBDDCSetNeumannBoundaries_C", (PC, IS), (pc, NeumannBoundaries));
813   PetscFunctionReturn(PETSC_SUCCESS);
814 }
815 
816 static PetscErrorCode PCBDDCSetNeumannBoundariesLocal_BDDC(PC pc, IS NeumannBoundaries)
817 {
818   PC_BDDC  *pcbddc  = (PC_BDDC *)pc->data;
819   PetscBool isequal = PETSC_FALSE;
820 
821   PetscFunctionBegin;
822   PetscCall(PetscObjectReference((PetscObject)NeumannBoundaries));
823   if (pcbddc->NeumannBoundariesLocal) PetscCall(ISEqual(NeumannBoundaries, pcbddc->NeumannBoundariesLocal, &isequal));
824   /* last user setting takes precedence -> destroy any other customization */
825   PetscCall(ISDestroy(&pcbddc->NeumannBoundariesLocal));
826   PetscCall(ISDestroy(&pcbddc->NeumannBoundaries));
827   pcbddc->NeumannBoundariesLocal = NeumannBoundaries;
828   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
829   PetscFunctionReturn(PETSC_SUCCESS);
830 }
831 
832 /*@
833   PCBDDCSetNeumannBoundariesLocal - Set the `IS` defining Neumann boundaries for the global problem in local ordering.
834 
835   Collective
836 
837   Input Parameters:
838 + pc                - the preconditioning context
839 - NeumannBoundaries - parallel `IS` defining the subdomain part of Neumann boundaries (in local ordering)
840 
841   Level: intermediate
842 
843 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetNeumannBoundaries()`, `PCBDDCGetDirichletBoundaries()`
844 @*/
845 PetscErrorCode PCBDDCSetNeumannBoundariesLocal(PC pc, IS NeumannBoundaries)
846 {
847   PetscFunctionBegin;
848   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
849   PetscValidHeaderSpecific(NeumannBoundaries, IS_CLASSID, 2);
850   PetscCheckSameComm(pc, 1, NeumannBoundaries, 2);
851   PetscTryMethod(pc, "PCBDDCSetNeumannBoundariesLocal_C", (PC, IS), (pc, NeumannBoundaries));
852   PetscFunctionReturn(PETSC_SUCCESS);
853 }
854 
855 static PetscErrorCode PCBDDCGetDirichletBoundaries_BDDC(PC pc, IS *DirichletBoundaries)
856 {
857   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
858 
859   PetscFunctionBegin;
860   *DirichletBoundaries = pcbddc->DirichletBoundaries;
861   PetscFunctionReturn(PETSC_SUCCESS);
862 }
863 
864 /*@
865   PCBDDCGetDirichletBoundaries - Get parallel `IS` for Dirichlet boundaries
866 
867   Collective
868 
869   Input Parameter:
870 . pc - the preconditioning context
871 
872   Output Parameter:
873 . DirichletBoundaries - index set defining the Dirichlet boundaries
874 
875   Level: intermediate
876 
877   Note:
878   The `IS` returned (if any) is the same passed in earlier by the user with `PCBDDCSetDirichletBoundaries()`
879 
880 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDirichletBoundaries()`
881 @*/
882 PetscErrorCode PCBDDCGetDirichletBoundaries(PC pc, IS *DirichletBoundaries)
883 {
884   PetscFunctionBegin;
885   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
886   PetscUseMethod(pc, "PCBDDCGetDirichletBoundaries_C", (PC, IS *), (pc, DirichletBoundaries));
887   PetscFunctionReturn(PETSC_SUCCESS);
888 }
889 
890 static PetscErrorCode PCBDDCGetDirichletBoundariesLocal_BDDC(PC pc, IS *DirichletBoundaries)
891 {
892   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
893 
894   PetscFunctionBegin;
895   *DirichletBoundaries = pcbddc->DirichletBoundariesLocal;
896   PetscFunctionReturn(PETSC_SUCCESS);
897 }
898 
899 /*@
900   PCBDDCGetDirichletBoundariesLocal - Get parallel `IS` for Dirichlet boundaries (in local ordering)
901 
902   Collective
903 
904   Input Parameter:
905 . pc - the preconditioning context
906 
907   Output Parameter:
908 . DirichletBoundaries - index set defining the subdomain part of Dirichlet boundaries
909 
910   Level: intermediate
911 
912   Note:
913   The `IS` returned could be the same passed in earlier by the user (if provided with `PCBDDCSetDirichletBoundariesLocal()`)
914   or a global-to-local map of the global `IS` (if provided with `PCBDDCSetDirichletBoundaries()`).
915   In the latter case, the `IS` will be available only after `PCSetUp()`.
916 
917 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCGetDirichletBoundaries()`, `PCBDDCSetDirichletBoundaries()`
918 @*/
919 PetscErrorCode PCBDDCGetDirichletBoundariesLocal(PC pc, IS *DirichletBoundaries)
920 {
921   PetscFunctionBegin;
922   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
923   PetscUseMethod(pc, "PCBDDCGetDirichletBoundariesLocal_C", (PC, IS *), (pc, DirichletBoundaries));
924   PetscFunctionReturn(PETSC_SUCCESS);
925 }
926 
927 static PetscErrorCode PCBDDCGetNeumannBoundaries_BDDC(PC pc, IS *NeumannBoundaries)
928 {
929   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
930 
931   PetscFunctionBegin;
932   *NeumannBoundaries = pcbddc->NeumannBoundaries;
933   PetscFunctionReturn(PETSC_SUCCESS);
934 }
935 
936 /*@
937   PCBDDCGetNeumannBoundaries - Get parallel `IS` for Neumann boundaries
938 
939   Not Collective
940 
941   Input Parameter:
942 . pc - the preconditioning context
943 
944   Output Parameter:
945 . NeumannBoundaries - index set defining the Neumann boundaries
946 
947   Level: intermediate
948 
949   Note:
950   The `IS` returned (if any) is the same passed in earlier by the user with `PCBDDCSetNeumannBoundaries()`
951 
952 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetNeumannBoundaries()`, `PCBDDCGetDirichletBoundaries()`, `PCBDDCSetDirichletBoundaries()`
953 @*/
954 PetscErrorCode PCBDDCGetNeumannBoundaries(PC pc, IS *NeumannBoundaries)
955 {
956   PetscFunctionBegin;
957   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
958   PetscUseMethod(pc, "PCBDDCGetNeumannBoundaries_C", (PC, IS *), (pc, NeumannBoundaries));
959   PetscFunctionReturn(PETSC_SUCCESS);
960 }
961 
962 static PetscErrorCode PCBDDCGetNeumannBoundariesLocal_BDDC(PC pc, IS *NeumannBoundaries)
963 {
964   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
965 
966   PetscFunctionBegin;
967   *NeumannBoundaries = pcbddc->NeumannBoundariesLocal;
968   PetscFunctionReturn(PETSC_SUCCESS);
969 }
970 
971 /*@
972   PCBDDCGetNeumannBoundariesLocal - Get parallel `IS` for Neumann boundaries (in local ordering)
973 
974   Not Collective
975 
976   Input Parameter:
977 . pc - the preconditioning context
978 
979   Output Parameter:
980 . NeumannBoundaries - index set defining the subdomain part of Neumann boundaries
981 
982   Level: intermediate
983 
984   Note:
985   The `IS` returned could be the same passed in earlier by the user (if provided with `PCBDDCSetNeumannBoundariesLocal()`
986   or a global-to-local map of the global `IS` (if provided with `PCBDDCSetNeumannBoundaries()`).
987   In the latter case, the `IS` will be available after `PCSetUp()`.
988 
989 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetNeumannBoundaries()`, `PCBDDCSetNeumannBoundariesLocal)`, `PCBDDCGetNeumannBoundaries()`
990 @*/
991 PetscErrorCode PCBDDCGetNeumannBoundariesLocal(PC pc, IS *NeumannBoundaries)
992 {
993   PetscFunctionBegin;
994   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
995   PetscUseMethod(pc, "PCBDDCGetNeumannBoundariesLocal_C", (PC, IS *), (pc, NeumannBoundaries));
996   PetscFunctionReturn(PETSC_SUCCESS);
997 }
998 
999 static PetscErrorCode PCBDDCSetLocalAdjacencyGraph_BDDC(PC pc, PetscInt nvtxs, const PetscInt xadj[], const PetscInt adjncy[], PetscCopyMode copymode)
1000 {
1001   PC_BDDC    *pcbddc    = (PC_BDDC *)pc->data;
1002   PCBDDCGraph mat_graph = pcbddc->mat_graph;
1003   PetscBool   same_data = PETSC_FALSE;
1004 
1005   PetscFunctionBegin;
1006   if (!nvtxs) {
1007     if (copymode == PETSC_OWN_POINTER) {
1008       PetscCall(PetscFree(xadj));
1009       PetscCall(PetscFree(adjncy));
1010     }
1011     PetscCall(PCBDDCGraphResetCSR(mat_graph));
1012     PetscFunctionReturn(PETSC_SUCCESS);
1013   }
1014   if (mat_graph->nvtxs == nvtxs && mat_graph->freecsr) { /* we own the data */
1015     if (mat_graph->xadj == xadj && mat_graph->adjncy == adjncy) same_data = PETSC_TRUE;
1016     if (!same_data && mat_graph->xadj[nvtxs] == xadj[nvtxs]) {
1017       PetscCall(PetscArraycmp(xadj, mat_graph->xadj, nvtxs + 1, &same_data));
1018       if (same_data) PetscCall(PetscArraycmp(adjncy, mat_graph->adjncy, xadj[nvtxs], &same_data));
1019     }
1020   }
1021   if (!same_data) {
1022     /* free old CSR */
1023     PetscCall(PCBDDCGraphResetCSR(mat_graph));
1024     /* get CSR into graph structure */
1025     if (copymode == PETSC_COPY_VALUES) {
1026       PetscCall(PetscMalloc1(nvtxs + 1, &mat_graph->xadj));
1027       PetscCall(PetscMalloc1(xadj[nvtxs], &mat_graph->adjncy));
1028       PetscCall(PetscArraycpy(mat_graph->xadj, xadj, nvtxs + 1));
1029       PetscCall(PetscArraycpy(mat_graph->adjncy, adjncy, xadj[nvtxs]));
1030       mat_graph->freecsr = PETSC_TRUE;
1031     } else if (copymode == PETSC_OWN_POINTER) {
1032       mat_graph->xadj    = (PetscInt *)xadj;
1033       mat_graph->adjncy  = (PetscInt *)adjncy;
1034       mat_graph->freecsr = PETSC_TRUE;
1035     } else if (copymode == PETSC_USE_POINTER) {
1036       mat_graph->xadj    = (PetscInt *)xadj;
1037       mat_graph->adjncy  = (PetscInt *)adjncy;
1038       mat_graph->freecsr = PETSC_FALSE;
1039     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported copy mode %d", copymode);
1040     mat_graph->nvtxs_csr         = nvtxs;
1041     pcbddc->recompute_topography = PETSC_TRUE;
1042   }
1043   PetscFunctionReturn(PETSC_SUCCESS);
1044 }
1045 
1046 /*@
1047   PCBDDCSetLocalAdjacencyGraph - Set adjacency structure (CSR graph) of the local degrees of freedom.
1048 
1049   Not collective
1050 
1051   Input Parameters:
1052 + pc       - the preconditioning context.
1053 . nvtxs    - number of local vertices of the graph (i.e., the number of local dofs).
1054 . xadj     - CSR format row pointers for the connectivity of the dofs
1055 . adjncy   - CSR format column pointers for the connectivity of the dofs
1056 - copymode - supported modes are `PETSC_COPY_VALUES`, `PETSC_USE_POINTER` or `PETSC_OWN_POINTER`.
1057 
1058   Level: intermediate
1059 
1060   Note:
1061   A dof is considered connected with all local dofs if xadj[dof+1]-xadj[dof] == 1 and adjncy[xadj[dof]] is negative.
1062 
1063 .seealso: [](ch_ksp), `PCBDDC`, `PetscCopyMode`
1064 @*/
1065 PetscErrorCode PCBDDCSetLocalAdjacencyGraph(PC pc, PetscInt nvtxs, const PetscInt xadj[], const PetscInt adjncy[], PetscCopyMode copymode)
1066 {
1067   void (*f)(void) = NULL;
1068 
1069   PetscFunctionBegin;
1070   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1071   if (nvtxs) {
1072     PetscAssertPointer(xadj, 3);
1073     if (xadj[nvtxs]) PetscAssertPointer(adjncy, 4);
1074   }
1075   PetscTryMethod(pc, "PCBDDCSetLocalAdjacencyGraph_C", (PC, PetscInt, const PetscInt[], const PetscInt[], PetscCopyMode), (pc, nvtxs, xadj, adjncy, copymode));
1076   /* free arrays if PCBDDC is not the PC type */
1077   PetscCall(PetscObjectQueryFunction((PetscObject)pc, "PCBDDCSetLocalAdjacencyGraph_C", &f));
1078   if (!f && copymode == PETSC_OWN_POINTER) {
1079     PetscCall(PetscFree(xadj));
1080     PetscCall(PetscFree(adjncy));
1081   }
1082   PetscFunctionReturn(PETSC_SUCCESS);
1083 }
1084 
1085 static PetscErrorCode PCBDDCSetDofsSplittingLocal_BDDC(PC pc, PetscInt n_is, IS ISForDofs[])
1086 {
1087   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
1088   PetscInt  i;
1089   PetscBool isequal = PETSC_FALSE;
1090 
1091   PetscFunctionBegin;
1092   if (pcbddc->n_ISForDofsLocal == n_is) {
1093     for (i = 0; i < n_is; i++) {
1094       PetscBool isequalt;
1095       PetscCall(ISEqual(ISForDofs[i], pcbddc->ISForDofsLocal[i], &isequalt));
1096       if (!isequalt) break;
1097     }
1098     if (i == n_is) isequal = PETSC_TRUE;
1099   }
1100   for (i = 0; i < n_is; i++) PetscCall(PetscObjectReference((PetscObject)ISForDofs[i]));
1101   /* Destroy ISes if they were already set */
1102   for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(ISDestroy(&pcbddc->ISForDofsLocal[i]));
1103   PetscCall(PetscFree(pcbddc->ISForDofsLocal));
1104   /* last user setting takes precedence -> destroy any other customization */
1105   for (i = 0; i < pcbddc->n_ISForDofs; i++) PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
1106   PetscCall(PetscFree(pcbddc->ISForDofs));
1107   pcbddc->n_ISForDofs = 0;
1108   /* allocate space then set */
1109   if (n_is) PetscCall(PetscMalloc1(n_is, &pcbddc->ISForDofsLocal));
1110   for (i = 0; i < n_is; i++) pcbddc->ISForDofsLocal[i] = ISForDofs[i];
1111   pcbddc->n_ISForDofsLocal = n_is;
1112   if (n_is) pcbddc->user_provided_isfordofs = PETSC_TRUE;
1113   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
1114   PetscFunctionReturn(PETSC_SUCCESS);
1115 }
1116 
1117 /*@
1118   PCBDDCSetDofsSplittingLocal - Set the `IS` defining fields of the local subdomain matrix
1119 
1120   Collective
1121 
1122   Input Parameters:
1123 + pc        - the preconditioning context
1124 . n_is      - number of index sets defining the fields, must be the same on all MPI processes
1125 - ISForDofs - array of `IS` describing the fields in local ordering
1126 
1127   Level: intermediate
1128 
1129   Note:
1130   Not all nodes need to be listed, unlisted nodes will belong to the complement field.
1131 
1132 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDofsSplitting()`
1133 @*/
1134 PetscErrorCode PCBDDCSetDofsSplittingLocal(PC pc, PetscInt n_is, IS ISForDofs[])
1135 {
1136   PetscInt i;
1137 
1138   PetscFunctionBegin;
1139   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1140   PetscValidLogicalCollectiveInt(pc, n_is, 2);
1141   for (i = 0; i < n_is; i++) {
1142     PetscCheckSameComm(pc, 1, ISForDofs[i], 3);
1143     PetscValidHeaderSpecific(ISForDofs[i], IS_CLASSID, 3);
1144   }
1145   PetscTryMethod(pc, "PCBDDCSetDofsSplittingLocal_C", (PC, PetscInt, IS[]), (pc, n_is, ISForDofs));
1146   PetscFunctionReturn(PETSC_SUCCESS);
1147 }
1148 
1149 static PetscErrorCode PCBDDCSetDofsSplitting_BDDC(PC pc, PetscInt n_is, IS ISForDofs[])
1150 {
1151   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
1152   PetscInt  i;
1153   PetscBool isequal = PETSC_FALSE;
1154 
1155   PetscFunctionBegin;
1156   if (pcbddc->n_ISForDofs == n_is) {
1157     for (i = 0; i < n_is; i++) {
1158       PetscBool isequalt;
1159       PetscCall(ISEqual(ISForDofs[i], pcbddc->ISForDofs[i], &isequalt));
1160       if (!isequalt) break;
1161     }
1162     if (i == n_is) isequal = PETSC_TRUE;
1163   }
1164   for (i = 0; i < n_is; i++) PetscCall(PetscObjectReference((PetscObject)ISForDofs[i]));
1165   /* Destroy ISes if they were already set */
1166   for (i = 0; i < pcbddc->n_ISForDofs; i++) PetscCall(ISDestroy(&pcbddc->ISForDofs[i]));
1167   PetscCall(PetscFree(pcbddc->ISForDofs));
1168   /* last user setting takes precedence -> destroy any other customization */
1169   for (i = 0; i < pcbddc->n_ISForDofsLocal; i++) PetscCall(ISDestroy(&pcbddc->ISForDofsLocal[i]));
1170   PetscCall(PetscFree(pcbddc->ISForDofsLocal));
1171   pcbddc->n_ISForDofsLocal = 0;
1172   /* allocate space then set */
1173   if (n_is) PetscCall(PetscMalloc1(n_is, &pcbddc->ISForDofs));
1174   for (i = 0; i < n_is; i++) pcbddc->ISForDofs[i] = ISForDofs[i];
1175   pcbddc->n_ISForDofs = n_is;
1176   if (n_is) pcbddc->user_provided_isfordofs = PETSC_TRUE;
1177   if (!isequal) pcbddc->recompute_topography = PETSC_TRUE;
1178   PetscFunctionReturn(PETSC_SUCCESS);
1179 }
1180 
1181 /*@
1182   PCBDDCSetDofsSplitting - Set the `IS` defining fields of the global matrix
1183 
1184   Collective
1185 
1186   Input Parameters:
1187 + pc        - the preconditioning context
1188 . n_is      - number of index sets defining the fields
1189 - ISForDofs - array of `IS` describing the fields in global ordering
1190 
1191   Level: intermediate
1192 
1193   Note:
1194   Any process can list any global node. Not all nodes need to be listed: unlisted nodes will belong to the complement field.
1195 
1196 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCSetDofsSplittingLocal()`
1197 @*/
1198 PetscErrorCode PCBDDCSetDofsSplitting(PC pc, PetscInt n_is, IS ISForDofs[])
1199 {
1200   PetscInt i;
1201 
1202   PetscFunctionBegin;
1203   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1204   PetscValidLogicalCollectiveInt(pc, n_is, 2);
1205   for (i = 0; i < n_is; i++) {
1206     PetscValidHeaderSpecific(ISForDofs[i], IS_CLASSID, 3);
1207     PetscCheckSameComm(pc, 1, ISForDofs[i], 3);
1208   }
1209   PetscTryMethod(pc, "PCBDDCSetDofsSplitting_C", (PC, PetscInt, IS[]), (pc, n_is, ISForDofs));
1210   PetscFunctionReturn(PETSC_SUCCESS);
1211 }
1212 
1213 /*
1214    PCPreSolve_BDDC - Changes the right hand side and (if necessary) the initial
1215                      guess if a transformation of basis approach has been selected.
1216 
1217    Input Parameter:
1218 +  pc - the preconditioner context
1219 
1220    Note:
1221      The interface routine PCPreSolve() is not usually called directly by
1222    the user, but instead is called by KSPSolve().
1223 */
1224 static PetscErrorCode PCPreSolve_BDDC(PC pc, KSP ksp, Vec rhs, Vec x)
1225 {
1226   PC_BDDC  *pcbddc = (PC_BDDC *)pc->data;
1227   PC_IS    *pcis   = (PC_IS *)(pc->data);
1228   Vec       used_vec;
1229   PetscBool iscg, save_rhs = PETSC_TRUE, benign_correction_computed;
1230 
1231   PetscFunctionBegin;
1232   /* if we are working with CG, one dirichlet solve can be avoided during Krylov iterations */
1233   if (ksp) {
1234     PetscCall(PetscObjectTypeCompareAny((PetscObject)ksp, &iscg, KSPCG, KSPGROPPCG, KSPPIPECG, KSPPIPELCG, KSPPIPECGRR, ""));
1235     if (pcbddc->benign_apply_coarse_only || pcbddc->switch_static || !iscg || pc->mat != pc->pmat) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
1236   }
1237   if (pcbddc->benign_apply_coarse_only || pcbddc->switch_static || pc->mat != pc->pmat) PetscCall(PCBDDCSetUseExactDirichlet(pc, PETSC_FALSE));
1238 
1239   /* Creates parallel work vectors used in presolve */
1240   if (!pcbddc->original_rhs) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->original_rhs));
1241   if (!pcbddc->temp_solution) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->temp_solution));
1242 
1243   pcbddc->temp_solution_used = PETSC_FALSE;
1244   if (x) {
1245     PetscCall(PetscObjectReference((PetscObject)x));
1246     used_vec = x;
1247   } else { /* it can only happen when calling PCBDDCMatFETIDPGetRHS */
1248     PetscCall(PetscObjectReference((PetscObject)pcbddc->temp_solution));
1249     used_vec = pcbddc->temp_solution;
1250     PetscCall(VecSet(used_vec, 0.0));
1251     pcbddc->temp_solution_used = PETSC_TRUE;
1252     PetscCall(VecCopy(rhs, pcbddc->original_rhs));
1253     save_rhs                  = PETSC_FALSE;
1254     pcbddc->eliminate_dirdofs = PETSC_TRUE;
1255   }
1256 
1257   /* hack into ksp data structure since PCPreSolve comes earlier than setting to zero the guess in src/ksp/ksp/interface/itfunc.c */
1258   if (ksp) {
1259     /* store the flag for the initial guess since it will be restored back during PCPostSolve_BDDC */
1260     PetscCall(KSPGetInitialGuessNonzero(ksp, &pcbddc->ksp_guess_nonzero));
1261     if (!pcbddc->ksp_guess_nonzero) PetscCall(VecSet(used_vec, 0.0));
1262   }
1263 
1264   pcbddc->rhs_change = PETSC_FALSE;
1265   /* Take into account zeroed rows -> change rhs and store solution removed */
1266   if (rhs && pcbddc->eliminate_dirdofs) {
1267     IS dirIS = NULL;
1268 
1269     /* DirichletBoundariesLocal may not be consistent among neighbours; gets a dirichlet dofs IS from graph (may be cached) */
1270     PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph, &dirIS));
1271     if (dirIS) {
1272       Mat_IS            *matis = (Mat_IS *)pc->pmat->data;
1273       PetscInt           dirsize, i, *is_indices;
1274       PetscScalar       *array_x;
1275       const PetscScalar *array_diagonal;
1276 
1277       PetscCall(MatGetDiagonal(pc->pmat, pcis->vec1_global));
1278       PetscCall(VecPointwiseDivide(pcis->vec1_global, rhs, pcis->vec1_global));
1279       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
1280       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_global, pcis->vec2_N, INSERT_VALUES, SCATTER_FORWARD));
1281       PetscCall(VecScatterBegin(matis->rctx, used_vec, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
1282       PetscCall(VecScatterEnd(matis->rctx, used_vec, pcis->vec1_N, INSERT_VALUES, SCATTER_FORWARD));
1283       PetscCall(ISGetLocalSize(dirIS, &dirsize));
1284       PetscCall(VecGetArray(pcis->vec1_N, &array_x));
1285       PetscCall(VecGetArrayRead(pcis->vec2_N, &array_diagonal));
1286       PetscCall(ISGetIndices(dirIS, (const PetscInt **)&is_indices));
1287       for (i = 0; i < dirsize; i++) array_x[is_indices[i]] = array_diagonal[is_indices[i]];
1288       PetscCall(ISRestoreIndices(dirIS, (const PetscInt **)&is_indices));
1289       PetscCall(VecRestoreArrayRead(pcis->vec2_N, &array_diagonal));
1290       PetscCall(VecRestoreArray(pcis->vec1_N, &array_x));
1291       PetscCall(VecScatterBegin(matis->rctx, pcis->vec1_N, used_vec, INSERT_VALUES, SCATTER_REVERSE));
1292       PetscCall(VecScatterEnd(matis->rctx, pcis->vec1_N, used_vec, INSERT_VALUES, SCATTER_REVERSE));
1293       pcbddc->rhs_change = PETSC_TRUE;
1294       PetscCall(ISDestroy(&dirIS));
1295     }
1296   }
1297 
1298   /* remove the computed solution or the initial guess from the rhs */
1299   if (pcbddc->rhs_change || (ksp && pcbddc->ksp_guess_nonzero)) {
1300     /* save the original rhs */
1301     if (save_rhs) {
1302       PetscCall(VecSwap(rhs, pcbddc->original_rhs));
1303       save_rhs = PETSC_FALSE;
1304     }
1305     pcbddc->rhs_change = PETSC_TRUE;
1306     PetscCall(VecScale(used_vec, -1.0));
1307     PetscCall(MatMultAdd(pc->mat, used_vec, pcbddc->original_rhs, rhs));
1308     PetscCall(VecScale(used_vec, -1.0));
1309     PetscCall(VecCopy(used_vec, pcbddc->temp_solution));
1310     pcbddc->temp_solution_used = PETSC_TRUE;
1311     if (ksp) PetscCall(KSPSetInitialGuessNonzero(ksp, PETSC_FALSE));
1312   }
1313   PetscCall(VecDestroy(&used_vec));
1314 
1315   /* compute initial vector in benign space if needed
1316      and remove non-benign solution from the rhs */
1317   benign_correction_computed = PETSC_FALSE;
1318   if (rhs && pcbddc->benign_compute_correction && (pcbddc->benign_have_null || pcbddc->benign_apply_coarse_only)) {
1319     /* compute u^*_h using ideas similar to those in Xuemin Tu's PhD thesis (see Section 4.8.1)
1320        Recursively apply BDDC in the multilevel case */
1321     if (!pcbddc->benign_vec) PetscCall(VecDuplicate(rhs, &pcbddc->benign_vec));
1322     /* keep applying coarse solver unless we no longer have benign subdomains */
1323     pcbddc->benign_apply_coarse_only = pcbddc->benign_have_null ? PETSC_TRUE : PETSC_FALSE;
1324     if (!pcbddc->benign_skip_correction) {
1325       PetscCall(PCApply_BDDC(pc, rhs, pcbddc->benign_vec));
1326       benign_correction_computed = PETSC_TRUE;
1327       if (pcbddc->temp_solution_used) PetscCall(VecAXPY(pcbddc->temp_solution, 1.0, pcbddc->benign_vec));
1328       PetscCall(VecScale(pcbddc->benign_vec, -1.0));
1329       /* store the original rhs if not done earlier */
1330       if (save_rhs) PetscCall(VecSwap(rhs, pcbddc->original_rhs));
1331       if (pcbddc->rhs_change) {
1332         PetscCall(MatMultAdd(pc->mat, pcbddc->benign_vec, rhs, rhs));
1333       } else {
1334         PetscCall(MatMultAdd(pc->mat, pcbddc->benign_vec, pcbddc->original_rhs, rhs));
1335       }
1336       pcbddc->rhs_change = PETSC_TRUE;
1337     }
1338     pcbddc->benign_apply_coarse_only = PETSC_FALSE;
1339   } else {
1340     PetscCall(VecDestroy(&pcbddc->benign_vec));
1341   }
1342 
1343   /* dbg output */
1344   if (pcbddc->dbg_flag && benign_correction_computed) {
1345     Vec v;
1346 
1347     PetscCall(VecDuplicate(pcis->vec1_global, &v));
1348     if (pcbddc->ChangeOfBasisMatrix) {
1349       PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, rhs, v));
1350     } else {
1351       PetscCall(VecCopy(rhs, v));
1352     }
1353     PetscCall(PCBDDCBenignGetOrSetP0(pc, v, PETSC_TRUE));
1354     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer, "LEVEL %" PetscInt_FMT ": is the correction benign?\n", pcbddc->current_level));
1355     PetscCall(PetscScalarView(pcbddc->benign_n, pcbddc->benign_p0, pcbddc->dbg_viewer));
1356     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
1357     PetscCall(VecDestroy(&v));
1358   }
1359 
1360   /* set initial guess if using PCG */
1361   pcbddc->exact_dirichlet_trick_app = PETSC_FALSE;
1362   if (x && pcbddc->use_exact_dirichlet_trick) {
1363     PetscCall(VecSet(x, 0.0));
1364     if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior) {
1365       if (benign_correction_computed) { /* we have already saved the changed rhs */
1366         PetscCall(VecLockReadPop(pcis->vec1_global));
1367       } else {
1368         PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, rhs, pcis->vec1_global));
1369       }
1370       PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec1_global, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1371       PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec1_global, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1372     } else {
1373       PetscCall(VecScatterBegin(pcis->global_to_D, rhs, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1374       PetscCall(VecScatterEnd(pcis->global_to_D, rhs, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1375     }
1376     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1377     PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
1378     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1379     PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
1380     if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior) {
1381       PetscCall(VecSet(pcis->vec1_global, 0.));
1382       PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, pcis->vec1_global, INSERT_VALUES, SCATTER_REVERSE));
1383       PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, pcis->vec1_global, INSERT_VALUES, SCATTER_REVERSE));
1384       PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcis->vec1_global, x));
1385     } else {
1386       PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, x, INSERT_VALUES, SCATTER_REVERSE));
1387       PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, x, INSERT_VALUES, SCATTER_REVERSE));
1388     }
1389     if (ksp) PetscCall(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE));
1390     pcbddc->exact_dirichlet_trick_app = PETSC_TRUE;
1391   } else if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior && benign_correction_computed && pcbddc->use_exact_dirichlet_trick) {
1392     PetscCall(VecLockReadPop(pcis->vec1_global));
1393   }
1394   PetscFunctionReturn(PETSC_SUCCESS);
1395 }
1396 
1397 /*
1398    PCPostSolve_BDDC - Changes the computed solution if a transformation of basis
1399                      approach has been selected. Also, restores rhs to its original state.
1400 
1401    Input Parameter:
1402 +  pc - the preconditioner context
1403 
1404    Application Interface Routine: PCPostSolve()
1405 
1406    Note:
1407      The interface routine PCPostSolve() is not usually called directly by
1408      the user, but instead is called by KSPSolve().
1409 */
1410 static PetscErrorCode PCPostSolve_BDDC(PC pc, KSP ksp, Vec rhs, Vec x)
1411 {
1412   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
1413 
1414   PetscFunctionBegin;
1415   /* add solution removed in presolve */
1416   if (x && pcbddc->rhs_change) {
1417     if (pcbddc->temp_solution_used) {
1418       PetscCall(VecAXPY(x, 1.0, pcbddc->temp_solution));
1419     } else if (pcbddc->benign_compute_correction && pcbddc->benign_vec) {
1420       PetscCall(VecAXPY(x, -1.0, pcbddc->benign_vec));
1421     }
1422     /* restore to original state (not for FETI-DP) */
1423     if (ksp) pcbddc->temp_solution_used = PETSC_FALSE;
1424   }
1425 
1426   /* restore rhs to its original state (not needed for FETI-DP) */
1427   if (rhs && pcbddc->rhs_change) {
1428     PetscCall(VecSwap(rhs, pcbddc->original_rhs));
1429     pcbddc->rhs_change = PETSC_FALSE;
1430   }
1431   /* restore ksp guess state */
1432   if (ksp) {
1433     PetscCall(KSPSetInitialGuessNonzero(ksp, pcbddc->ksp_guess_nonzero));
1434     /* reset flag for exact dirichlet trick */
1435     pcbddc->exact_dirichlet_trick_app = PETSC_FALSE;
1436   }
1437   PetscFunctionReturn(PETSC_SUCCESS);
1438 }
1439 
1440 // PetscClangLinter pragma disable: -fdoc-sowing-chars
1441 /*
1442   PCSetUp_BDDC - Prepares for the use of the BDDC preconditioner
1443   by setting data structures and options.
1444 
1445   Input Parameter:
1446 . pc - the preconditioner context
1447 
1448    Application Interface Routine: PCSetUp()
1449 
1450 */
1451 static PetscErrorCode PCSetUp_BDDC(PC pc)
1452 {
1453   PC_BDDC        *pcbddc = (PC_BDDC *)pc->data;
1454   PCBDDCSubSchurs sub_schurs;
1455   Mat_IS         *matis;
1456   MatNullSpace    nearnullspace;
1457   Mat             lA;
1458   IS              lP, zerodiag = NULL;
1459   PetscInt        nrows, ncols;
1460   PetscMPIInt     size;
1461   PetscBool       computesubschurs;
1462   PetscBool       computeconstraintsmatrix;
1463   PetscBool       new_nearnullspace_provided, ismatis, rl;
1464   PetscBool       isset, issym, isspd;
1465 
1466   PetscFunctionBegin;
1467   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATIS, &ismatis));
1468   PetscCheck(ismatis, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "PCBDDC preconditioner requires matrix of type MATIS");
1469   PetscCall(MatGetSize(pc->pmat, &nrows, &ncols));
1470   PetscCheck(nrows == ncols, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCBDDC preconditioner requires a square preconditioning matrix");
1471   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
1472 
1473   matis = (Mat_IS *)pc->pmat->data;
1474   /* the following lines of code should be replaced by a better logic between PCIS, PCNN, PCBDDC and other future nonoverlapping preconditioners */
1475   /* For BDDC we need to define a local "Neumann" problem different to that defined in PCISSetup
1476      Also, BDDC builds its own KSP for the Dirichlet problem */
1477   rl = pcbddc->recompute_topography;
1478   if (!pc->setupcalled || pc->flag == DIFFERENT_NONZERO_PATTERN) rl = PETSC_TRUE;
1479   PetscCall(MPIU_Allreduce(&rl, &pcbddc->recompute_topography, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)pc)));
1480   if (pcbddc->recompute_topography) {
1481     pcbddc->graphanalyzed    = PETSC_FALSE;
1482     computeconstraintsmatrix = PETSC_TRUE;
1483   } else {
1484     computeconstraintsmatrix = PETSC_FALSE;
1485   }
1486 
1487   /* check parameters' compatibility */
1488   if (!pcbddc->use_deluxe_scaling) pcbddc->deluxe_zerorows = PETSC_FALSE;
1489   pcbddc->adaptive_selection   = (PetscBool)(pcbddc->adaptive_threshold[0] != 0.0 || pcbddc->adaptive_threshold[1] != 0.0);
1490   pcbddc->use_deluxe_scaling   = (PetscBool)(pcbddc->use_deluxe_scaling && size > 1);
1491   pcbddc->adaptive_selection   = (PetscBool)(pcbddc->adaptive_selection && size > 1);
1492   pcbddc->adaptive_userdefined = (PetscBool)(pcbddc->adaptive_selection && pcbddc->adaptive_userdefined);
1493   if (pcbddc->adaptive_selection) pcbddc->use_faces = PETSC_TRUE;
1494 
1495   computesubschurs = (PetscBool)(pcbddc->adaptive_selection || pcbddc->use_deluxe_scaling);
1496 
1497   /* activate all connected components if the netflux has been requested */
1498   if (pcbddc->compute_nonetflux) {
1499     pcbddc->use_vertices = PETSC_TRUE;
1500     pcbddc->use_edges    = PETSC_TRUE;
1501     pcbddc->use_faces    = PETSC_TRUE;
1502   }
1503 
1504   /* Get stdout for dbg */
1505   if (pcbddc->dbg_flag) {
1506     if (!pcbddc->dbg_viewer) pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
1507     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
1508     PetscCall(PetscViewerASCIIAddTab(pcbddc->dbg_viewer, 2 * pcbddc->current_level));
1509   }
1510 
1511   /* process topology information */
1512   PetscCall(PetscLogEventBegin(PC_BDDC_Topology[pcbddc->current_level], pc, 0, 0, 0));
1513   if (pcbddc->recompute_topography) {
1514     PetscCall(PCBDDCComputeLocalTopologyInfo(pc));
1515     if (pcbddc->discretegradient) PetscCall(PCBDDCNedelecSupport(pc));
1516   }
1517   if (pcbddc->corner_selected) pcbddc->use_vertices = PETSC_TRUE;
1518 
1519   /* change basis if requested by the user */
1520   if (pcbddc->user_ChangeOfBasisMatrix) {
1521     /* use_change_of_basis flag is used to automatically compute a change of basis from constraints */
1522     pcbddc->use_change_of_basis = PETSC_FALSE;
1523     PetscCall(PCBDDCComputeLocalMatrix(pc, pcbddc->user_ChangeOfBasisMatrix));
1524   } else {
1525     PetscCall(MatDestroy(&pcbddc->local_mat));
1526     PetscCall(PetscObjectReference((PetscObject)matis->A));
1527     pcbddc->local_mat = matis->A;
1528   }
1529 
1530   /*
1531      Compute change of basis on local pressures (aka zerodiag dofs) with the benign trick
1532      This should come earlier then PCISSetUp for extracting the correct subdomain matrices
1533   */
1534   PetscCall(PCBDDCBenignShellMat(pc, PETSC_TRUE));
1535   if (pcbddc->benign_saddle_point) {
1536     PC_IS *pcis = (PC_IS *)pc->data;
1537 
1538     if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->use_change_of_basis || !computesubschurs) pcbddc->benign_change_explicit = PETSC_TRUE;
1539     /* detect local saddle point and change the basis in pcbddc->local_mat */
1540     PetscCall(PCBDDCBenignDetectSaddlePoint(pc, (PetscBool)(!pcbddc->recompute_topography), &zerodiag));
1541     /* pop B0 mat from local mat */
1542     PetscCall(PCBDDCBenignPopOrPushB0(pc, PETSC_TRUE));
1543     /* give pcis a hint to not reuse submatrices during PCISCreate */
1544     if (pc->flag == SAME_NONZERO_PATTERN && pcis->reusesubmatrices == PETSC_TRUE) {
1545       if (pcbddc->benign_n && (pcbddc->benign_change_explicit || pcbddc->dbg_flag)) {
1546         pcis->reusesubmatrices = PETSC_FALSE;
1547       } else {
1548         pcis->reusesubmatrices = PETSC_TRUE;
1549       }
1550     } else {
1551       pcis->reusesubmatrices = PETSC_FALSE;
1552     }
1553   }
1554 
1555   /* propagate relevant information */
1556   PetscCall(MatIsSymmetricKnown(matis->A, &isset, &issym));
1557   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SYMMETRIC, issym));
1558   PetscCall(MatIsSPDKnown(matis->A, &isset, &isspd));
1559   if (isset) PetscCall(MatSetOption(pcbddc->local_mat, MAT_SPD, isspd));
1560 
1561   /* Set up all the "iterative substructuring" common block without computing solvers */
1562   {
1563     Mat temp_mat;
1564 
1565     temp_mat = matis->A;
1566     matis->A = pcbddc->local_mat;
1567     PetscCall(PCISSetUp(pc, PETSC_TRUE, PETSC_FALSE));
1568     pcbddc->local_mat = matis->A;
1569     matis->A          = temp_mat;
1570   }
1571 
1572   /* Analyze interface */
1573   if (!pcbddc->graphanalyzed) {
1574     PetscCall(PCBDDCAnalyzeInterface(pc));
1575     computeconstraintsmatrix = PETSC_TRUE;
1576     PetscCheck(!(pcbddc->adaptive_selection && !pcbddc->use_deluxe_scaling && !pcbddc->mat_graph->twodim), PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot compute the adaptive primal space for a problem with 3D edges without deluxe scaling");
1577     if (pcbddc->compute_nonetflux) {
1578       MatNullSpace nnfnnsp;
1579 
1580       PetscCheck(pcbddc->divudotp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Missing divudotp operator");
1581       PetscCall(PCBDDCComputeNoNetFlux(pc->pmat, pcbddc->divudotp, pcbddc->divudotp_trans, pcbddc->divudotp_vl2l, pcbddc->mat_graph, &nnfnnsp));
1582       /* TODO what if a nearnullspace is already attached? */
1583       if (nnfnnsp) {
1584         PetscCall(MatSetNearNullSpace(pc->pmat, nnfnnsp));
1585         PetscCall(MatNullSpaceDestroy(&nnfnnsp));
1586       }
1587     }
1588   }
1589   PetscCall(PetscLogEventEnd(PC_BDDC_Topology[pcbddc->current_level], pc, 0, 0, 0));
1590 
1591   /* check existence of a divergence free extension, i.e.
1592      b(v_I,p_0) = 0 for all v_I (raise error if not).
1593      Also, check that PCBDDCBenignGetOrSetP0 works */
1594   if (pcbddc->benign_saddle_point && pcbddc->dbg_flag > 1) PetscCall(PCBDDCBenignCheck(pc, zerodiag));
1595   PetscCall(ISDestroy(&zerodiag));
1596 
1597   /* Setup local dirichlet solver ksp_D and sub_schurs solvers */
1598   if (computesubschurs && pcbddc->recompute_topography) PetscCall(PCBDDCInitSubSchurs(pc));
1599   /* SetUp Scaling operator (scaling matrices could be needed in SubSchursSetUp)*/
1600   if (!pcbddc->use_deluxe_scaling) PetscCall(PCBDDCScalingSetUp(pc));
1601 
1602   /* finish setup solvers and do adaptive selection of constraints */
1603   sub_schurs = pcbddc->sub_schurs;
1604   if (sub_schurs && sub_schurs->schur_explicit) {
1605     if (computesubschurs) PetscCall(PCBDDCSetUpSubSchurs(pc));
1606     PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_TRUE, PETSC_FALSE));
1607   } else {
1608     PetscCall(PCBDDCSetUpLocalSolvers(pc, PETSC_TRUE, PETSC_FALSE));
1609     if (computesubschurs) PetscCall(PCBDDCSetUpSubSchurs(pc));
1610   }
1611   if (pcbddc->adaptive_selection) {
1612     PetscCall(PCBDDCAdaptiveSelection(pc));
1613     computeconstraintsmatrix = PETSC_TRUE;
1614   }
1615 
1616   /* infer if NullSpace object attached to Mat via MatSetNearNullSpace has changed */
1617   new_nearnullspace_provided = PETSC_FALSE;
1618   PetscCall(MatGetNearNullSpace(pc->pmat, &nearnullspace));
1619   if (pcbddc->onearnullspace) { /* already used nearnullspace */
1620     if (!nearnullspace) {       /* near null space attached to mat has been destroyed */
1621       new_nearnullspace_provided = PETSC_TRUE;
1622     } else {
1623       /* determine if the two nullspaces are different (should be lightweight) */
1624       if (nearnullspace != pcbddc->onearnullspace) {
1625         new_nearnullspace_provided = PETSC_TRUE;
1626       } else { /* maybe the user has changed the content of the nearnullspace so check vectors ObjectStateId */
1627         PetscInt         i;
1628         const Vec       *nearnullvecs;
1629         PetscObjectState state;
1630         PetscInt         nnsp_size;
1631         PetscCall(MatNullSpaceGetVecs(nearnullspace, NULL, &nnsp_size, &nearnullvecs));
1632         for (i = 0; i < nnsp_size; i++) {
1633           PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i], &state));
1634           if (pcbddc->onearnullvecs_state[i] != state) {
1635             new_nearnullspace_provided = PETSC_TRUE;
1636             break;
1637           }
1638         }
1639       }
1640     }
1641   } else {
1642     if (!nearnullspace) { /* both nearnullspaces are null */
1643       new_nearnullspace_provided = PETSC_FALSE;
1644     } else { /* nearnullspace attached later */
1645       new_nearnullspace_provided = PETSC_TRUE;
1646     }
1647   }
1648 
1649   /* Setup constraints and related work vectors */
1650   /* reset primal space flags */
1651   PetscCall(PetscLogEventBegin(PC_BDDC_LocalWork[pcbddc->current_level], pc, 0, 0, 0));
1652   pcbddc->new_primal_space       = PETSC_FALSE;
1653   pcbddc->new_primal_space_local = PETSC_FALSE;
1654   if (computeconstraintsmatrix || new_nearnullspace_provided) {
1655     /* It also sets the primal space flags */
1656     PetscCall(PCBDDCConstraintsSetUp(pc));
1657   }
1658   /* Allocate needed local vectors (which depends on quantities defined during ConstraintsSetUp) */
1659   PetscCall(PCBDDCSetUpLocalWorkVectors(pc));
1660 
1661   if (pcbddc->use_change_of_basis) {
1662     PC_IS *pcis = (PC_IS *)(pc->data);
1663 
1664     PetscCall(PCBDDCComputeLocalMatrix(pc, pcbddc->ChangeOfBasisMatrix));
1665     if (pcbddc->benign_change) {
1666       PetscCall(MatDestroy(&pcbddc->benign_B0));
1667       /* pop B0 from pcbddc->local_mat */
1668       PetscCall(PCBDDCBenignPopOrPushB0(pc, PETSC_TRUE));
1669     }
1670     /* get submatrices */
1671     PetscCall(MatDestroy(&pcis->A_IB));
1672     PetscCall(MatDestroy(&pcis->A_BI));
1673     PetscCall(MatDestroy(&pcis->A_BB));
1674     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcis->is_B_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &pcis->A_BB));
1675     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcis->is_I_local, pcis->is_B_local, MAT_INITIAL_MATRIX, &pcis->A_IB));
1676     PetscCall(MatCreateSubMatrix(pcbddc->local_mat, pcis->is_B_local, pcis->is_I_local, MAT_INITIAL_MATRIX, &pcis->A_BI));
1677     /* set flag in pcis to not reuse submatrices during PCISCreate */
1678     pcis->reusesubmatrices = PETSC_FALSE;
1679   } else if (!pcbddc->user_ChangeOfBasisMatrix && !pcbddc->benign_change) {
1680     PetscCall(MatDestroy(&pcbddc->local_mat));
1681     PetscCall(PetscObjectReference((PetscObject)matis->A));
1682     pcbddc->local_mat = matis->A;
1683   }
1684 
1685   /* interface pressure block row for B_C */
1686   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lP", (PetscObject *)&lP));
1687   PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_lA", (PetscObject *)&lA));
1688   if (lA && lP) {
1689     PC_IS    *pcis = (PC_IS *)pc->data;
1690     Mat       B_BI, B_BB, Bt_BI, Bt_BB;
1691     PetscBool issym;
1692 
1693     PetscCall(MatIsSymmetric(lA, PETSC_SMALL, &issym));
1694     if (issym) {
1695       PetscCall(MatCreateSubMatrix(lA, lP, pcis->is_I_local, MAT_INITIAL_MATRIX, &B_BI));
1696       PetscCall(MatCreateSubMatrix(lA, lP, pcis->is_B_local, MAT_INITIAL_MATRIX, &B_BB));
1697       PetscCall(MatCreateTranspose(B_BI, &Bt_BI));
1698       PetscCall(MatCreateTranspose(B_BB, &Bt_BB));
1699     } else {
1700       PetscCall(MatCreateSubMatrix(lA, lP, pcis->is_I_local, MAT_INITIAL_MATRIX, &B_BI));
1701       PetscCall(MatCreateSubMatrix(lA, lP, pcis->is_B_local, MAT_INITIAL_MATRIX, &B_BB));
1702       PetscCall(MatCreateSubMatrix(lA, pcis->is_I_local, lP, MAT_INITIAL_MATRIX, &Bt_BI));
1703       PetscCall(MatCreateSubMatrix(lA, pcis->is_B_local, lP, MAT_INITIAL_MATRIX, &Bt_BB));
1704     }
1705     PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_B_BI", (PetscObject)B_BI));
1706     PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_B_BB", (PetscObject)B_BB));
1707     PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_Bt_BI", (PetscObject)Bt_BI));
1708     PetscCall(PetscObjectCompose((PetscObject)pc, "__KSPFETIDP_Bt_BB", (PetscObject)Bt_BB));
1709     PetscCall(MatDestroy(&B_BI));
1710     PetscCall(MatDestroy(&B_BB));
1711     PetscCall(MatDestroy(&Bt_BI));
1712     PetscCall(MatDestroy(&Bt_BB));
1713   }
1714   PetscCall(PetscLogEventEnd(PC_BDDC_LocalWork[pcbddc->current_level], pc, 0, 0, 0));
1715 
1716   /* SetUp coarse and local Neumann solvers */
1717   PetscCall(PCBDDCSetUpSolvers(pc));
1718   /* SetUp Scaling operator */
1719   if (pcbddc->use_deluxe_scaling) PetscCall(PCBDDCScalingSetUp(pc));
1720 
1721   /* mark topography as done */
1722   pcbddc->recompute_topography = PETSC_FALSE;
1723 
1724   /* wrap pcis->A_IB and pcis->A_BI if we did not change explicitly the variables on the pressures */
1725   PetscCall(PCBDDCBenignShellMat(pc, PETSC_FALSE));
1726 
1727   if (pcbddc->dbg_flag) {
1728     PetscCall(PetscViewerASCIISubtractTab(pcbddc->dbg_viewer, 2 * pcbddc->current_level));
1729     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
1730   }
1731   PetscFunctionReturn(PETSC_SUCCESS);
1732 }
1733 
1734 // PetscClangLinter pragma disable: -fdoc-sowing-chars
1735 /*
1736    PCApply_BDDC - Applies the BDDC operator to a vector.
1737 
1738    Input Parameters:
1739 +  pc - the preconditioner context
1740 -  r - input vector (global)
1741 
1742    Output Parameter:
1743 .  z - output vector (global)
1744 
1745    Application Interface Routine: PCApply()
1746  */
1747 static PetscErrorCode PCApply_BDDC(PC pc, Vec r, Vec z)
1748 {
1749   PC_IS            *pcis   = (PC_IS *)(pc->data);
1750   PC_BDDC          *pcbddc = (PC_BDDC *)(pc->data);
1751   Mat               lA     = NULL;
1752   PetscInt          n_B = pcis->n_B, n_D = pcis->n - n_B;
1753   const PetscScalar one   = 1.0;
1754   const PetscScalar m_one = -1.0;
1755   const PetscScalar zero  = 0.0;
1756   /* This code is similar to that provided in nn.c for PCNN
1757    NN interface preconditioner changed to BDDC
1758    Added support for M_3 preconditioner in the reference article (code is active if pcbddc->switch_static == PETSC_TRUE) */
1759 
1760   PetscFunctionBegin;
1761   PetscCall(PetscCitationsRegister(citation, &cited));
1762   if (pcbddc->switch_static) PetscCall(MatISGetLocalMat(pc->useAmat ? pc->mat : pc->pmat, &lA));
1763 
1764   if (pcbddc->ChangeOfBasisMatrix) {
1765     Vec swap;
1766 
1767     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
1768     swap                = pcbddc->work_change;
1769     pcbddc->work_change = r;
1770     r                   = swap;
1771     /* save rhs so that we don't need to apply the change of basis for the exact dirichlet trick in PreSolve */
1772     if (pcbddc->benign_apply_coarse_only && pcbddc->use_exact_dirichlet_trick && pcbddc->change_interior) {
1773       PetscCall(VecCopy(r, pcis->vec1_global));
1774       PetscCall(VecLockReadPush(pcis->vec1_global));
1775     }
1776   }
1777   if (pcbddc->benign_have_null) { /* get p0 from r */
1778     PetscCall(PCBDDCBenignGetOrSetP0(pc, r, PETSC_TRUE));
1779   }
1780   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_DIRICHLET && !pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
1781     PetscCall(VecCopy(r, z));
1782     /* First Dirichlet solve */
1783     PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1784     PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1785     /*
1786       Assembling right hand side for BDDC operator
1787       - pcis->vec1_D for the Dirichlet part (if needed, i.e. pcbddc->switch_static == PETSC_TRUE)
1788       - pcis->vec1_B the interface part of the global vector z
1789     */
1790     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1791     if (n_D) {
1792       PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
1793       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1794       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
1795       PetscCall(VecScale(pcis->vec2_D, m_one));
1796       if (pcbddc->switch_static) {
1797         PetscCall(VecSet(pcis->vec1_N, 0.));
1798         PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1799         PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1800         if (!pcbddc->switch_static_change) {
1801           PetscCall(MatMult(lA, pcis->vec1_N, pcis->vec2_N));
1802         } else {
1803           PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1804           PetscCall(MatMult(lA, pcis->vec2_N, pcis->vec1_N));
1805           PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1806         }
1807         PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_N, pcis->vec1_D, ADD_VALUES, SCATTER_FORWARD));
1808         PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_N, pcis->vec1_D, ADD_VALUES, SCATTER_FORWARD));
1809         PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec2_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1810         PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec2_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1811       } else {
1812         PetscCall(MatMult(pcis->A_BI, pcis->vec2_D, pcis->vec1_B));
1813       }
1814     } else {
1815       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1816       PetscCall(VecSet(pcis->vec1_B, zero));
1817     }
1818     PetscCall(VecScatterBegin(pcis->global_to_B, pcis->vec1_B, z, ADD_VALUES, SCATTER_REVERSE));
1819     PetscCall(VecScatterEnd(pcis->global_to_B, pcis->vec1_B, z, ADD_VALUES, SCATTER_REVERSE));
1820     PetscCall(PCBDDCScalingRestriction(pc, z, pcis->vec1_B));
1821   } else {
1822     if (!pcbddc->benign_apply_coarse_only) PetscCall(PCBDDCScalingRestriction(pc, r, pcis->vec1_B));
1823   }
1824   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_LUMP) {
1825     PetscCheck(pcbddc->switch_static, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "You forgot to pass -pc_bddc_switch_static");
1826     PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1827     PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1828   }
1829 
1830   /* Apply interface preconditioner
1831      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1832   PetscCall(PCBDDCApplyInterfacePreconditioner(pc, PETSC_FALSE));
1833 
1834   /* Apply transpose of partition of unity operator */
1835   PetscCall(PCBDDCScalingExtension(pc, pcis->vec1_B, z));
1836   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_LUMP) {
1837     PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec1_D, z, INSERT_VALUES, SCATTER_REVERSE));
1838     PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec1_D, z, INSERT_VALUES, SCATTER_REVERSE));
1839     PetscFunctionReturn(PETSC_SUCCESS);
1840   }
1841   /* Second Dirichlet solve and assembling of output */
1842   PetscCall(VecScatterBegin(pcis->global_to_B, z, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1843   PetscCall(VecScatterEnd(pcis->global_to_B, z, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1844   if (n_B) {
1845     if (pcbddc->switch_static) {
1846       PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec1_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1847       PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec1_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1848       PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1849       PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1850       if (!pcbddc->switch_static_change) {
1851         PetscCall(MatMult(lA, pcis->vec1_N, pcis->vec2_N));
1852       } else {
1853         PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1854         PetscCall(MatMult(lA, pcis->vec2_N, pcis->vec1_N));
1855         PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1856       }
1857       PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_N, pcis->vec3_D, INSERT_VALUES, SCATTER_FORWARD));
1858       PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_N, pcis->vec3_D, INSERT_VALUES, SCATTER_FORWARD));
1859     } else {
1860       PetscCall(MatMult(pcis->A_IB, pcis->vec1_B, pcis->vec3_D));
1861     }
1862   } else if (pcbddc->switch_static) { /* n_B is zero */
1863     if (!pcbddc->switch_static_change) {
1864       PetscCall(MatMult(lA, pcis->vec1_D, pcis->vec3_D));
1865     } else {
1866       PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_D, pcis->vec1_N));
1867       PetscCall(MatMult(lA, pcis->vec1_N, pcis->vec2_N));
1868       PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec2_N, pcis->vec3_D));
1869     }
1870   }
1871   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1872   PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec3_D, pcis->vec4_D));
1873   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1874   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec4_D));
1875 
1876   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
1877     if (pcbddc->switch_static) {
1878       PetscCall(VecAXPBYPCZ(pcis->vec2_D, m_one, one, m_one, pcis->vec4_D, pcis->vec1_D));
1879     } else {
1880       PetscCall(VecAXPBY(pcis->vec2_D, m_one, m_one, pcis->vec4_D));
1881     }
1882     PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
1883     PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
1884   } else {
1885     if (pcbddc->switch_static) {
1886       PetscCall(VecAXPBY(pcis->vec4_D, one, m_one, pcis->vec1_D));
1887     } else {
1888       PetscCall(VecScale(pcis->vec4_D, m_one));
1889     }
1890     PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec4_D, z, INSERT_VALUES, SCATTER_REVERSE));
1891     PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec4_D, z, INSERT_VALUES, SCATTER_REVERSE));
1892   }
1893   if (pcbddc->benign_have_null) { /* set p0 (computed in PCBDDCApplyInterface) */
1894     if (pcbddc->benign_apply_coarse_only) PetscCall(PetscArrayzero(pcbddc->benign_p0, pcbddc->benign_n));
1895     PetscCall(PCBDDCBenignGetOrSetP0(pc, z, PETSC_FALSE));
1896   }
1897 
1898   if (pcbddc->ChangeOfBasisMatrix) {
1899     pcbddc->work_change = r;
1900     PetscCall(VecCopy(z, pcbddc->work_change));
1901     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
1902   }
1903   PetscFunctionReturn(PETSC_SUCCESS);
1904 }
1905 
1906 /*
1907    PCApplyTranspose_BDDC - Applies the transpose of the BDDC operator to a vector.
1908 
1909    Input Parameters:
1910 +  pc - the preconditioner context
1911 -  r - input vector (global)
1912 
1913    Output Parameter:
1914 .  z - output vector (global)
1915 
1916    Application Interface Routine: PCApplyTranspose()
1917  */
1918 static PetscErrorCode PCApplyTranspose_BDDC(PC pc, Vec r, Vec z)
1919 {
1920   PC_IS            *pcis   = (PC_IS *)(pc->data);
1921   PC_BDDC          *pcbddc = (PC_BDDC *)(pc->data);
1922   Mat               lA     = NULL;
1923   PetscInt          n_B = pcis->n_B, n_D = pcis->n - n_B;
1924   const PetscScalar one   = 1.0;
1925   const PetscScalar m_one = -1.0;
1926   const PetscScalar zero  = 0.0;
1927 
1928   PetscFunctionBegin;
1929   PetscCall(PetscCitationsRegister(citation, &cited));
1930   if (pcbddc->switch_static) PetscCall(MatISGetLocalMat(pc->useAmat ? pc->mat : pc->pmat, &lA));
1931   if (pcbddc->ChangeOfBasisMatrix) {
1932     Vec swap;
1933 
1934     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, r, pcbddc->work_change));
1935     swap                = pcbddc->work_change;
1936     pcbddc->work_change = r;
1937     r                   = swap;
1938     /* save rhs so that we don't need to apply the change of basis for the exact dirichlet trick in PreSolve */
1939     if (pcbddc->benign_apply_coarse_only && pcbddc->exact_dirichlet_trick_app && pcbddc->change_interior) {
1940       PetscCall(VecCopy(r, pcis->vec1_global));
1941       PetscCall(VecLockReadPush(pcis->vec1_global));
1942     }
1943   }
1944   if (pcbddc->benign_have_null) { /* get p0 from r */
1945     PetscCall(PCBDDCBenignGetOrSetP0(pc, r, PETSC_TRUE));
1946   }
1947   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
1948     PetscCall(VecCopy(r, z));
1949     /* First Dirichlet solve */
1950     PetscCall(VecScatterBegin(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1951     PetscCall(VecScatterEnd(pcis->global_to_D, r, pcis->vec1_D, INSERT_VALUES, SCATTER_FORWARD));
1952     /*
1953       Assembling right hand side for BDDC operator
1954       - pcis->vec1_D for the Dirichlet part (if needed, i.e. pcbddc->switch_static == PETSC_TRUE)
1955       - pcis->vec1_B the interface part of the global vector z
1956     */
1957     if (n_D) {
1958       PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1959       PetscCall(KSPSolveTranspose(pcbddc->ksp_D, pcis->vec1_D, pcis->vec2_D));
1960       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
1961       PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec2_D));
1962       PetscCall(VecScale(pcis->vec2_D, m_one));
1963       if (pcbddc->switch_static) {
1964         PetscCall(VecSet(pcis->vec1_N, 0.));
1965         PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1966         PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
1967         if (!pcbddc->switch_static_change) {
1968           PetscCall(MatMultTranspose(lA, pcis->vec1_N, pcis->vec2_N));
1969         } else {
1970           PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1971           PetscCall(MatMultTranspose(lA, pcis->vec2_N, pcis->vec1_N));
1972           PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
1973         }
1974         PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_N, pcis->vec1_D, ADD_VALUES, SCATTER_FORWARD));
1975         PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_N, pcis->vec1_D, ADD_VALUES, SCATTER_FORWARD));
1976         PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec2_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1977         PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec2_N, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
1978       } else {
1979         PetscCall(MatMultTranspose(pcis->A_IB, pcis->vec2_D, pcis->vec1_B));
1980       }
1981     } else {
1982       PetscCall(VecSet(pcis->vec1_B, zero));
1983     }
1984     PetscCall(VecScatterBegin(pcis->global_to_B, pcis->vec1_B, z, ADD_VALUES, SCATTER_REVERSE));
1985     PetscCall(VecScatterEnd(pcis->global_to_B, pcis->vec1_B, z, ADD_VALUES, SCATTER_REVERSE));
1986     PetscCall(PCBDDCScalingRestriction(pc, z, pcis->vec1_B));
1987   } else {
1988     PetscCall(PCBDDCScalingRestriction(pc, r, pcis->vec1_B));
1989   }
1990 
1991   /* Apply interface preconditioner
1992      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1993   PetscCall(PCBDDCApplyInterfacePreconditioner(pc, PETSC_TRUE));
1994 
1995   /* Apply transpose of partition of unity operator */
1996   PetscCall(PCBDDCScalingExtension(pc, pcis->vec1_B, z));
1997 
1998   /* Second Dirichlet solve and assembling of output */
1999   PetscCall(VecScatterBegin(pcis->global_to_B, z, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
2000   PetscCall(VecScatterEnd(pcis->global_to_B, z, pcis->vec1_B, INSERT_VALUES, SCATTER_FORWARD));
2001   if (n_B) {
2002     if (pcbddc->switch_static) {
2003       PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec1_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
2004       PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec1_D, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
2005       PetscCall(VecScatterBegin(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
2006       PetscCall(VecScatterEnd(pcis->N_to_B, pcis->vec1_B, pcis->vec1_N, INSERT_VALUES, SCATTER_REVERSE));
2007       if (!pcbddc->switch_static_change) {
2008         PetscCall(MatMultTranspose(lA, pcis->vec1_N, pcis->vec2_N));
2009       } else {
2010         PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
2011         PetscCall(MatMultTranspose(lA, pcis->vec2_N, pcis->vec1_N));
2012         PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec1_N, pcis->vec2_N));
2013       }
2014       PetscCall(VecScatterBegin(pcis->N_to_D, pcis->vec2_N, pcis->vec3_D, INSERT_VALUES, SCATTER_FORWARD));
2015       PetscCall(VecScatterEnd(pcis->N_to_D, pcis->vec2_N, pcis->vec3_D, INSERT_VALUES, SCATTER_FORWARD));
2016     } else {
2017       PetscCall(MatMultTranspose(pcis->A_BI, pcis->vec1_B, pcis->vec3_D));
2018     }
2019   } else if (pcbddc->switch_static) { /* n_B is zero */
2020     if (!pcbddc->switch_static_change) {
2021       PetscCall(MatMultTranspose(lA, pcis->vec1_D, pcis->vec3_D));
2022     } else {
2023       PetscCall(MatMult(pcbddc->switch_static_change, pcis->vec1_D, pcis->vec1_N));
2024       PetscCall(MatMultTranspose(lA, pcis->vec1_N, pcis->vec2_N));
2025       PetscCall(MatMultTranspose(pcbddc->switch_static_change, pcis->vec2_N, pcis->vec3_D));
2026     }
2027   }
2028   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
2029   PetscCall(KSPSolveTranspose(pcbddc->ksp_D, pcis->vec3_D, pcis->vec4_D));
2030   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], pc, 0, 0, 0));
2031   PetscCall(KSPCheckSolve(pcbddc->ksp_D, pc, pcis->vec4_D));
2032   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
2033     if (pcbddc->switch_static) {
2034       PetscCall(VecAXPBYPCZ(pcis->vec2_D, m_one, one, m_one, pcis->vec4_D, pcis->vec1_D));
2035     } else {
2036       PetscCall(VecAXPBY(pcis->vec2_D, m_one, m_one, pcis->vec4_D));
2037     }
2038     PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
2039     PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec2_D, z, INSERT_VALUES, SCATTER_REVERSE));
2040   } else {
2041     if (pcbddc->switch_static) {
2042       PetscCall(VecAXPBY(pcis->vec4_D, one, m_one, pcis->vec1_D));
2043     } else {
2044       PetscCall(VecScale(pcis->vec4_D, m_one));
2045     }
2046     PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec4_D, z, INSERT_VALUES, SCATTER_REVERSE));
2047     PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec4_D, z, INSERT_VALUES, SCATTER_REVERSE));
2048   }
2049   if (pcbddc->benign_have_null) { /* set p0 (computed in PCBDDCApplyInterface) */
2050     PetscCall(PCBDDCBenignGetOrSetP0(pc, z, PETSC_FALSE));
2051   }
2052   if (pcbddc->ChangeOfBasisMatrix) {
2053     pcbddc->work_change = r;
2054     PetscCall(VecCopy(z, pcbddc->work_change));
2055     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, pcbddc->work_change, z));
2056   }
2057   PetscFunctionReturn(PETSC_SUCCESS);
2058 }
2059 
2060 static PetscErrorCode PCReset_BDDC(PC pc)
2061 {
2062   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2063   PC_IS   *pcis   = (PC_IS *)pc->data;
2064   KSP      kspD, kspR, kspC;
2065 
2066   PetscFunctionBegin;
2067   /* free BDDC custom data  */
2068   PetscCall(PCBDDCResetCustomization(pc));
2069   /* destroy objects related to topography */
2070   PetscCall(PCBDDCResetTopography(pc));
2071   /* destroy objects for scaling operator */
2072   PetscCall(PCBDDCScalingDestroy(pc));
2073   /* free solvers stuff */
2074   PetscCall(PCBDDCResetSolvers(pc));
2075   /* free global vectors needed in presolve */
2076   PetscCall(VecDestroy(&pcbddc->temp_solution));
2077   PetscCall(VecDestroy(&pcbddc->original_rhs));
2078   /* free data created by PCIS */
2079   PetscCall(PCISReset(pc));
2080 
2081   /* restore defaults */
2082   kspD = pcbddc->ksp_D;
2083   kspR = pcbddc->ksp_R;
2084   kspC = pcbddc->coarse_ksp;
2085   PetscCall(PetscMemzero(pc->data, sizeof(*pcbddc)));
2086   pcis->n_neigh                     = -1;
2087   pcis->scaling_factor              = 1.0;
2088   pcis->reusesubmatrices            = PETSC_TRUE;
2089   pcbddc->use_local_adj             = PETSC_TRUE;
2090   pcbddc->use_vertices              = PETSC_TRUE;
2091   pcbddc->use_edges                 = PETSC_TRUE;
2092   pcbddc->symmetric_primal          = PETSC_TRUE;
2093   pcbddc->vertex_size               = 1;
2094   pcbddc->recompute_topography      = PETSC_TRUE;
2095   pcbddc->coarse_size               = -1;
2096   pcbddc->use_exact_dirichlet_trick = PETSC_TRUE;
2097   pcbddc->coarsening_ratio          = 8;
2098   pcbddc->coarse_eqs_per_proc       = 1;
2099   pcbddc->benign_compute_correction = PETSC_TRUE;
2100   pcbddc->nedfield                  = -1;
2101   pcbddc->nedglobal                 = PETSC_TRUE;
2102   pcbddc->graphmaxcount             = PETSC_MAX_INT;
2103   pcbddc->sub_schurs_layers         = -1;
2104   pcbddc->ksp_D                     = kspD;
2105   pcbddc->ksp_R                     = kspR;
2106   pcbddc->coarse_ksp                = kspC;
2107   PetscFunctionReturn(PETSC_SUCCESS);
2108 }
2109 
2110 static PetscErrorCode PCDestroy_BDDC(PC pc)
2111 {
2112   PC_BDDC *pcbddc = (PC_BDDC *)pc->data;
2113 
2114   PetscFunctionBegin;
2115   PetscCall(PCReset_BDDC(pc));
2116   PetscCall(KSPDestroy(&pcbddc->ksp_D));
2117   PetscCall(KSPDestroy(&pcbddc->ksp_R));
2118   PetscCall(KSPDestroy(&pcbddc->coarse_ksp));
2119   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDiscreteGradient_C", NULL));
2120   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDivergenceMat_C", NULL));
2121   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetChangeOfBasisMat_C", NULL));
2122   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetPrimalVerticesLocalIS_C", NULL));
2123   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetPrimalVerticesIS_C", NULL));
2124   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetPrimalVerticesLocalIS_C", NULL));
2125   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetPrimalVerticesIS_C", NULL));
2126   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetCoarseningRatio_C", NULL));
2127   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLevel_C", NULL));
2128   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetUseExactDirichlet_C", NULL));
2129   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLevels_C", NULL));
2130   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDirichletBoundaries_C", NULL));
2131   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDirichletBoundariesLocal_C", NULL));
2132   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetNeumannBoundaries_C", NULL));
2133   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetNeumannBoundariesLocal_C", NULL));
2134   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetDirichletBoundaries_C", NULL));
2135   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetDirichletBoundariesLocal_C", NULL));
2136   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetNeumannBoundaries_C", NULL));
2137   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetNeumannBoundariesLocal_C", NULL));
2138   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDofsSplitting_C", NULL));
2139   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDofsSplittingLocal_C", NULL));
2140   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLocalAdjacencyGraph_C", NULL));
2141   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCCreateFETIDPOperators_C", NULL));
2142   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCMatFETIDPGetRHS_C", NULL));
2143   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCMatFETIDPGetSolution_C", NULL));
2144   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL));
2145   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
2146   PetscCall(PetscFree(pc->data));
2147   PetscFunctionReturn(PETSC_SUCCESS);
2148 }
2149 
2150 static PetscErrorCode PCSetCoordinates_BDDC(PC pc, PetscInt dim, PetscInt nloc, PetscReal *coords)
2151 {
2152   PC_BDDC    *pcbddc    = (PC_BDDC *)pc->data;
2153   PCBDDCGraph mat_graph = pcbddc->mat_graph;
2154 
2155   PetscFunctionBegin;
2156   PetscCall(PetscFree(mat_graph->coords));
2157   PetscCall(PetscMalloc1(nloc * dim, &mat_graph->coords));
2158   PetscCall(PetscArraycpy(mat_graph->coords, coords, nloc * dim));
2159   mat_graph->cnloc = nloc;
2160   mat_graph->cdim  = dim;
2161   mat_graph->cloc  = PETSC_FALSE;
2162   /* flg setup */
2163   pcbddc->recompute_topography = PETSC_TRUE;
2164   pcbddc->corner_selected      = PETSC_FALSE;
2165   PetscFunctionReturn(PETSC_SUCCESS);
2166 }
2167 
2168 static PetscErrorCode PCPreSolveChangeRHS_BDDC(PC pc, PetscBool *change)
2169 {
2170   PetscFunctionBegin;
2171   *change = PETSC_TRUE;
2172   PetscFunctionReturn(PETSC_SUCCESS);
2173 }
2174 
2175 static PetscErrorCode PCBDDCMatFETIDPGetRHS_BDDC(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
2176 {
2177   FETIDPMat_ctx mat_ctx;
2178   Vec           work;
2179   PC_IS        *pcis;
2180   PC_BDDC      *pcbddc;
2181 
2182   PetscFunctionBegin;
2183   PetscCall(MatShellGetContext(fetidp_mat, &mat_ctx));
2184   pcis   = (PC_IS *)mat_ctx->pc->data;
2185   pcbddc = (PC_BDDC *)mat_ctx->pc->data;
2186 
2187   PetscCall(VecSet(fetidp_flux_rhs, 0.0));
2188   /* copy rhs since we may change it during PCPreSolve_BDDC */
2189   if (!pcbddc->original_rhs) PetscCall(VecDuplicate(pcis->vec1_global, &pcbddc->original_rhs));
2190   if (mat_ctx->rhs_flip) {
2191     PetscCall(VecPointwiseMult(pcbddc->original_rhs, standard_rhs, mat_ctx->rhs_flip));
2192   } else {
2193     PetscCall(VecCopy(standard_rhs, pcbddc->original_rhs));
2194   }
2195   if (mat_ctx->g2g_p) {
2196     /* interface pressure rhs */
2197     PetscCall(VecScatterBegin(mat_ctx->g2g_p, fetidp_flux_rhs, pcbddc->original_rhs, INSERT_VALUES, SCATTER_REVERSE));
2198     PetscCall(VecScatterEnd(mat_ctx->g2g_p, fetidp_flux_rhs, pcbddc->original_rhs, INSERT_VALUES, SCATTER_REVERSE));
2199     PetscCall(VecScatterBegin(mat_ctx->g2g_p, standard_rhs, fetidp_flux_rhs, INSERT_VALUES, SCATTER_FORWARD));
2200     PetscCall(VecScatterEnd(mat_ctx->g2g_p, standard_rhs, fetidp_flux_rhs, INSERT_VALUES, SCATTER_FORWARD));
2201     if (!mat_ctx->rhs_flip) PetscCall(VecScale(fetidp_flux_rhs, -1.));
2202   }
2203   /*
2204      change of basis for physical rhs if needed
2205      It also changes the rhs in case of dirichlet boundaries
2206   */
2207   PetscCall(PCPreSolve_BDDC(mat_ctx->pc, NULL, pcbddc->original_rhs, NULL));
2208   if (pcbddc->ChangeOfBasisMatrix) {
2209     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix, pcbddc->original_rhs, pcbddc->work_change));
2210     work = pcbddc->work_change;
2211   } else {
2212     work = pcbddc->original_rhs;
2213   }
2214   /* store vectors for computation of fetidp final solution */
2215   PetscCall(VecScatterBegin(pcis->global_to_D, work, mat_ctx->temp_solution_D, INSERT_VALUES, SCATTER_FORWARD));
2216   PetscCall(VecScatterEnd(pcis->global_to_D, work, mat_ctx->temp_solution_D, INSERT_VALUES, SCATTER_FORWARD));
2217   /* scale rhs since it should be unassembled */
2218   /* TODO use counter scaling? (also below) */
2219   PetscCall(VecScatterBegin(pcis->global_to_B, work, mat_ctx->temp_solution_B, INSERT_VALUES, SCATTER_FORWARD));
2220   PetscCall(VecScatterEnd(pcis->global_to_B, work, mat_ctx->temp_solution_B, INSERT_VALUES, SCATTER_FORWARD));
2221   /* Apply partition of unity */
2222   PetscCall(VecPointwiseMult(mat_ctx->temp_solution_B, pcis->D, mat_ctx->temp_solution_B));
2223   /* PetscCall(PCBDDCScalingRestriction(mat_ctx->pc,work,mat_ctx->temp_solution_B)); */
2224   if (!pcbddc->switch_static) {
2225     /* compute partially subassembled Schur complement right-hand side */
2226     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], mat_ctx->pc, 0, 0, 0));
2227     PetscCall(KSPSolve(pcbddc->ksp_D, mat_ctx->temp_solution_D, pcis->vec1_D));
2228     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], mat_ctx->pc, 0, 0, 0));
2229     /* Cannot propagate up error in KSPSolve() because there is no access to the PC */
2230     PetscCall(MatMult(pcis->A_BI, pcis->vec1_D, pcis->vec1_B));
2231     PetscCall(VecAXPY(mat_ctx->temp_solution_B, -1.0, pcis->vec1_B));
2232     PetscCall(VecSet(work, 0.0));
2233     PetscCall(VecScatterBegin(pcis->global_to_B, mat_ctx->temp_solution_B, work, ADD_VALUES, SCATTER_REVERSE));
2234     PetscCall(VecScatterEnd(pcis->global_to_B, mat_ctx->temp_solution_B, work, ADD_VALUES, SCATTER_REVERSE));
2235     /* PetscCall(PCBDDCScalingRestriction(mat_ctx->pc,work,mat_ctx->temp_solution_B)); */
2236     PetscCall(VecScatterBegin(pcis->global_to_B, work, mat_ctx->temp_solution_B, INSERT_VALUES, SCATTER_FORWARD));
2237     PetscCall(VecScatterEnd(pcis->global_to_B, work, mat_ctx->temp_solution_B, INSERT_VALUES, SCATTER_FORWARD));
2238     PetscCall(VecPointwiseMult(mat_ctx->temp_solution_B, pcis->D, mat_ctx->temp_solution_B));
2239   }
2240   /* BDDC rhs */
2241   PetscCall(VecCopy(mat_ctx->temp_solution_B, pcis->vec1_B));
2242   if (pcbddc->switch_static) PetscCall(VecCopy(mat_ctx->temp_solution_D, pcis->vec1_D));
2243   /* apply BDDC */
2244   PetscCall(PetscArrayzero(pcbddc->benign_p0, pcbddc->benign_n));
2245   PetscCall(PCBDDCApplyInterfacePreconditioner(mat_ctx->pc, PETSC_FALSE));
2246   PetscCall(PetscArrayzero(pcbddc->benign_p0, pcbddc->benign_n));
2247 
2248   /* Application of B_delta and assembling of rhs for fetidp fluxes */
2249   PetscCall(MatMult(mat_ctx->B_delta, pcis->vec1_B, mat_ctx->lambda_local));
2250   PetscCall(VecScatterBegin(mat_ctx->l2g_lambda, mat_ctx->lambda_local, fetidp_flux_rhs, ADD_VALUES, SCATTER_FORWARD));
2251   PetscCall(VecScatterEnd(mat_ctx->l2g_lambda, mat_ctx->lambda_local, fetidp_flux_rhs, ADD_VALUES, SCATTER_FORWARD));
2252   /* Add contribution to interface pressures */
2253   if (mat_ctx->l2g_p) {
2254     PetscCall(MatMult(mat_ctx->B_BB, pcis->vec1_B, mat_ctx->vP));
2255     if (pcbddc->switch_static) PetscCall(MatMultAdd(mat_ctx->B_BI, pcis->vec1_D, mat_ctx->vP, mat_ctx->vP));
2256     PetscCall(VecScatterBegin(mat_ctx->l2g_p, mat_ctx->vP, fetidp_flux_rhs, ADD_VALUES, SCATTER_FORWARD));
2257     PetscCall(VecScatterEnd(mat_ctx->l2g_p, mat_ctx->vP, fetidp_flux_rhs, ADD_VALUES, SCATTER_FORWARD));
2258   }
2259   PetscFunctionReturn(PETSC_SUCCESS);
2260 }
2261 
2262 /*@
2263   PCBDDCMatFETIDPGetRHS - Compute the right-hand side for a FETI-DP linear system using the physical right-hand side
2264 
2265   Collective
2266 
2267   Input Parameters:
2268 + fetidp_mat   - the FETI-DP matrix object obtained by a call to `PCBDDCCreateFETIDPOperators()`
2269 - standard_rhs - the right-hand side of the original linear system
2270 
2271   Output Parameter:
2272 . fetidp_flux_rhs - the right-hand side for the FETI-DP linear system
2273 
2274   Level: developer
2275 
2276 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCCreateFETIDPOperators()`, `PCBDDCMatFETIDPGetSolution()`
2277 @*/
2278 PetscErrorCode PCBDDCMatFETIDPGetRHS(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
2279 {
2280   FETIDPMat_ctx mat_ctx;
2281 
2282   PetscFunctionBegin;
2283   PetscValidHeaderSpecific(fetidp_mat, MAT_CLASSID, 1);
2284   PetscValidHeaderSpecific(standard_rhs, VEC_CLASSID, 2);
2285   PetscValidHeaderSpecific(fetidp_flux_rhs, VEC_CLASSID, 3);
2286   PetscCall(MatShellGetContext(fetidp_mat, &mat_ctx));
2287   PetscUseMethod(mat_ctx->pc, "PCBDDCMatFETIDPGetRHS_C", (Mat, Vec, Vec), (fetidp_mat, standard_rhs, fetidp_flux_rhs));
2288   PetscFunctionReturn(PETSC_SUCCESS);
2289 }
2290 
2291 static PetscErrorCode PCBDDCMatFETIDPGetSolution_BDDC(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
2292 {
2293   FETIDPMat_ctx mat_ctx;
2294   PC_IS        *pcis;
2295   PC_BDDC      *pcbddc;
2296   Vec           work;
2297 
2298   PetscFunctionBegin;
2299   PetscCall(MatShellGetContext(fetidp_mat, &mat_ctx));
2300   pcis   = (PC_IS *)mat_ctx->pc->data;
2301   pcbddc = (PC_BDDC *)mat_ctx->pc->data;
2302 
2303   /* apply B_delta^T */
2304   PetscCall(VecSet(pcis->vec1_B, 0.));
2305   PetscCall(VecScatterBegin(mat_ctx->l2g_lambda, fetidp_flux_sol, mat_ctx->lambda_local, INSERT_VALUES, SCATTER_REVERSE));
2306   PetscCall(VecScatterEnd(mat_ctx->l2g_lambda, fetidp_flux_sol, mat_ctx->lambda_local, INSERT_VALUES, SCATTER_REVERSE));
2307   PetscCall(MatMultTranspose(mat_ctx->B_delta, mat_ctx->lambda_local, pcis->vec1_B));
2308   if (mat_ctx->l2g_p) {
2309     PetscCall(VecScatterBegin(mat_ctx->l2g_p, fetidp_flux_sol, mat_ctx->vP, INSERT_VALUES, SCATTER_REVERSE));
2310     PetscCall(VecScatterEnd(mat_ctx->l2g_p, fetidp_flux_sol, mat_ctx->vP, INSERT_VALUES, SCATTER_REVERSE));
2311     PetscCall(MatMultAdd(mat_ctx->Bt_BB, mat_ctx->vP, pcis->vec1_B, pcis->vec1_B));
2312   }
2313 
2314   /* compute rhs for BDDC application */
2315   PetscCall(VecAYPX(pcis->vec1_B, -1.0, mat_ctx->temp_solution_B));
2316   if (pcbddc->switch_static) {
2317     PetscCall(VecCopy(mat_ctx->temp_solution_D, pcis->vec1_D));
2318     if (mat_ctx->l2g_p) {
2319       PetscCall(VecScale(mat_ctx->vP, -1.));
2320       PetscCall(MatMultAdd(mat_ctx->Bt_BI, mat_ctx->vP, pcis->vec1_D, pcis->vec1_D));
2321     }
2322   }
2323 
2324   /* apply BDDC */
2325   PetscCall(PetscArrayzero(pcbddc->benign_p0, pcbddc->benign_n));
2326   PetscCall(PCBDDCApplyInterfacePreconditioner(mat_ctx->pc, PETSC_FALSE));
2327 
2328   /* put values into global vector */
2329   if (pcbddc->ChangeOfBasisMatrix) work = pcbddc->work_change;
2330   else work = standard_sol;
2331   PetscCall(VecScatterBegin(pcis->global_to_B, pcis->vec1_B, work, INSERT_VALUES, SCATTER_REVERSE));
2332   PetscCall(VecScatterEnd(pcis->global_to_B, pcis->vec1_B, work, INSERT_VALUES, SCATTER_REVERSE));
2333   if (!pcbddc->switch_static) {
2334     /* compute values into the interior if solved for the partially subassembled Schur complement */
2335     PetscCall(MatMult(pcis->A_IB, pcis->vec1_B, pcis->vec1_D));
2336     PetscCall(VecAYPX(pcis->vec1_D, -1.0, mat_ctx->temp_solution_D));
2337     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0], mat_ctx->pc, 0, 0, 0));
2338     PetscCall(KSPSolve(pcbddc->ksp_D, pcis->vec1_D, pcis->vec1_D));
2339     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0], mat_ctx->pc, 0, 0, 0));
2340     /* Cannot propagate up error in KSPSolve() because there is no access to the PC */
2341   }
2342 
2343   PetscCall(VecScatterBegin(pcis->global_to_D, pcis->vec1_D, work, INSERT_VALUES, SCATTER_REVERSE));
2344   PetscCall(VecScatterEnd(pcis->global_to_D, pcis->vec1_D, work, INSERT_VALUES, SCATTER_REVERSE));
2345   /* add p0 solution to final solution */
2346   PetscCall(PCBDDCBenignGetOrSetP0(mat_ctx->pc, work, PETSC_FALSE));
2347   if (pcbddc->ChangeOfBasisMatrix) PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix, work, standard_sol));
2348   PetscCall(PCPostSolve_BDDC(mat_ctx->pc, NULL, NULL, standard_sol));
2349   if (mat_ctx->g2g_p) {
2350     PetscCall(VecScatterBegin(mat_ctx->g2g_p, fetidp_flux_sol, standard_sol, INSERT_VALUES, SCATTER_REVERSE));
2351     PetscCall(VecScatterEnd(mat_ctx->g2g_p, fetidp_flux_sol, standard_sol, INSERT_VALUES, SCATTER_REVERSE));
2352   }
2353   PetscFunctionReturn(PETSC_SUCCESS);
2354 }
2355 
2356 static PetscErrorCode PCView_BDDCIPC(PC pc, PetscViewer viewer)
2357 {
2358   BDDCIPC_ctx bddcipc_ctx;
2359   PetscBool   isascii;
2360 
2361   PetscFunctionBegin;
2362   PetscCall(PCShellGetContext(pc, &bddcipc_ctx));
2363   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2364   if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer, "BDDC interface preconditioner\n"));
2365   PetscCall(PetscViewerASCIIPushTab(viewer));
2366   PetscCall(PCView(bddcipc_ctx->bddc, viewer));
2367   PetscCall(PetscViewerASCIIPopTab(viewer));
2368   PetscFunctionReturn(PETSC_SUCCESS);
2369 }
2370 
2371 static PetscErrorCode PCSetUp_BDDCIPC(PC pc)
2372 {
2373   BDDCIPC_ctx bddcipc_ctx;
2374   PetscBool   isbddc;
2375   Vec         vv;
2376   IS          is;
2377   PC_IS      *pcis;
2378 
2379   PetscFunctionBegin;
2380   PetscCall(PCShellGetContext(pc, &bddcipc_ctx));
2381   PetscCall(PetscObjectTypeCompare((PetscObject)bddcipc_ctx->bddc, PCBDDC, &isbddc));
2382   PetscCheck(isbddc, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Invalid type %s. Must be of type bddc", ((PetscObject)bddcipc_ctx->bddc)->type_name);
2383   PetscCall(PCSetUp(bddcipc_ctx->bddc));
2384 
2385   /* create interface scatter */
2386   pcis = (PC_IS *)(bddcipc_ctx->bddc->data);
2387   PetscCall(VecScatterDestroy(&bddcipc_ctx->g2l));
2388   PetscCall(MatCreateVecs(pc->pmat, &vv, NULL));
2389   PetscCall(ISRenumber(pcis->is_B_global, NULL, NULL, &is));
2390   PetscCall(VecScatterCreate(vv, is, pcis->vec1_B, NULL, &bddcipc_ctx->g2l));
2391   PetscCall(ISDestroy(&is));
2392   PetscCall(VecDestroy(&vv));
2393   PetscFunctionReturn(PETSC_SUCCESS);
2394 }
2395 
2396 static PetscErrorCode PCApply_BDDCIPC(PC pc, Vec r, Vec x)
2397 {
2398   BDDCIPC_ctx bddcipc_ctx;
2399   PC_IS      *pcis;
2400   VecScatter  tmps;
2401 
2402   PetscFunctionBegin;
2403   PetscCall(PCShellGetContext(pc, &bddcipc_ctx));
2404   pcis              = (PC_IS *)(bddcipc_ctx->bddc->data);
2405   tmps              = pcis->global_to_B;
2406   pcis->global_to_B = bddcipc_ctx->g2l;
2407   PetscCall(PCBDDCScalingRestriction(bddcipc_ctx->bddc, r, pcis->vec1_B));
2408   PetscCall(PCBDDCApplyInterfacePreconditioner(bddcipc_ctx->bddc, PETSC_FALSE));
2409   PetscCall(PCBDDCScalingExtension(bddcipc_ctx->bddc, pcis->vec1_B, x));
2410   pcis->global_to_B = tmps;
2411   PetscFunctionReturn(PETSC_SUCCESS);
2412 }
2413 
2414 static PetscErrorCode PCApplyTranspose_BDDCIPC(PC pc, Vec r, Vec x)
2415 {
2416   BDDCIPC_ctx bddcipc_ctx;
2417   PC_IS      *pcis;
2418   VecScatter  tmps;
2419 
2420   PetscFunctionBegin;
2421   PetscCall(PCShellGetContext(pc, &bddcipc_ctx));
2422   pcis              = (PC_IS *)(bddcipc_ctx->bddc->data);
2423   tmps              = pcis->global_to_B;
2424   pcis->global_to_B = bddcipc_ctx->g2l;
2425   PetscCall(PCBDDCScalingRestriction(bddcipc_ctx->bddc, r, pcis->vec1_B));
2426   PetscCall(PCBDDCApplyInterfacePreconditioner(bddcipc_ctx->bddc, PETSC_TRUE));
2427   PetscCall(PCBDDCScalingExtension(bddcipc_ctx->bddc, pcis->vec1_B, x));
2428   pcis->global_to_B = tmps;
2429   PetscFunctionReturn(PETSC_SUCCESS);
2430 }
2431 
2432 static PetscErrorCode PCDestroy_BDDCIPC(PC pc)
2433 {
2434   BDDCIPC_ctx bddcipc_ctx;
2435 
2436   PetscFunctionBegin;
2437   PetscCall(PCShellGetContext(pc, &bddcipc_ctx));
2438   PetscCall(PCDestroy(&bddcipc_ctx->bddc));
2439   PetscCall(VecScatterDestroy(&bddcipc_ctx->g2l));
2440   PetscCall(PetscFree(bddcipc_ctx));
2441   PetscFunctionReturn(PETSC_SUCCESS);
2442 }
2443 
2444 /*@
2445   PCBDDCMatFETIDPGetSolution - Compute the physical solution using the solution of the FETI-DP linear system
2446 
2447   Collective
2448 
2449   Input Parameters:
2450 + fetidp_mat      - the FETI-DP matrix obtained by a call to `PCBDDCCreateFETIDPOperators()`
2451 - fetidp_flux_sol - the solution of the FETI-DP linear system`
2452 
2453   Output Parameter:
2454 . standard_sol - the solution defined on the physical domain
2455 
2456   Level: developer
2457 
2458 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCCreateFETIDPOperators()`, `PCBDDCMatFETIDPGetRHS()`
2459 @*/
2460 PetscErrorCode PCBDDCMatFETIDPGetSolution(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
2461 {
2462   FETIDPMat_ctx mat_ctx;
2463 
2464   PetscFunctionBegin;
2465   PetscValidHeaderSpecific(fetidp_mat, MAT_CLASSID, 1);
2466   PetscValidHeaderSpecific(fetidp_flux_sol, VEC_CLASSID, 2);
2467   PetscValidHeaderSpecific(standard_sol, VEC_CLASSID, 3);
2468   PetscCall(MatShellGetContext(fetidp_mat, &mat_ctx));
2469   PetscUseMethod(mat_ctx->pc, "PCBDDCMatFETIDPGetSolution_C", (Mat, Vec, Vec), (fetidp_mat, fetidp_flux_sol, standard_sol));
2470   PetscFunctionReturn(PETSC_SUCCESS);
2471 }
2472 
2473 static PetscErrorCode PCBDDCCreateFETIDPOperators_BDDC(PC pc, PetscBool fully_redundant, const char *prefix, Mat *fetidp_mat, PC *fetidp_pc)
2474 {
2475   FETIDPMat_ctx fetidpmat_ctx;
2476   Mat           newmat;
2477   FETIDPPC_ctx  fetidppc_ctx;
2478   PC            newpc;
2479   MPI_Comm      comm;
2480 
2481   PetscFunctionBegin;
2482   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
2483   /* FETI-DP matrix */
2484   PetscCall(PCBDDCCreateFETIDPMatContext(pc, &fetidpmat_ctx));
2485   fetidpmat_ctx->fully_redundant = fully_redundant;
2486   PetscCall(PCBDDCSetupFETIDPMatContext(fetidpmat_ctx));
2487   PetscCall(MatCreateShell(comm, fetidpmat_ctx->n, fetidpmat_ctx->n, fetidpmat_ctx->N, fetidpmat_ctx->N, fetidpmat_ctx, &newmat));
2488   PetscCall(PetscObjectSetName((PetscObject)newmat, !fetidpmat_ctx->l2g_lambda_only ? "F" : "G"));
2489   PetscCall(MatShellSetOperation(newmat, MATOP_MULT, (void (*)(void))FETIDPMatMult));
2490   PetscCall(MatShellSetOperation(newmat, MATOP_MULT_TRANSPOSE, (void (*)(void))FETIDPMatMultTranspose));
2491   PetscCall(MatShellSetOperation(newmat, MATOP_DESTROY, (void (*)(void))PCBDDCDestroyFETIDPMat));
2492   /* propagate MatOptions */
2493   {
2494     PC_BDDC  *pcbddc = (PC_BDDC *)fetidpmat_ctx->pc->data;
2495     PetscBool isset, issym;
2496 
2497     PetscCall(MatIsSymmetricKnown(pc->mat, &isset, &issym));
2498     if ((isset && issym) || pcbddc->symmetric_primal) PetscCall(MatSetOption(newmat, MAT_SYMMETRIC, PETSC_TRUE));
2499   }
2500   PetscCall(MatSetOptionsPrefix(newmat, prefix));
2501   PetscCall(MatAppendOptionsPrefix(newmat, "fetidp_"));
2502   PetscCall(MatSetUp(newmat));
2503   /* FETI-DP preconditioner */
2504   PetscCall(PCBDDCCreateFETIDPPCContext(pc, &fetidppc_ctx));
2505   PetscCall(PCBDDCSetupFETIDPPCContext(newmat, fetidppc_ctx));
2506   PetscCall(PCCreate(comm, &newpc));
2507   PetscCall(PCSetOperators(newpc, newmat, newmat));
2508   PetscCall(PCSetOptionsPrefix(newpc, prefix));
2509   PetscCall(PCAppendOptionsPrefix(newpc, "fetidp_"));
2510   PetscCall(PCSetErrorIfFailure(newpc, pc->erroriffailure));
2511   if (!fetidpmat_ctx->l2g_lambda_only) { /* standard FETI-DP */
2512     PetscCall(PCSetType(newpc, PCSHELL));
2513     PetscCall(PCShellSetName(newpc, "FETI-DP multipliers"));
2514     PetscCall(PCShellSetContext(newpc, fetidppc_ctx));
2515     PetscCall(PCShellSetApply(newpc, FETIDPPCApply));
2516     PetscCall(PCShellSetApplyTranspose(newpc, FETIDPPCApplyTranspose));
2517     PetscCall(PCShellSetView(newpc, FETIDPPCView));
2518     PetscCall(PCShellSetDestroy(newpc, PCBDDCDestroyFETIDPPC));
2519   } else { /* saddle-point FETI-DP */
2520     Mat       M;
2521     PetscInt  psize;
2522     PetscBool fake = PETSC_FALSE, isfieldsplit;
2523 
2524     PetscCall(ISViewFromOptions(fetidpmat_ctx->lagrange, NULL, "-lag_view"));
2525     PetscCall(ISViewFromOptions(fetidpmat_ctx->pressure, NULL, "-press_view"));
2526     PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_PPmat", (PetscObject *)&M));
2527     PetscCall(PCSetType(newpc, PCFIELDSPLIT));
2528     PetscCall(PCFieldSplitSetIS(newpc, "lag", fetidpmat_ctx->lagrange));
2529     PetscCall(PCFieldSplitSetIS(newpc, "p", fetidpmat_ctx->pressure));
2530     PetscCall(PCFieldSplitSetType(newpc, PC_COMPOSITE_SCHUR));
2531     PetscCall(PCFieldSplitSetSchurFactType(newpc, PC_FIELDSPLIT_SCHUR_FACT_DIAG));
2532     PetscCall(ISGetSize(fetidpmat_ctx->pressure, &psize));
2533     if (psize != M->rmap->N) {
2534       Mat      M2;
2535       PetscInt lpsize;
2536 
2537       fake = PETSC_TRUE;
2538       PetscCall(ISGetLocalSize(fetidpmat_ctx->pressure, &lpsize));
2539       PetscCall(MatCreate(comm, &M2));
2540       PetscCall(MatSetType(M2, MATAIJ));
2541       PetscCall(MatSetSizes(M2, lpsize, lpsize, psize, psize));
2542       PetscCall(MatSetUp(M2));
2543       PetscCall(MatAssemblyBegin(M2, MAT_FINAL_ASSEMBLY));
2544       PetscCall(MatAssemblyEnd(M2, MAT_FINAL_ASSEMBLY));
2545       PetscCall(PCFieldSplitSetSchurPre(newpc, PC_FIELDSPLIT_SCHUR_PRE_USER, M2));
2546       PetscCall(MatDestroy(&M2));
2547     } else {
2548       PetscCall(PCFieldSplitSetSchurPre(newpc, PC_FIELDSPLIT_SCHUR_PRE_USER, M));
2549     }
2550     PetscCall(PCFieldSplitSetSchurScale(newpc, 1.0));
2551 
2552     /* we need to setfromoptions and setup here to access the blocks */
2553     PetscCall(PCSetFromOptions(newpc));
2554     PetscCall(PCSetUp(newpc));
2555 
2556     /* user may have changed the type (e.g. -fetidp_pc_type none) */
2557     PetscCall(PetscObjectTypeCompare((PetscObject)newpc, PCFIELDSPLIT, &isfieldsplit));
2558     if (isfieldsplit) {
2559       KSP      *ksps;
2560       PC        ppc, lagpc;
2561       PetscInt  nn;
2562       PetscBool ismatis, matisok = PETSC_FALSE, check = PETSC_FALSE;
2563 
2564       /* set the solver for the (0,0) block */
2565       PetscCall(PCFieldSplitSchurGetSubKSP(newpc, &nn, &ksps));
2566       if (!nn) { /* not of type PC_COMPOSITE_SCHUR */
2567         PetscCall(PCFieldSplitGetSubKSP(newpc, &nn, &ksps));
2568         if (!fake) { /* pass pmat to the pressure solver */
2569           Mat F;
2570 
2571           PetscCall(KSPGetOperators(ksps[1], &F, NULL));
2572           PetscCall(KSPSetOperators(ksps[1], F, M));
2573         }
2574       } else {
2575         PetscBool issym, isset;
2576         Mat       S;
2577 
2578         PetscCall(PCFieldSplitSchurGetS(newpc, &S));
2579         PetscCall(MatIsSymmetricKnown(newmat, &isset, &issym));
2580         if (isset) PetscCall(MatSetOption(S, MAT_SYMMETRIC, issym));
2581       }
2582       PetscCall(KSPGetPC(ksps[0], &lagpc));
2583       PetscCall(PCSetType(lagpc, PCSHELL));
2584       PetscCall(PCShellSetName(lagpc, "FETI-DP multipliers"));
2585       PetscCall(PCShellSetContext(lagpc, fetidppc_ctx));
2586       PetscCall(PCShellSetApply(lagpc, FETIDPPCApply));
2587       PetscCall(PCShellSetApplyTranspose(lagpc, FETIDPPCApplyTranspose));
2588       PetscCall(PCShellSetView(lagpc, FETIDPPCView));
2589       PetscCall(PCShellSetDestroy(lagpc, PCBDDCDestroyFETIDPPC));
2590 
2591       /* Olof's idea: interface Schur complement preconditioner for the mass matrix */
2592       PetscCall(KSPGetPC(ksps[1], &ppc));
2593       if (fake) {
2594         BDDCIPC_ctx    bddcipc_ctx;
2595         PetscContainer c;
2596 
2597         matisok = PETSC_TRUE;
2598 
2599         /* create inner BDDC solver */
2600         PetscCall(PetscNew(&bddcipc_ctx));
2601         PetscCall(PCCreate(comm, &bddcipc_ctx->bddc));
2602         PetscCall(PCSetType(bddcipc_ctx->bddc, PCBDDC));
2603         PetscCall(PCSetOperators(bddcipc_ctx->bddc, M, M));
2604         PetscCall(PetscObjectQuery((PetscObject)pc, "__KSPFETIDP_pCSR", (PetscObject *)&c));
2605         PetscCall(PetscObjectTypeCompare((PetscObject)M, MATIS, &ismatis));
2606         if (c && ismatis) {
2607           Mat       lM;
2608           PetscInt *csr, n;
2609 
2610           PetscCall(MatISGetLocalMat(M, &lM));
2611           PetscCall(MatGetSize(lM, &n, NULL));
2612           PetscCall(PetscContainerGetPointer(c, (void **)&csr));
2613           PetscCall(PCBDDCSetLocalAdjacencyGraph(bddcipc_ctx->bddc, n, csr, csr + (n + 1), PETSC_COPY_VALUES));
2614           PetscCall(MatISRestoreLocalMat(M, &lM));
2615         }
2616         PetscCall(PCSetOptionsPrefix(bddcipc_ctx->bddc, ((PetscObject)ksps[1])->prefix));
2617         PetscCall(PCSetErrorIfFailure(bddcipc_ctx->bddc, pc->erroriffailure));
2618         PetscCall(PCSetFromOptions(bddcipc_ctx->bddc));
2619 
2620         /* wrap the interface application */
2621         PetscCall(PCSetType(ppc, PCSHELL));
2622         PetscCall(PCShellSetName(ppc, "FETI-DP pressure"));
2623         PetscCall(PCShellSetContext(ppc, bddcipc_ctx));
2624         PetscCall(PCShellSetSetUp(ppc, PCSetUp_BDDCIPC));
2625         PetscCall(PCShellSetApply(ppc, PCApply_BDDCIPC));
2626         PetscCall(PCShellSetApplyTranspose(ppc, PCApplyTranspose_BDDCIPC));
2627         PetscCall(PCShellSetView(ppc, PCView_BDDCIPC));
2628         PetscCall(PCShellSetDestroy(ppc, PCDestroy_BDDCIPC));
2629       }
2630 
2631       /* determine if we need to assemble M to construct a preconditioner */
2632       if (!matisok) {
2633         PetscCall(PetscObjectTypeCompare((PetscObject)M, MATIS, &ismatis));
2634         PetscCall(PetscObjectTypeCompareAny((PetscObject)ppc, &matisok, PCBDDC, PCJACOBI, PCNONE, PCMG, ""));
2635         if (ismatis && !matisok) PetscCall(MatConvert(M, MATAIJ, MAT_INPLACE_MATRIX, &M));
2636       }
2637 
2638       /* run the subproblems to check convergence */
2639       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)newmat)->prefix, "-check_saddlepoint", &check, NULL));
2640       if (check) {
2641         PetscInt i;
2642 
2643         for (i = 0; i < nn; i++) {
2644           KSP       kspC;
2645           PC        npc;
2646           Mat       F, pF;
2647           Vec       x, y;
2648           PetscBool isschur, prec = PETSC_TRUE;
2649 
2650           PetscCall(KSPCreate(PetscObjectComm((PetscObject)ksps[i]), &kspC));
2651           PetscCall(KSPSetNestLevel(kspC, pc->kspnestlevel));
2652           PetscCall(KSPSetOptionsPrefix(kspC, ((PetscObject)ksps[i])->prefix));
2653           PetscCall(KSPAppendOptionsPrefix(kspC, "check_"));
2654           PetscCall(KSPGetOperators(ksps[i], &F, &pF));
2655           PetscCall(PetscObjectTypeCompare((PetscObject)F, MATSCHURCOMPLEMENT, &isschur));
2656           if (isschur) {
2657             KSP  kspS, kspS2;
2658             Mat  A00, pA00, A10, A01, A11;
2659             char prefix[256];
2660 
2661             PetscCall(MatSchurComplementGetKSP(F, &kspS));
2662             PetscCall(MatSchurComplementGetSubMatrices(F, &A00, &pA00, &A01, &A10, &A11));
2663             PetscCall(MatCreateSchurComplement(A00, pA00, A01, A10, A11, &F));
2664             PetscCall(MatSchurComplementGetKSP(F, &kspS2));
2665             PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sschur_", ((PetscObject)kspC)->prefix));
2666             PetscCall(KSPSetOptionsPrefix(kspS2, prefix));
2667             PetscCall(KSPGetPC(kspS2, &npc));
2668             PetscCall(PCSetType(npc, PCKSP));
2669             PetscCall(PCKSPSetKSP(npc, kspS));
2670             PetscCall(KSPSetFromOptions(kspS2));
2671             PetscCall(KSPGetPC(kspS2, &npc));
2672             PetscCall(PCSetUseAmat(npc, PETSC_TRUE));
2673           } else {
2674             PetscCall(PetscObjectReference((PetscObject)F));
2675           }
2676           PetscCall(KSPSetFromOptions(kspC));
2677           PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)kspC)->prefix, "-preconditioned", &prec, NULL));
2678           if (prec) {
2679             PetscCall(KSPGetPC(ksps[i], &npc));
2680             PetscCall(KSPSetPC(kspC, npc));
2681           }
2682           PetscCall(KSPSetOperators(kspC, F, pF));
2683           PetscCall(MatCreateVecs(F, &x, &y));
2684           PetscCall(VecSetRandom(x, NULL));
2685           PetscCall(MatMult(F, x, y));
2686           PetscCall(KSPSolve(kspC, y, x));
2687           PetscCall(KSPCheckSolve(kspC, npc, x));
2688           PetscCall(KSPDestroy(&kspC));
2689           PetscCall(MatDestroy(&F));
2690           PetscCall(VecDestroy(&x));
2691           PetscCall(VecDestroy(&y));
2692         }
2693       }
2694       PetscCall(PetscFree(ksps));
2695     }
2696   }
2697   /* return pointers for objects created */
2698   *fetidp_mat = newmat;
2699   *fetidp_pc  = newpc;
2700   PetscFunctionReturn(PETSC_SUCCESS);
2701 }
2702 
2703 /*@C
2704   PCBDDCCreateFETIDPOperators - Create FETI-DP operators
2705 
2706   Collective
2707 
2708   Input Parameters:
2709 + pc              - the `PCBDDC` preconditioning context (setup should have been called before)
2710 . fully_redundant - true for a fully redundant set of Lagrange multipliers
2711 - prefix          - optional options database prefix for the objects to be created (can be `NULL`)
2712 
2713   Output Parameters:
2714 + fetidp_mat - shell FETI-DP matrix object
2715 - fetidp_pc  - shell Dirichlet preconditioner for FETI-DP matrix
2716 
2717   Level: developer
2718 
2719   Note:
2720   Currently the only operations provided for FETI-DP matrix are `MatMult()` and `MatMultTranspose()`
2721 
2722 .seealso: [](ch_ksp), `PCBDDC`, `PCBDDCMatFETIDPGetRHS()`, `PCBDDCMatFETIDPGetSolution()`
2723 @*/
2724 PetscErrorCode PCBDDCCreateFETIDPOperators(PC pc, PetscBool fully_redundant, const char *prefix, Mat *fetidp_mat, PC *fetidp_pc)
2725 {
2726   PetscFunctionBegin;
2727   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2728   PetscCheck(pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "You must call PCSetup_BDDC() first");
2729   PetscUseMethod(pc, "PCBDDCCreateFETIDPOperators_C", (PC, PetscBool, const char *, Mat *, PC *), (pc, fully_redundant, prefix, fetidp_mat, fetidp_pc));
2730   PetscFunctionReturn(PETSC_SUCCESS);
2731 }
2732 
2733 /*MC
2734    PCBDDC - Balancing Domain Decomposition by Constraints preconditioners, {cite}`dohrmann2007approximate`, {cite}`klawonn2006dual`, {cite}`mandel2008multispace`
2735 
2736    Requires `MATIS` matrices (Pmat) with local matrices (inside the `MATIS`) of type `MATSEQAIJ`, `MATSEQBAIJ` or `MATSEQSBAIJ`
2737 
2738    It also works with unsymmetric and indefinite problems.
2739 
2740    Unlike 'conventional' interface preconditioners, `PCBDDC` iterates over all degrees of freedom, not just those on the interface. This allows the use
2741    of approximate solvers on the subdomains.
2742 
2743    Approximate local solvers are automatically adapted (see {cite}`dohrmann2007approximate`,) if the user has attached a nullspace object to the subdomain matrices, and informed
2744    `PCBDDC` of using approximate solvers (via the command line).
2745 
2746    Boundary nodes are split in vertices, edges and faces classes using information from the local to global mapping of dofs and the local connectivity graph of nodes.
2747    The latter can be customized by using `PCBDDCSetLocalAdjacencyGraph()`
2748 
2749    Additional information on dofs can be provided by using `PCBDDCSetDofsSplitting()`, `PCBDDCSetDirichletBoundaries()`, `PCBDDCSetNeumannBoundaries()`, and
2750    `PCBDDCSetPrimalVerticesIS()` and their local counterparts.
2751 
2752    Constraints can be customized by attaching a `MatNullSpace` object to the `MATIS` matrix via `MatSetNearNullSpace()`. Non-singular modes are retained via SVD.
2753 
2754    Change of basis is performed similarly to {cite}`klawonn2006dual` when requested. When more than one constraint is present on a single connected component
2755    (i.e. an edge or a face), a robust method based on local QR factorizations is used.
2756    User defined change of basis can be passed to `PCBDDC` with `PCBDDCSetChangeOfBasisMat()`
2757 
2758    The PETSc implementation also supports multilevel `PCBDDC` {cite}`mandel2008multispace`. Coarse grids are partitioned using a `MatPartitioning` object.
2759 
2760    Adaptive selection of primal constraints is supported for SPD systems with high-contrast in the coefficients if MUMPS or MKL_PARDISO are present.
2761    Future versions of the code will also consider using PASTIX.
2762 
2763    An experimental interface to the FETI-DP method is available. FETI-DP operators could be created using `PCBDDCCreateFETIDPOperators()`.
2764     A stand-alone class for the FETI-DP method will be provided in the next releases.
2765 
2766    Options Database Keys:
2767 +    -pc_bddc_use_vertices <true>         - use or not vertices in primal space
2768 .    -pc_bddc_use_edges <true>            - use or not edges in primal space
2769 .    -pc_bddc_use_faces <false>           - use or not faces in primal space
2770 .    -pc_bddc_symmetric <true>            - symmetric computation of primal basis functions. Specify false for unsymmetric problems
2771 .    -pc_bddc_use_change_of_basis <false> - use change of basis approach (on edges only)
2772 .    -pc_bddc_use_change_on_faces <false> - use change of basis approach on faces if change of basis has been requested
2773 .    -pc_bddc_switch_static <false>       - switches from M_2 (default) to M_3 operator (see reference article [1])
2774 .    -pc_bddc_levels <0>                  - maximum number of levels for multilevel
2775 .    -pc_bddc_coarsening_ratio <8>        - number of subdomains which will be aggregated together at the coarser level (e.g. H/h ratio at the coarser level, significative only in the multilevel case)
2776 .    -pc_bddc_coarse_redistribute <0>     - size of a subset of processors where the coarse problem will be remapped (the value is ignored if not at the coarsest level)
2777 .    -pc_bddc_use_deluxe_scaling <false>  - use deluxe scaling
2778 .    -pc_bddc_schur_layers <\-1>          - select the economic version of deluxe scaling by specifying the number of layers (-1 corresponds to the original deluxe scaling)
2779 .    -pc_bddc_adaptive_threshold <0.0>    - when a value different than zero is specified, adaptive selection of constraints is performed on edges and faces (requires deluxe scaling and MUMPS or MKL_PARDISO installed)
2780 -    -pc_bddc_check_level <0>             - set verbosity level of debugging output
2781 
2782    Options for Dirichlet, Neumann or coarse solver can be set using the appropriate options prefix
2783 .vb
2784       -pc_bddc_dirichlet_
2785       -pc_bddc_neumann_
2786       -pc_bddc_coarse_
2787 .ve
2788    e.g. -pc_bddc_dirichlet_ksp_type richardson -pc_bddc_dirichlet_pc_type gamg. `PCBDDC` uses by default `KSPPREONLY` and `PCLU`.
2789 
2790    When using a multilevel approach, solvers' options at the N-th level (N > 1) can be specified using the options prefix
2791 .vb
2792       -pc_bddc_dirichlet_lN_
2793       -pc_bddc_neumann_lN_
2794       -pc_bddc_coarse_lN_
2795 .ve
2796    Note that level number ranges from the finest (0) to the coarsest (N).
2797    In order to specify options for the `PCBDDC` operators at the coarser levels (and not for the solvers), prepend -pc_bddc_coarse_ or -pc_bddc_coarse_l
2798    to the option, e.g.
2799 .vb
2800      -pc_bddc_coarse_pc_bddc_adaptive_threshold 5 -pc_bddc_coarse_l1_pc_bddc_redistribute 3
2801 .ve
2802    will use a threshold of 5 for constraints' selection at the first coarse level and will redistribute the coarse problem of the first coarse level on 3 processors
2803 
2804    Level: intermediate
2805 
2806    Contributed by:
2807    Stefano Zampini
2808 
2809 .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `MATIS`, `PCLU`, `PCGAMG`, `PC`, `PCBDDCSetLocalAdjacencyGraph()`, `PCBDDCSetDofsSplitting()`,
2810           `PCBDDCSetDirichletBoundaries()`, `PCBDDCSetNeumannBoundaries()`, `PCBDDCSetPrimalVerticesIS()`, `MatNullSpace`, `MatSetNearNullSpace()`,
2811           `PCBDDCSetChangeOfBasisMat()`, `PCBDDCCreateFETIDPOperators()`, `PCNN`
2812 M*/
2813 
2814 PETSC_EXTERN PetscErrorCode PCCreate_BDDC(PC pc)
2815 {
2816   PC_BDDC *pcbddc;
2817 
2818   PetscFunctionBegin;
2819   PetscCall(PetscNew(&pcbddc));
2820   pc->data = pcbddc;
2821 
2822   PetscCall(PCISInitialize(pc));
2823 
2824   /* create local graph structure */
2825   PetscCall(PCBDDCGraphCreate(&pcbddc->mat_graph));
2826 
2827   /* BDDC nonzero defaults */
2828   pcbddc->use_nnsp                  = PETSC_TRUE;
2829   pcbddc->use_local_adj             = PETSC_TRUE;
2830   pcbddc->use_vertices              = PETSC_TRUE;
2831   pcbddc->use_edges                 = PETSC_TRUE;
2832   pcbddc->symmetric_primal          = PETSC_TRUE;
2833   pcbddc->vertex_size               = 1;
2834   pcbddc->recompute_topography      = PETSC_TRUE;
2835   pcbddc->coarse_size               = -1;
2836   pcbddc->use_exact_dirichlet_trick = PETSC_TRUE;
2837   pcbddc->coarsening_ratio          = 8;
2838   pcbddc->coarse_eqs_per_proc       = 1;
2839   pcbddc->benign_compute_correction = PETSC_TRUE;
2840   pcbddc->nedfield                  = -1;
2841   pcbddc->nedglobal                 = PETSC_TRUE;
2842   pcbddc->graphmaxcount             = PETSC_MAX_INT;
2843   pcbddc->sub_schurs_layers         = -1;
2844   pcbddc->adaptive_threshold[0]     = 0.0;
2845   pcbddc->adaptive_threshold[1]     = 0.0;
2846 
2847   /* function pointers */
2848   pc->ops->apply               = PCApply_BDDC;
2849   pc->ops->applytranspose      = PCApplyTranspose_BDDC;
2850   pc->ops->setup               = PCSetUp_BDDC;
2851   pc->ops->destroy             = PCDestroy_BDDC;
2852   pc->ops->setfromoptions      = PCSetFromOptions_BDDC;
2853   pc->ops->view                = PCView_BDDC;
2854   pc->ops->applyrichardson     = NULL;
2855   pc->ops->applysymmetricleft  = NULL;
2856   pc->ops->applysymmetricright = NULL;
2857   pc->ops->presolve            = PCPreSolve_BDDC;
2858   pc->ops->postsolve           = PCPostSolve_BDDC;
2859   pc->ops->reset               = PCReset_BDDC;
2860 
2861   /* composing function */
2862   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDiscreteGradient_C", PCBDDCSetDiscreteGradient_BDDC));
2863   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDivergenceMat_C", PCBDDCSetDivergenceMat_BDDC));
2864   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetChangeOfBasisMat_C", PCBDDCSetChangeOfBasisMat_BDDC));
2865   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetPrimalVerticesLocalIS_C", PCBDDCSetPrimalVerticesLocalIS_BDDC));
2866   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetPrimalVerticesIS_C", PCBDDCSetPrimalVerticesIS_BDDC));
2867   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetPrimalVerticesLocalIS_C", PCBDDCGetPrimalVerticesLocalIS_BDDC));
2868   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetPrimalVerticesIS_C", PCBDDCGetPrimalVerticesIS_BDDC));
2869   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetCoarseningRatio_C", PCBDDCSetCoarseningRatio_BDDC));
2870   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLevel_C", PCBDDCSetLevel_BDDC));
2871   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetUseExactDirichlet_C", PCBDDCSetUseExactDirichlet_BDDC));
2872   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLevels_C", PCBDDCSetLevels_BDDC));
2873   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDirichletBoundaries_C", PCBDDCSetDirichletBoundaries_BDDC));
2874   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDirichletBoundariesLocal_C", PCBDDCSetDirichletBoundariesLocal_BDDC));
2875   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetNeumannBoundaries_C", PCBDDCSetNeumannBoundaries_BDDC));
2876   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetNeumannBoundariesLocal_C", PCBDDCSetNeumannBoundariesLocal_BDDC));
2877   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetDirichletBoundaries_C", PCBDDCGetDirichletBoundaries_BDDC));
2878   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetDirichletBoundariesLocal_C", PCBDDCGetDirichletBoundariesLocal_BDDC));
2879   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetNeumannBoundaries_C", PCBDDCGetNeumannBoundaries_BDDC));
2880   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCGetNeumannBoundariesLocal_C", PCBDDCGetNeumannBoundariesLocal_BDDC));
2881   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDofsSplitting_C", PCBDDCSetDofsSplitting_BDDC));
2882   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetDofsSplittingLocal_C", PCBDDCSetDofsSplittingLocal_BDDC));
2883   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCSetLocalAdjacencyGraph_C", PCBDDCSetLocalAdjacencyGraph_BDDC));
2884   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCCreateFETIDPOperators_C", PCBDDCCreateFETIDPOperators_BDDC));
2885   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCMatFETIDPGetRHS_C", PCBDDCMatFETIDPGetRHS_BDDC));
2886   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCBDDCMatFETIDPGetSolution_C", PCBDDCMatFETIDPGetSolution_BDDC));
2887   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", PCPreSolveChangeRHS_BDDC));
2888   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_BDDC));
2889   PetscFunctionReturn(PETSC_SUCCESS);
2890 }
2891 
2892 /*@C
2893   PCBDDCInitializePackage - This function initializes everything in the `PCBDDC` package. It is called
2894   from `PCInitializePackage()`.
2895 
2896   Level: developer
2897 
2898 .seealso: [](ch_ksp), `PetscInitialize()`, `PCBDDCFinalizePackage()`
2899 @*/
2900 PetscErrorCode PCBDDCInitializePackage(void)
2901 {
2902   int i;
2903 
2904   PetscFunctionBegin;
2905   if (PCBDDCPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
2906   PCBDDCPackageInitialized = PETSC_TRUE;
2907   PetscCall(PetscRegisterFinalize(PCBDDCFinalizePackage));
2908 
2909   /* general events */
2910   PetscCall(PetscLogEventRegister("PCBDDCTopo", PC_CLASSID, &PC_BDDC_Topology[0]));
2911   PetscCall(PetscLogEventRegister("PCBDDCLKSP", PC_CLASSID, &PC_BDDC_LocalSolvers[0]));
2912   PetscCall(PetscLogEventRegister("PCBDDCLWor", PC_CLASSID, &PC_BDDC_LocalWork[0]));
2913   PetscCall(PetscLogEventRegister("PCBDDCCorr", PC_CLASSID, &PC_BDDC_CorrectionSetUp[0]));
2914   PetscCall(PetscLogEventRegister("PCBDDCASet", PC_CLASSID, &PC_BDDC_ApproxSetUp[0]));
2915   PetscCall(PetscLogEventRegister("PCBDDCAApp", PC_CLASSID, &PC_BDDC_ApproxApply[0]));
2916   PetscCall(PetscLogEventRegister("PCBDDCCSet", PC_CLASSID, &PC_BDDC_CoarseSetUp[0]));
2917   PetscCall(PetscLogEventRegister("PCBDDCCKSP", PC_CLASSID, &PC_BDDC_CoarseSolver[0]));
2918   PetscCall(PetscLogEventRegister("PCBDDCAdap", PC_CLASSID, &PC_BDDC_AdaptiveSetUp[0]));
2919   PetscCall(PetscLogEventRegister("PCBDDCScal", PC_CLASSID, &PC_BDDC_Scaling[0]));
2920   PetscCall(PetscLogEventRegister("PCBDDCSchr", PC_CLASSID, &PC_BDDC_Schurs[0]));
2921   PetscCall(PetscLogEventRegister("PCBDDCDirS", PC_CLASSID, &PC_BDDC_Solves[0][0]));
2922   PetscCall(PetscLogEventRegister("PCBDDCNeuS", PC_CLASSID, &PC_BDDC_Solves[0][1]));
2923   PetscCall(PetscLogEventRegister("PCBDDCCoaS", PC_CLASSID, &PC_BDDC_Solves[0][2]));
2924   for (i = 1; i < PETSC_PCBDDC_MAXLEVELS; i++) {
2925     char ename[32];
2926 
2927     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCTopo l%02d", i));
2928     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Topology[i]));
2929     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCLKSP l%02d", i));
2930     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_LocalSolvers[i]));
2931     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCLWor l%02d", i));
2932     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_LocalWork[i]));
2933     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCCorr l%02d", i));
2934     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_CorrectionSetUp[i]));
2935     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCASet l%02d", i));
2936     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_ApproxSetUp[i]));
2937     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCAApp l%02d", i));
2938     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_ApproxApply[i]));
2939     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCCSet l%02d", i));
2940     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_CoarseSetUp[i]));
2941     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCCKSP l%02d", i));
2942     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_CoarseSolver[i]));
2943     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCAdap l%02d", i));
2944     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_AdaptiveSetUp[i]));
2945     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCScal l%02d", i));
2946     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Scaling[i]));
2947     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCSchr l%02d", i));
2948     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Schurs[i]));
2949     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCDirS l%02d", i));
2950     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Solves[i][0]));
2951     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCNeuS l%02d", i));
2952     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Solves[i][1]));
2953     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCBDDCCoaS l%02d", i));
2954     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &PC_BDDC_Solves[i][2]));
2955   }
2956   PetscFunctionReturn(PETSC_SUCCESS);
2957 }
2958 
2959 /*@C
2960   PCBDDCFinalizePackage - This function frees everything from the `PCBDDC` package. It is
2961   called from `PetscFinalize()` automatically.
2962 
2963   Level: developer
2964 
2965 .seealso: [](ch_ksp), `PetscFinalize()`, `PCBDDCInitializePackage()`
2966 @*/
2967 PetscErrorCode PCBDDCFinalizePackage(void)
2968 {
2969   PetscFunctionBegin;
2970   PCBDDCPackageInitialized = PETSC_FALSE;
2971   PetscFunctionReturn(PETSC_SUCCESS);
2972 }
2973