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