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