xref: /petsc/src/ksp/pc/impls/bddc/bddc.c (revision fdf6c4e30aafdbc795e4f76379caa977fd5cdf5a)
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) PetscCall(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1376   }
1377   PetscCall(VecDestroy(&used_vec));
1378 
1379   /* compute initial vector in benign space if needed
1380      and remove non-benign solution from the rhs */
1381   benign_correction_computed = PETSC_FALSE;
1382   if (rhs && pcbddc->benign_compute_correction && (pcbddc->benign_have_null || pcbddc->benign_apply_coarse_only)) {
1383     /* compute u^*_h using ideas similar to those in Xuemin Tu's PhD thesis (see Section 4.8.1)
1384        Recursively apply BDDC in the multilevel case */
1385     if (!pcbddc->benign_vec) {
1386       PetscCall(VecDuplicate(rhs,&pcbddc->benign_vec));
1387     }
1388     /* keep applying coarse solver unless we no longer have benign subdomains */
1389     pcbddc->benign_apply_coarse_only = pcbddc->benign_have_null ? PETSC_TRUE : PETSC_FALSE;
1390     if (!pcbddc->benign_skip_correction) {
1391       PetscCall(PCApply_BDDC(pc,rhs,pcbddc->benign_vec));
1392       benign_correction_computed = PETSC_TRUE;
1393       if (pcbddc->temp_solution_used) PetscCall(VecAXPY(pcbddc->temp_solution,1.0,pcbddc->benign_vec));
1394       PetscCall(VecScale(pcbddc->benign_vec,-1.0));
1395       /* store the original rhs if not done earlier */
1396       if (save_rhs) PetscCall(VecSwap(rhs,pcbddc->original_rhs));
1397       if (pcbddc->rhs_change) {
1398         PetscCall(MatMultAdd(pc->mat,pcbddc->benign_vec,rhs,rhs));
1399       } else {
1400         PetscCall(MatMultAdd(pc->mat,pcbddc->benign_vec,pcbddc->original_rhs,rhs));
1401       }
1402       pcbddc->rhs_change = PETSC_TRUE;
1403     }
1404     pcbddc->benign_apply_coarse_only = PETSC_FALSE;
1405   } else {
1406     PetscCall(VecDestroy(&pcbddc->benign_vec));
1407   }
1408 
1409   /* dbg output */
1410   if (pcbddc->dbg_flag && benign_correction_computed) {
1411     Vec v;
1412 
1413     PetscCall(VecDuplicate(pcis->vec1_global,&v));
1414     if (pcbddc->ChangeOfBasisMatrix) {
1415       PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix,rhs,v));
1416     } else {
1417       PetscCall(VecCopy(rhs,v));
1418     }
1419     PetscCall(PCBDDCBenignGetOrSetP0(pc,v,PETSC_TRUE));
1420     PetscCall(PetscViewerASCIIPrintf(pcbddc->dbg_viewer,"LEVEL %" PetscInt_FMT ": is the correction benign?\n",pcbddc->current_level));
1421     PetscCall(PetscScalarView(pcbddc->benign_n,pcbddc->benign_p0,pcbddc->dbg_viewer));
1422     PetscCall(PetscViewerFlush(pcbddc->dbg_viewer));
1423     PetscCall(VecDestroy(&v));
1424   }
1425 
1426   /* set initial guess if using PCG */
1427   pcbddc->exact_dirichlet_trick_app = PETSC_FALSE;
1428   if (x && pcbddc->use_exact_dirichlet_trick) {
1429     PetscCall(VecSet(x,0.0));
1430     if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior) {
1431       if (benign_correction_computed) { /* we have already saved the changed rhs */
1432         PetscCall(VecLockReadPop(pcis->vec1_global));
1433       } else {
1434         PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix,rhs,pcis->vec1_global));
1435       }
1436       PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec1_global,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1437       PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec1_global,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1438     } else {
1439       PetscCall(VecScatterBegin(pcis->global_to_D,rhs,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1440       PetscCall(VecScatterEnd(pcis->global_to_D,rhs,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1441     }
1442     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1443     PetscCall(KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D));
1444     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1445     PetscCall(KSPCheckSolve(pcbddc->ksp_D,pc,pcis->vec2_D));
1446     if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior) {
1447       PetscCall(VecSet(pcis->vec1_global,0.));
1448       PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,pcis->vec1_global,INSERT_VALUES,SCATTER_REVERSE));
1449       PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec2_D,pcis->vec1_global,INSERT_VALUES,SCATTER_REVERSE));
1450       PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix,pcis->vec1_global,x));
1451     } else {
1452       PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,x,INSERT_VALUES,SCATTER_REVERSE));
1453       PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec2_D,x,INSERT_VALUES,SCATTER_REVERSE));
1454     }
1455     if (ksp) PetscCall(KSPSetInitialGuessNonzero(ksp,PETSC_TRUE));
1456     pcbddc->exact_dirichlet_trick_app = PETSC_TRUE;
1457   } else if (pcbddc->ChangeOfBasisMatrix && pcbddc->change_interior && benign_correction_computed && pcbddc->use_exact_dirichlet_trick) {
1458     PetscCall(VecLockReadPop(pcis->vec1_global));
1459   }
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 /*
1464    PCPostSolve_BDDC - Changes the computed solution if a transformation of basis
1465                      approach has been selected. Also, restores rhs to its original state.
1466 
1467    Input Parameter:
1468 +  pc - the preconditioner context
1469 
1470    Application Interface Routine: PCPostSolve()
1471 
1472    Notes:
1473      The interface routine PCPostSolve() is not usually called directly by
1474      the user, but instead is called by KSPSolve().
1475 */
1476 static PetscErrorCode PCPostSolve_BDDC(PC pc, KSP ksp, Vec rhs, Vec x)
1477 {
1478   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
1479 
1480   PetscFunctionBegin;
1481   /* add solution removed in presolve */
1482   if (x && pcbddc->rhs_change) {
1483     if (pcbddc->temp_solution_used) {
1484       PetscCall(VecAXPY(x,1.0,pcbddc->temp_solution));
1485     } else if (pcbddc->benign_compute_correction && pcbddc->benign_vec) {
1486       PetscCall(VecAXPY(x,-1.0,pcbddc->benign_vec));
1487     }
1488     /* restore to original state (not for FETI-DP) */
1489     if (ksp) pcbddc->temp_solution_used = PETSC_FALSE;
1490   }
1491 
1492   /* restore rhs to its original state (not needed for FETI-DP) */
1493   if (rhs && pcbddc->rhs_change) {
1494     PetscCall(VecSwap(rhs,pcbddc->original_rhs));
1495     pcbddc->rhs_change = PETSC_FALSE;
1496   }
1497   /* restore ksp guess state */
1498   if (ksp) {
1499     PetscCall(KSPSetInitialGuessNonzero(ksp,pcbddc->ksp_guess_nonzero));
1500     /* reset flag for exact dirichlet trick */
1501     pcbddc->exact_dirichlet_trick_app = PETSC_FALSE;
1502   }
1503   PetscFunctionReturn(0);
1504 }
1505 
1506 /*
1507    PCSetUp_BDDC - Prepares for the use of the BDDC preconditioner
1508                   by setting data structures and options.
1509 
1510    Input Parameter:
1511 +  pc - the preconditioner context
1512 
1513    Application Interface Routine: PCSetUp()
1514 
1515    Notes:
1516      The interface routine PCSetUp() is not usually called directly by
1517      the user, but instead is called by PCApply() if necessary.
1518 */
1519 PetscErrorCode PCSetUp_BDDC(PC pc)
1520 {
1521   PC_BDDC*        pcbddc = (PC_BDDC*)pc->data;
1522   PCBDDCSubSchurs sub_schurs;
1523   Mat_IS*         matis;
1524   MatNullSpace    nearnullspace;
1525   Mat             lA;
1526   IS              lP,zerodiag = NULL;
1527   PetscInt        nrows,ncols;
1528   PetscMPIInt     size;
1529   PetscBool       computesubschurs;
1530   PetscBool       computeconstraintsmatrix;
1531   PetscBool       new_nearnullspace_provided,ismatis,rl;
1532   PetscBool       isset,issym,isspd;
1533 
1534   PetscFunctionBegin;
1535   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATIS,&ismatis));
1536   PetscCheck(ismatis,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"PCBDDC preconditioner requires matrix of type MATIS");
1537   PetscCall(MatGetSize(pc->pmat,&nrows,&ncols));
1538   PetscCheck(nrows == ncols,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"PCBDDC preconditioner requires a square preconditioning matrix");
1539   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size));
1540 
1541   matis = (Mat_IS*)pc->pmat->data;
1542   /* the following lines of code should be replaced by a better logic between PCIS, PCNN, PCBDDC and other future nonoverlapping preconditioners */
1543   /* For BDDC we need to define a local "Neumann" problem different to that defined in PCISSetup
1544      Also, BDDC builds its own KSP for the Dirichlet problem */
1545   rl = pcbddc->recompute_topography;
1546   if (!pc->setupcalled || pc->flag == DIFFERENT_NONZERO_PATTERN) rl = PETSC_TRUE;
1547   PetscCall(MPIU_Allreduce(&rl,&pcbddc->recompute_topography,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)pc)));
1548   if (pcbddc->recompute_topography) {
1549     pcbddc->graphanalyzed    = PETSC_FALSE;
1550     computeconstraintsmatrix = PETSC_TRUE;
1551   } else {
1552     computeconstraintsmatrix = PETSC_FALSE;
1553   }
1554 
1555   /* check parameters' compatibility */
1556   if (!pcbddc->use_deluxe_scaling) pcbddc->deluxe_zerorows = PETSC_FALSE;
1557   pcbddc->adaptive_selection   = (PetscBool)(pcbddc->adaptive_threshold[0] != 0.0 || pcbddc->adaptive_threshold[1] != 0.0);
1558   pcbddc->use_deluxe_scaling   = (PetscBool)(pcbddc->use_deluxe_scaling && size > 1);
1559   pcbddc->adaptive_selection   = (PetscBool)(pcbddc->adaptive_selection && size > 1);
1560   pcbddc->adaptive_userdefined = (PetscBool)(pcbddc->adaptive_selection && pcbddc->adaptive_userdefined);
1561   if (pcbddc->adaptive_selection) pcbddc->use_faces = PETSC_TRUE;
1562 
1563   computesubschurs = (PetscBool)(pcbddc->adaptive_selection || pcbddc->use_deluxe_scaling);
1564 
1565   /* activate all connected components if the netflux has been requested */
1566   if (pcbddc->compute_nonetflux) {
1567     pcbddc->use_vertices = PETSC_TRUE;
1568     pcbddc->use_edges    = PETSC_TRUE;
1569     pcbddc->use_faces    = PETSC_TRUE;
1570   }
1571 
1572   /* Get stdout for dbg */
1573   if (pcbddc->dbg_flag) {
1574     if (!pcbddc->dbg_viewer) {
1575       pcbddc->dbg_viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)pc));
1576     }
1577     PetscCall(PetscViewerASCIIPushSynchronized(pcbddc->dbg_viewer));
1578     PetscCall(PetscViewerASCIIAddTab(pcbddc->dbg_viewer,2*pcbddc->current_level));
1579   }
1580 
1581   /* process topology information */
1582   PetscCall(PetscLogEventBegin(PC_BDDC_Topology[pcbddc->current_level],pc,0,0,0));
1583   if (pcbddc->recompute_topography) {
1584     PetscCall(PCBDDCComputeLocalTopologyInfo(pc));
1585     if (pcbddc->discretegradient) PetscCall(PCBDDCNedelecSupport(pc));
1586   }
1587   if (pcbddc->corner_selected) pcbddc->use_vertices = PETSC_TRUE;
1588 
1589   /* change basis if requested by the user */
1590   if (pcbddc->user_ChangeOfBasisMatrix) {
1591     /* use_change_of_basis flag is used to automatically compute a change of basis from constraints */
1592     pcbddc->use_change_of_basis = PETSC_FALSE;
1593     PetscCall(PCBDDCComputeLocalMatrix(pc,pcbddc->user_ChangeOfBasisMatrix));
1594   } else {
1595     PetscCall(MatDestroy(&pcbddc->local_mat));
1596     PetscCall(PetscObjectReference((PetscObject)matis->A));
1597     pcbddc->local_mat = matis->A;
1598   }
1599 
1600   /*
1601      Compute change of basis on local pressures (aka zerodiag dofs) with the benign trick
1602      This should come earlier then PCISSetUp for extracting the correct subdomain matrices
1603   */
1604   PetscCall(PCBDDCBenignShellMat(pc,PETSC_TRUE));
1605   if (pcbddc->benign_saddle_point) {
1606     PC_IS* pcis = (PC_IS*)pc->data;
1607 
1608     if (pcbddc->user_ChangeOfBasisMatrix || pcbddc->use_change_of_basis || !computesubschurs) pcbddc->benign_change_explicit = PETSC_TRUE;
1609     /* detect local saddle point and change the basis in pcbddc->local_mat */
1610     PetscCall(PCBDDCBenignDetectSaddlePoint(pc,(PetscBool)(!pcbddc->recompute_topography),&zerodiag));
1611     /* pop B0 mat from local mat */
1612     PetscCall(PCBDDCBenignPopOrPushB0(pc,PETSC_TRUE));
1613     /* give pcis a hint to not reuse submatrices during PCISCreate */
1614     if (pc->flag == SAME_NONZERO_PATTERN && pcis->reusesubmatrices == PETSC_TRUE) {
1615       if (pcbddc->benign_n && (pcbddc->benign_change_explicit || pcbddc->dbg_flag)) {
1616         pcis->reusesubmatrices = PETSC_FALSE;
1617       } else {
1618         pcis->reusesubmatrices = PETSC_TRUE;
1619       }
1620     } else {
1621       pcis->reusesubmatrices = PETSC_FALSE;
1622     }
1623   }
1624 
1625   /* propagate relevant information */
1626   PetscCall(MatIsSymmetricKnown(matis->A,&isset,&issym));
1627   if (isset) PetscCall(MatSetOption(pcbddc->local_mat,MAT_SYMMETRIC,issym));
1628   PetscCall(MatIsSPDKnown(matis->A,&isset,&isspd));
1629   if (isset) PetscCall(MatSetOption(pcbddc->local_mat,MAT_SPD,isspd));
1630 
1631   /* Set up all the "iterative substructuring" common block without computing solvers */
1632   {
1633     Mat temp_mat;
1634 
1635     temp_mat = matis->A;
1636     matis->A = pcbddc->local_mat;
1637     PetscCall(PCISSetUp(pc,PETSC_TRUE,PETSC_FALSE));
1638     pcbddc->local_mat = matis->A;
1639     matis->A = temp_mat;
1640   }
1641 
1642   /* Analyze interface */
1643   if (!pcbddc->graphanalyzed) {
1644     PetscCall(PCBDDCAnalyzeInterface(pc));
1645     computeconstraintsmatrix = PETSC_TRUE;
1646     if (pcbddc->adaptive_selection && !pcbddc->use_deluxe_scaling && !pcbddc->mat_graph->twodim) {
1647       SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot compute the adaptive primal space for a problem with 3D edges without deluxe scaling");
1648     }
1649     if (pcbddc->compute_nonetflux) {
1650       MatNullSpace nnfnnsp;
1651 
1652       PetscCheck(pcbddc->divudotp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Missing divudotp operator");
1653       PetscCall(PCBDDCComputeNoNetFlux(pc->pmat,pcbddc->divudotp,pcbddc->divudotp_trans,pcbddc->divudotp_vl2l,pcbddc->mat_graph,&nnfnnsp));
1654       /* TODO what if a nearnullspace is already attached? */
1655       if (nnfnnsp) {
1656         PetscCall(MatSetNearNullSpace(pc->pmat,nnfnnsp));
1657         PetscCall(MatNullSpaceDestroy(&nnfnnsp));
1658       }
1659     }
1660   }
1661   PetscCall(PetscLogEventEnd(PC_BDDC_Topology[pcbddc->current_level],pc,0,0,0));
1662 
1663   /* check existence of a divergence free extension, i.e.
1664      b(v_I,p_0) = 0 for all v_I (raise error if not).
1665      Also, check that PCBDDCBenignGetOrSetP0 works */
1666   if (pcbddc->benign_saddle_point && pcbddc->dbg_flag > 1) {
1667     PetscCall(PCBDDCBenignCheck(pc,zerodiag));
1668   }
1669   PetscCall(ISDestroy(&zerodiag));
1670 
1671   /* Setup local dirichlet solver ksp_D and sub_schurs solvers */
1672   if (computesubschurs && pcbddc->recompute_topography) {
1673     PetscCall(PCBDDCInitSubSchurs(pc));
1674   }
1675   /* SetUp Scaling operator (scaling matrices could be needed in SubSchursSetUp)*/
1676   if (!pcbddc->use_deluxe_scaling) {
1677     PetscCall(PCBDDCScalingSetUp(pc));
1678   }
1679 
1680   /* finish setup solvers and do adaptive selection of constraints */
1681   sub_schurs = pcbddc->sub_schurs;
1682   if (sub_schurs && sub_schurs->schur_explicit) {
1683     if (computesubschurs) PetscCall(PCBDDCSetUpSubSchurs(pc));
1684     PetscCall(PCBDDCSetUpLocalSolvers(pc,PETSC_TRUE,PETSC_FALSE));
1685   } else {
1686     PetscCall(PCBDDCSetUpLocalSolvers(pc,PETSC_TRUE,PETSC_FALSE));
1687     if (computesubschurs) PetscCall(PCBDDCSetUpSubSchurs(pc));
1688   }
1689   if (pcbddc->adaptive_selection) {
1690     PetscCall(PCBDDCAdaptiveSelection(pc));
1691     computeconstraintsmatrix = PETSC_TRUE;
1692   }
1693 
1694   /* infer if NullSpace object attached to Mat via MatSetNearNullSpace has changed */
1695   new_nearnullspace_provided = PETSC_FALSE;
1696   PetscCall(MatGetNearNullSpace(pc->pmat,&nearnullspace));
1697   if (pcbddc->onearnullspace) { /* already used nearnullspace */
1698     if (!nearnullspace) { /* near null space attached to mat has been destroyed */
1699       new_nearnullspace_provided = PETSC_TRUE;
1700     } else {
1701       /* determine if the two nullspaces are different (should be lightweight) */
1702       if (nearnullspace != pcbddc->onearnullspace) {
1703         new_nearnullspace_provided = PETSC_TRUE;
1704       } else { /* maybe the user has changed the content of the nearnullspace so check vectors ObjectStateId */
1705         PetscInt         i;
1706         const Vec        *nearnullvecs;
1707         PetscObjectState state;
1708         PetscInt         nnsp_size;
1709         PetscCall(MatNullSpaceGetVecs(nearnullspace,NULL,&nnsp_size,&nearnullvecs));
1710         for (i=0;i<nnsp_size;i++) {
1711           PetscCall(PetscObjectStateGet((PetscObject)nearnullvecs[i],&state));
1712           if (pcbddc->onearnullvecs_state[i] != state) {
1713             new_nearnullspace_provided = PETSC_TRUE;
1714             break;
1715           }
1716         }
1717       }
1718     }
1719   } else {
1720     if (!nearnullspace) { /* both nearnullspaces are null */
1721       new_nearnullspace_provided = PETSC_FALSE;
1722     } else { /* nearnullspace attached later */
1723       new_nearnullspace_provided = PETSC_TRUE;
1724     }
1725   }
1726 
1727   /* Setup constraints and related work vectors */
1728   /* reset primal space flags */
1729   PetscCall(PetscLogEventBegin(PC_BDDC_LocalWork[pcbddc->current_level],pc,0,0,0));
1730   pcbddc->new_primal_space = PETSC_FALSE;
1731   pcbddc->new_primal_space_local = PETSC_FALSE;
1732   if (computeconstraintsmatrix || new_nearnullspace_provided) {
1733     /* It also sets the primal space flags */
1734     PetscCall(PCBDDCConstraintsSetUp(pc));
1735   }
1736   /* Allocate needed local vectors (which depends on quantities defined during ConstraintsSetUp) */
1737   PetscCall(PCBDDCSetUpLocalWorkVectors(pc));
1738 
1739   if (pcbddc->use_change_of_basis) {
1740     PC_IS *pcis = (PC_IS*)(pc->data);
1741 
1742     PetscCall(PCBDDCComputeLocalMatrix(pc,pcbddc->ChangeOfBasisMatrix));
1743     if (pcbddc->benign_change) {
1744       PetscCall(MatDestroy(&pcbddc->benign_B0));
1745       /* pop B0 from pcbddc->local_mat */
1746       PetscCall(PCBDDCBenignPopOrPushB0(pc,PETSC_TRUE));
1747     }
1748     /* get submatrices */
1749     PetscCall(MatDestroy(&pcis->A_IB));
1750     PetscCall(MatDestroy(&pcis->A_BI));
1751     PetscCall(MatDestroy(&pcis->A_BB));
1752     PetscCall(MatCreateSubMatrix(pcbddc->local_mat,pcis->is_B_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&pcis->A_BB));
1753     PetscCall(MatCreateSubMatrix(pcbddc->local_mat,pcis->is_I_local,pcis->is_B_local,MAT_INITIAL_MATRIX,&pcis->A_IB));
1754     PetscCall(MatCreateSubMatrix(pcbddc->local_mat,pcis->is_B_local,pcis->is_I_local,MAT_INITIAL_MATRIX,&pcis->A_BI));
1755     /* set flag in pcis to not reuse submatrices during PCISCreate */
1756     pcis->reusesubmatrices = PETSC_FALSE;
1757   } else if (!pcbddc->user_ChangeOfBasisMatrix && !pcbddc->benign_change) {
1758     PetscCall(MatDestroy(&pcbddc->local_mat));
1759     PetscCall(PetscObjectReference((PetscObject)matis->A));
1760     pcbddc->local_mat = matis->A;
1761   }
1762 
1763   /* interface pressure block row for B_C */
1764   PetscCall(PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_lP" ,(PetscObject*)&lP));
1765   PetscCall(PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_lA" ,(PetscObject*)&lA));
1766   if (lA && lP) {
1767     PC_IS*    pcis = (PC_IS*)pc->data;
1768     Mat       B_BI,B_BB,Bt_BI,Bt_BB;
1769     PetscBool issym;
1770 
1771     PetscCall(MatIsSymmetric(lA,PETSC_SMALL,&issym));
1772     if (issym) {
1773       PetscCall(MatCreateSubMatrix(lA,lP,pcis->is_I_local,MAT_INITIAL_MATRIX,&B_BI));
1774       PetscCall(MatCreateSubMatrix(lA,lP,pcis->is_B_local,MAT_INITIAL_MATRIX,&B_BB));
1775       PetscCall(MatCreateTranspose(B_BI,&Bt_BI));
1776       PetscCall(MatCreateTranspose(B_BB,&Bt_BB));
1777     } else {
1778       PetscCall(MatCreateSubMatrix(lA,lP,pcis->is_I_local,MAT_INITIAL_MATRIX,&B_BI));
1779       PetscCall(MatCreateSubMatrix(lA,lP,pcis->is_B_local,MAT_INITIAL_MATRIX,&B_BB));
1780       PetscCall(MatCreateSubMatrix(lA,pcis->is_I_local,lP,MAT_INITIAL_MATRIX,&Bt_BI));
1781       PetscCall(MatCreateSubMatrix(lA,pcis->is_B_local,lP,MAT_INITIAL_MATRIX,&Bt_BB));
1782     }
1783     PetscCall(PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_B_BI",(PetscObject)B_BI));
1784     PetscCall(PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_B_BB",(PetscObject)B_BB));
1785     PetscCall(PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_Bt_BI",(PetscObject)Bt_BI));
1786     PetscCall(PetscObjectCompose((PetscObject)pc,"__KSPFETIDP_Bt_BB",(PetscObject)Bt_BB));
1787     PetscCall(MatDestroy(&B_BI));
1788     PetscCall(MatDestroy(&B_BB));
1789     PetscCall(MatDestroy(&Bt_BI));
1790     PetscCall(MatDestroy(&Bt_BB));
1791   }
1792   PetscCall(PetscLogEventEnd(PC_BDDC_LocalWork[pcbddc->current_level],pc,0,0,0));
1793 
1794   /* SetUp coarse and local Neumann solvers */
1795   PetscCall(PCBDDCSetUpSolvers(pc));
1796   /* SetUp Scaling operator */
1797   if (pcbddc->use_deluxe_scaling) PetscCall(PCBDDCScalingSetUp(pc));
1798 
1799   /* mark topography as done */
1800   pcbddc->recompute_topography = PETSC_FALSE;
1801 
1802   /* wrap pcis->A_IB and pcis->A_BI if we did not change explicitly the variables on the pressures */
1803   PetscCall(PCBDDCBenignShellMat(pc,PETSC_FALSE));
1804 
1805   if (pcbddc->dbg_flag) {
1806     PetscCall(PetscViewerASCIISubtractTab(pcbddc->dbg_viewer,2*pcbddc->current_level));
1807     PetscCall(PetscViewerASCIIPopSynchronized(pcbddc->dbg_viewer));
1808   }
1809   PetscFunctionReturn(0);
1810 }
1811 
1812 /*
1813    PCApply_BDDC - Applies the BDDC operator to a vector.
1814 
1815    Input Parameters:
1816 +  pc - the preconditioner context
1817 -  r - input vector (global)
1818 
1819    Output Parameter:
1820 .  z - output vector (global)
1821 
1822    Application Interface Routine: PCApply()
1823  */
1824 PetscErrorCode PCApply_BDDC(PC pc,Vec r,Vec z)
1825 {
1826   PC_IS             *pcis = (PC_IS*)(pc->data);
1827   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
1828   Mat               lA = NULL;
1829   PetscInt          n_B = pcis->n_B, n_D = pcis->n - n_B;
1830   const PetscScalar one = 1.0;
1831   const PetscScalar m_one = -1.0;
1832   const PetscScalar zero = 0.0;
1833 /* This code is similar to that provided in nn.c for PCNN
1834    NN interface preconditioner changed to BDDC
1835    Added support for M_3 preconditioner in the reference article (code is active if pcbddc->switch_static == PETSC_TRUE) */
1836 
1837   PetscFunctionBegin;
1838   PetscCall(PetscCitationsRegister(citation,&cited));
1839   if (pcbddc->switch_static) {
1840     PetscCall(MatISGetLocalMat(pc->useAmat ? pc->mat : pc->pmat,&lA));
1841   }
1842 
1843   if (pcbddc->ChangeOfBasisMatrix) {
1844     Vec swap;
1845 
1846     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix,r,pcbddc->work_change));
1847     swap = pcbddc->work_change;
1848     pcbddc->work_change = r;
1849     r = swap;
1850     /* save rhs so that we don't need to apply the change of basis for the exact dirichlet trick in PreSolve */
1851     if (pcbddc->benign_apply_coarse_only && pcbddc->use_exact_dirichlet_trick && pcbddc->change_interior) {
1852       PetscCall(VecCopy(r,pcis->vec1_global));
1853       PetscCall(VecLockReadPush(pcis->vec1_global));
1854     }
1855   }
1856   if (pcbddc->benign_have_null) { /* get p0 from r */
1857     PetscCall(PCBDDCBenignGetOrSetP0(pc,r,PETSC_TRUE));
1858   }
1859   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_DIRICHLET && !pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
1860     PetscCall(VecCopy(r,z));
1861     /* First Dirichlet solve */
1862     PetscCall(VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1863     PetscCall(VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1864     /*
1865       Assembling right hand side for BDDC operator
1866       - pcis->vec1_D for the Dirichlet part (if needed, i.e. pcbddc->switch_static == PETSC_TRUE)
1867       - pcis->vec1_B the interface part of the global vector z
1868     */
1869     if (n_D) {
1870       PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1871       PetscCall(KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D));
1872       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1873       PetscCall(KSPCheckSolve(pcbddc->ksp_D,pc,pcis->vec2_D));
1874       PetscCall(VecScale(pcis->vec2_D,m_one));
1875       if (pcbddc->switch_static) {
1876         PetscCall(VecSet(pcis->vec1_N,0.));
1877         PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1878         PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1879         if (!pcbddc->switch_static_change) {
1880           PetscCall(MatMult(lA,pcis->vec1_N,pcis->vec2_N));
1881         } else {
1882           PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
1883           PetscCall(MatMult(lA,pcis->vec2_N,pcis->vec1_N));
1884           PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
1885         }
1886         PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_N,pcis->vec1_D,ADD_VALUES,SCATTER_FORWARD));
1887         PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_N,pcis->vec1_D,ADD_VALUES,SCATTER_FORWARD));
1888         PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec2_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
1889         PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec2_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
1890       } else {
1891         PetscCall(MatMult(pcis->A_BI,pcis->vec2_D,pcis->vec1_B));
1892       }
1893     } else {
1894       PetscCall(VecSet(pcis->vec1_B,zero));
1895     }
1896     PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE));
1897     PetscCall(VecScatterEnd(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE));
1898     PetscCall(PCBDDCScalingRestriction(pc,z,pcis->vec1_B));
1899   } else {
1900     if (!pcbddc->benign_apply_coarse_only) {
1901       PetscCall(PCBDDCScalingRestriction(pc,r,pcis->vec1_B));
1902     }
1903   }
1904   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_LUMP) {
1905     PetscCheck(pcbddc->switch_static,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"You forgot to pass -pc_bddc_switch_static");
1906     PetscCall(VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1907     PetscCall(VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
1908   }
1909 
1910   /* Apply interface preconditioner
1911      input/output vecs: pcis->vec1_B and pcis->vec1_D */
1912   PetscCall(PCBDDCApplyInterfacePreconditioner(pc,PETSC_FALSE));
1913 
1914   /* Apply transpose of partition of unity operator */
1915   PetscCall(PCBDDCScalingExtension(pc,pcis->vec1_B,z));
1916   if (pcbddc->interface_extension == PC_BDDC_INTERFACE_EXT_LUMP) {
1917     PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec1_D,z,INSERT_VALUES,SCATTER_REVERSE));
1918     PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec1_D,z,INSERT_VALUES,SCATTER_REVERSE));
1919     PetscFunctionReturn(0);
1920   }
1921   /* Second Dirichlet solve and assembling of output */
1922   PetscCall(VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
1923   PetscCall(VecScatterEnd(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
1924   if (n_B) {
1925     if (pcbddc->switch_static) {
1926       PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec1_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1927       PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec1_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1928       PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1929       PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
1930       if (!pcbddc->switch_static_change) {
1931         PetscCall(MatMult(lA,pcis->vec1_N,pcis->vec2_N));
1932       } else {
1933         PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
1934         PetscCall(MatMult(lA,pcis->vec2_N,pcis->vec1_N));
1935         PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
1936       }
1937       PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_N,pcis->vec3_D,INSERT_VALUES,SCATTER_FORWARD));
1938       PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_N,pcis->vec3_D,INSERT_VALUES,SCATTER_FORWARD));
1939     } else {
1940       PetscCall(MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec3_D));
1941     }
1942   } else if (pcbddc->switch_static) { /* n_B is zero */
1943     if (!pcbddc->switch_static_change) {
1944       PetscCall(MatMult(lA,pcis->vec1_D,pcis->vec3_D));
1945     } else {
1946       PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_D,pcis->vec1_N));
1947       PetscCall(MatMult(lA,pcis->vec1_N,pcis->vec2_N));
1948       PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec2_N,pcis->vec3_D));
1949     }
1950   }
1951   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1952   PetscCall(KSPSolve(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D));
1953   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
1954   PetscCall(KSPCheckSolve(pcbddc->ksp_D,pc,pcis->vec4_D));
1955 
1956   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
1957     if (pcbddc->switch_static) {
1958       PetscCall(VecAXPBYPCZ(pcis->vec2_D,m_one,one,m_one,pcis->vec4_D,pcis->vec1_D));
1959     } else {
1960       PetscCall(VecAXPBY(pcis->vec2_D,m_one,m_one,pcis->vec4_D));
1961     }
1962     PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE));
1963     PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE));
1964   } else {
1965     if (pcbddc->switch_static) {
1966       PetscCall(VecAXPBY(pcis->vec4_D,one,m_one,pcis->vec1_D));
1967     } else {
1968       PetscCall(VecScale(pcis->vec4_D,m_one));
1969     }
1970     PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec4_D,z,INSERT_VALUES,SCATTER_REVERSE));
1971     PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec4_D,z,INSERT_VALUES,SCATTER_REVERSE));
1972   }
1973   if (pcbddc->benign_have_null) { /* set p0 (computed in PCBDDCApplyInterface) */
1974     if (pcbddc->benign_apply_coarse_only) PetscCall(PetscArrayzero(pcbddc->benign_p0,pcbddc->benign_n));
1975     PetscCall(PCBDDCBenignGetOrSetP0(pc,z,PETSC_FALSE));
1976   }
1977 
1978   if (pcbddc->ChangeOfBasisMatrix) {
1979     pcbddc->work_change = r;
1980     PetscCall(VecCopy(z,pcbddc->work_change));
1981     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix,pcbddc->work_change,z));
1982   }
1983   PetscFunctionReturn(0);
1984 }
1985 
1986 /*
1987    PCApplyTranspose_BDDC - Applies the transpose of the BDDC operator to a vector.
1988 
1989    Input Parameters:
1990 +  pc - the preconditioner context
1991 -  r - input vector (global)
1992 
1993    Output Parameter:
1994 .  z - output vector (global)
1995 
1996    Application Interface Routine: PCApplyTranspose()
1997  */
1998 PetscErrorCode PCApplyTranspose_BDDC(PC pc,Vec r,Vec z)
1999 {
2000   PC_IS             *pcis = (PC_IS*)(pc->data);
2001   PC_BDDC           *pcbddc = (PC_BDDC*)(pc->data);
2002   Mat               lA = NULL;
2003   PetscInt          n_B = pcis->n_B, n_D = pcis->n - n_B;
2004   const PetscScalar one = 1.0;
2005   const PetscScalar m_one = -1.0;
2006   const PetscScalar zero = 0.0;
2007 
2008   PetscFunctionBegin;
2009   PetscCall(PetscCitationsRegister(citation,&cited));
2010   if (pcbddc->switch_static) {
2011     PetscCall(MatISGetLocalMat(pc->useAmat ? pc->mat : pc->pmat,&lA));
2012   }
2013   if (pcbddc->ChangeOfBasisMatrix) {
2014     Vec swap;
2015 
2016     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix,r,pcbddc->work_change));
2017     swap = pcbddc->work_change;
2018     pcbddc->work_change = r;
2019     r = swap;
2020     /* save rhs so that we don't need to apply the change of basis for the exact dirichlet trick in PreSolve */
2021     if (pcbddc->benign_apply_coarse_only && pcbddc->exact_dirichlet_trick_app && pcbddc->change_interior) {
2022       PetscCall(VecCopy(r,pcis->vec1_global));
2023       PetscCall(VecLockReadPush(pcis->vec1_global));
2024     }
2025   }
2026   if (pcbddc->benign_have_null) { /* get p0 from r */
2027     PetscCall(PCBDDCBenignGetOrSetP0(pc,r,PETSC_TRUE));
2028   }
2029   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
2030     PetscCall(VecCopy(r,z));
2031     /* First Dirichlet solve */
2032     PetscCall(VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
2033     PetscCall(VecScatterEnd(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD));
2034     /*
2035       Assembling right hand side for BDDC operator
2036       - pcis->vec1_D for the Dirichlet part (if needed, i.e. pcbddc->switch_static == PETSC_TRUE)
2037       - pcis->vec1_B the interface part of the global vector z
2038     */
2039     if (n_D) {
2040       PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
2041       PetscCall(KSPSolveTranspose(pcbddc->ksp_D,pcis->vec1_D,pcis->vec2_D));
2042       PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
2043       PetscCall(KSPCheckSolve(pcbddc->ksp_D,pc,pcis->vec2_D));
2044       PetscCall(VecScale(pcis->vec2_D,m_one));
2045       if (pcbddc->switch_static) {
2046         PetscCall(VecSet(pcis->vec1_N,0.));
2047         PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2048         PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2049         if (!pcbddc->switch_static_change) {
2050           PetscCall(MatMultTranspose(lA,pcis->vec1_N,pcis->vec2_N));
2051         } else {
2052           PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
2053           PetscCall(MatMultTranspose(lA,pcis->vec2_N,pcis->vec1_N));
2054           PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
2055         }
2056         PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_N,pcis->vec1_D,ADD_VALUES,SCATTER_FORWARD));
2057         PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_N,pcis->vec1_D,ADD_VALUES,SCATTER_FORWARD));
2058         PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec2_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
2059         PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec2_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
2060       } else {
2061         PetscCall(MatMultTranspose(pcis->A_IB,pcis->vec2_D,pcis->vec1_B));
2062       }
2063     } else {
2064       PetscCall(VecSet(pcis->vec1_B,zero));
2065     }
2066     PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE));
2067     PetscCall(VecScatterEnd(pcis->global_to_B,pcis->vec1_B,z,ADD_VALUES,SCATTER_REVERSE));
2068     PetscCall(PCBDDCScalingRestriction(pc,z,pcis->vec1_B));
2069   } else {
2070     PetscCall(PCBDDCScalingRestriction(pc,r,pcis->vec1_B));
2071   }
2072 
2073   /* Apply interface preconditioner
2074      input/output vecs: pcis->vec1_B and pcis->vec1_D */
2075   PetscCall(PCBDDCApplyInterfacePreconditioner(pc,PETSC_TRUE));
2076 
2077   /* Apply transpose of partition of unity operator */
2078   PetscCall(PCBDDCScalingExtension(pc,pcis->vec1_B,z));
2079 
2080   /* Second Dirichlet solve and assembling of output */
2081   PetscCall(VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
2082   PetscCall(VecScatterEnd(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD));
2083   if (n_B) {
2084     if (pcbddc->switch_static) {
2085       PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec1_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2086       PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec1_D,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2087       PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2088       PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_B,pcis->vec1_N,INSERT_VALUES,SCATTER_REVERSE));
2089       if (!pcbddc->switch_static_change) {
2090         PetscCall(MatMultTranspose(lA,pcis->vec1_N,pcis->vec2_N));
2091       } else {
2092         PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
2093         PetscCall(MatMultTranspose(lA,pcis->vec2_N,pcis->vec1_N));
2094         PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec1_N,pcis->vec2_N));
2095       }
2096       PetscCall(VecScatterBegin(pcis->N_to_D,pcis->vec2_N,pcis->vec3_D,INSERT_VALUES,SCATTER_FORWARD));
2097       PetscCall(VecScatterEnd(pcis->N_to_D,pcis->vec2_N,pcis->vec3_D,INSERT_VALUES,SCATTER_FORWARD));
2098     } else {
2099       PetscCall(MatMultTranspose(pcis->A_BI,pcis->vec1_B,pcis->vec3_D));
2100     }
2101   } else if (pcbddc->switch_static) { /* n_B is zero */
2102     if (!pcbddc->switch_static_change) {
2103       PetscCall(MatMultTranspose(lA,pcis->vec1_D,pcis->vec3_D));
2104     } else {
2105       PetscCall(MatMult(pcbddc->switch_static_change,pcis->vec1_D,pcis->vec1_N));
2106       PetscCall(MatMultTranspose(lA,pcis->vec1_N,pcis->vec2_N));
2107       PetscCall(MatMultTranspose(pcbddc->switch_static_change,pcis->vec2_N,pcis->vec3_D));
2108     }
2109   }
2110   PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
2111   PetscCall(KSPSolveTranspose(pcbddc->ksp_D,pcis->vec3_D,pcis->vec4_D));
2112   PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],pc,0,0,0));
2113   PetscCall(KSPCheckSolve(pcbddc->ksp_D,pc,pcis->vec4_D));
2114   if (!pcbddc->exact_dirichlet_trick_app && !pcbddc->benign_apply_coarse_only) {
2115     if (pcbddc->switch_static) {
2116       PetscCall(VecAXPBYPCZ(pcis->vec2_D,m_one,one,m_one,pcis->vec4_D,pcis->vec1_D));
2117     } else {
2118       PetscCall(VecAXPBY(pcis->vec2_D,m_one,m_one,pcis->vec4_D));
2119     }
2120     PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE));
2121     PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE));
2122   } else {
2123     if (pcbddc->switch_static) {
2124       PetscCall(VecAXPBY(pcis->vec4_D,one,m_one,pcis->vec1_D));
2125     } else {
2126       PetscCall(VecScale(pcis->vec4_D,m_one));
2127     }
2128     PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec4_D,z,INSERT_VALUES,SCATTER_REVERSE));
2129     PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec4_D,z,INSERT_VALUES,SCATTER_REVERSE));
2130   }
2131   if (pcbddc->benign_have_null) { /* set p0 (computed in PCBDDCApplyInterface) */
2132     PetscCall(PCBDDCBenignGetOrSetP0(pc,z,PETSC_FALSE));
2133   }
2134   if (pcbddc->ChangeOfBasisMatrix) {
2135     pcbddc->work_change = r;
2136     PetscCall(VecCopy(z,pcbddc->work_change));
2137     PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix,pcbddc->work_change,z));
2138   }
2139   PetscFunctionReturn(0);
2140 }
2141 
2142 PetscErrorCode PCReset_BDDC(PC pc)
2143 {
2144   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
2145   PC_IS          *pcis = (PC_IS*)pc->data;
2146   KSP            kspD,kspR,kspC;
2147 
2148   PetscFunctionBegin;
2149   /* free BDDC custom data  */
2150   PetscCall(PCBDDCResetCustomization(pc));
2151   /* destroy objects related to topography */
2152   PetscCall(PCBDDCResetTopography(pc));
2153   /* destroy objects for scaling operator */
2154   PetscCall(PCBDDCScalingDestroy(pc));
2155   /* free solvers stuff */
2156   PetscCall(PCBDDCResetSolvers(pc));
2157   /* free global vectors needed in presolve */
2158   PetscCall(VecDestroy(&pcbddc->temp_solution));
2159   PetscCall(VecDestroy(&pcbddc->original_rhs));
2160   /* free data created by PCIS */
2161   PetscCall(PCISDestroy(pc));
2162 
2163   /* restore defaults */
2164   kspD = pcbddc->ksp_D;
2165   kspR = pcbddc->ksp_R;
2166   kspC = pcbddc->coarse_ksp;
2167   PetscCall(PetscMemzero(pc->data,sizeof(*pcbddc)));
2168   pcis->n_neigh                     = -1;
2169   pcis->scaling_factor              = 1.0;
2170   pcis->reusesubmatrices            = PETSC_TRUE;
2171   pcbddc->use_local_adj             = PETSC_TRUE;
2172   pcbddc->use_vertices              = PETSC_TRUE;
2173   pcbddc->use_edges                 = PETSC_TRUE;
2174   pcbddc->symmetric_primal          = PETSC_TRUE;
2175   pcbddc->vertex_size               = 1;
2176   pcbddc->recompute_topography      = PETSC_TRUE;
2177   pcbddc->coarse_size               = -1;
2178   pcbddc->use_exact_dirichlet_trick = PETSC_TRUE;
2179   pcbddc->coarsening_ratio          = 8;
2180   pcbddc->coarse_eqs_per_proc       = 1;
2181   pcbddc->benign_compute_correction = PETSC_TRUE;
2182   pcbddc->nedfield                  = -1;
2183   pcbddc->nedglobal                 = PETSC_TRUE;
2184   pcbddc->graphmaxcount             = PETSC_MAX_INT;
2185   pcbddc->sub_schurs_layers         = -1;
2186   pcbddc->ksp_D                     = kspD;
2187   pcbddc->ksp_R                     = kspR;
2188   pcbddc->coarse_ksp                = kspC;
2189   PetscFunctionReturn(0);
2190 }
2191 
2192 PetscErrorCode PCDestroy_BDDC(PC pc)
2193 {
2194   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
2195 
2196   PetscFunctionBegin;
2197   PetscCall(PCReset_BDDC(pc));
2198   PetscCall(KSPDestroy(&pcbddc->ksp_D));
2199   PetscCall(KSPDestroy(&pcbddc->ksp_R));
2200   PetscCall(KSPDestroy(&pcbddc->coarse_ksp));
2201   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDiscreteGradient_C",NULL));
2202   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDivergenceMat_C",NULL));
2203   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetChangeOfBasisMat_C",NULL));
2204   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",NULL));
2205   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesIS_C",NULL));
2206   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetPrimalVerticesLocalIS_C",NULL));
2207   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetPrimalVerticesIS_C",NULL));
2208   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",NULL));
2209   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",NULL));
2210   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",NULL));
2211   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",NULL));
2212   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",NULL));
2213   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",NULL));
2214   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",NULL));
2215   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",NULL));
2216   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",NULL));
2217   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",NULL));
2218   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",NULL));
2219   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",NULL));
2220   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",NULL));
2221   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",NULL));
2222   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",NULL));
2223   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",NULL));
2224   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",NULL));
2225   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",NULL));
2226   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCPreSolveChangeRHS_C",NULL));
2227   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",NULL));
2228   PetscCall(PetscFree(pc->data));
2229   PetscFunctionReturn(0);
2230 }
2231 
2232 static PetscErrorCode PCSetCoordinates_BDDC(PC pc, PetscInt dim, PetscInt nloc, PetscReal *coords)
2233 {
2234   PC_BDDC        *pcbddc = (PC_BDDC*)pc->data;
2235   PCBDDCGraph    mat_graph = pcbddc->mat_graph;
2236 
2237   PetscFunctionBegin;
2238   PetscCall(PetscFree(mat_graph->coords));
2239   PetscCall(PetscMalloc1(nloc*dim,&mat_graph->coords));
2240   PetscCall(PetscArraycpy(mat_graph->coords,coords,nloc*dim));
2241   mat_graph->cnloc = nloc;
2242   mat_graph->cdim  = dim;
2243   mat_graph->cloc  = PETSC_FALSE;
2244   /* flg setup */
2245   pcbddc->recompute_topography = PETSC_TRUE;
2246   pcbddc->corner_selected = PETSC_FALSE;
2247   PetscFunctionReturn(0);
2248 }
2249 
2250 static PetscErrorCode PCPreSolveChangeRHS_BDDC(PC pc, PetscBool* change)
2251 {
2252   PetscFunctionBegin;
2253   *change = PETSC_TRUE;
2254   PetscFunctionReturn(0);
2255 }
2256 
2257 static PetscErrorCode PCBDDCMatFETIDPGetRHS_BDDC(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
2258 {
2259   FETIDPMat_ctx  mat_ctx;
2260   Vec            work;
2261   PC_IS*         pcis;
2262   PC_BDDC*       pcbddc;
2263 
2264   PetscFunctionBegin;
2265   PetscCall(MatShellGetContext(fetidp_mat,&mat_ctx));
2266   pcis = (PC_IS*)mat_ctx->pc->data;
2267   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
2268 
2269   PetscCall(VecSet(fetidp_flux_rhs,0.0));
2270   /* copy rhs since we may change it during PCPreSolve_BDDC */
2271   if (!pcbddc->original_rhs) {
2272     PetscCall(VecDuplicate(pcis->vec1_global,&pcbddc->original_rhs));
2273   }
2274   if (mat_ctx->rhs_flip) {
2275     PetscCall(VecPointwiseMult(pcbddc->original_rhs,standard_rhs,mat_ctx->rhs_flip));
2276   } else {
2277     PetscCall(VecCopy(standard_rhs,pcbddc->original_rhs));
2278   }
2279   if (mat_ctx->g2g_p) {
2280     /* interface pressure rhs */
2281     PetscCall(VecScatterBegin(mat_ctx->g2g_p,fetidp_flux_rhs,pcbddc->original_rhs,INSERT_VALUES,SCATTER_REVERSE));
2282     PetscCall(VecScatterEnd(mat_ctx->g2g_p,fetidp_flux_rhs,pcbddc->original_rhs,INSERT_VALUES,SCATTER_REVERSE));
2283     PetscCall(VecScatterBegin(mat_ctx->g2g_p,standard_rhs,fetidp_flux_rhs,INSERT_VALUES,SCATTER_FORWARD));
2284     PetscCall(VecScatterEnd(mat_ctx->g2g_p,standard_rhs,fetidp_flux_rhs,INSERT_VALUES,SCATTER_FORWARD));
2285     if (!mat_ctx->rhs_flip) {
2286       PetscCall(VecScale(fetidp_flux_rhs,-1.));
2287     }
2288   }
2289   /*
2290      change of basis for physical rhs if needed
2291      It also changes the rhs in case of dirichlet boundaries
2292   */
2293   PetscCall(PCPreSolve_BDDC(mat_ctx->pc,NULL,pcbddc->original_rhs,NULL));
2294   if (pcbddc->ChangeOfBasisMatrix) {
2295     PetscCall(MatMultTranspose(pcbddc->ChangeOfBasisMatrix,pcbddc->original_rhs,pcbddc->work_change));
2296     work = pcbddc->work_change;
2297    } else {
2298     work = pcbddc->original_rhs;
2299   }
2300   /* store vectors for computation of fetidp final solution */
2301   PetscCall(VecScatterBegin(pcis->global_to_D,work,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD));
2302   PetscCall(VecScatterEnd(pcis->global_to_D,work,mat_ctx->temp_solution_D,INSERT_VALUES,SCATTER_FORWARD));
2303   /* scale rhs since it should be unassembled */
2304   /* TODO use counter scaling? (also below) */
2305   PetscCall(VecScatterBegin(pcis->global_to_B,work,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD));
2306   PetscCall(VecScatterEnd(pcis->global_to_B,work,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD));
2307   /* Apply partition of unity */
2308   PetscCall(VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B));
2309   /* PetscCall(PCBDDCScalingRestriction(mat_ctx->pc,work,mat_ctx->temp_solution_B)); */
2310   if (!pcbddc->switch_static) {
2311     /* compute partially subassembled Schur complement right-hand side */
2312     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],mat_ctx->pc,0,0,0));
2313     PetscCall(KSPSolve(pcbddc->ksp_D,mat_ctx->temp_solution_D,pcis->vec1_D));
2314     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],mat_ctx->pc,0,0,0));
2315     /* Cannot propagate up error in KSPSolve() because there is no access to the PC */
2316     PetscCall(MatMult(pcis->A_BI,pcis->vec1_D,pcis->vec1_B));
2317     PetscCall(VecAXPY(mat_ctx->temp_solution_B,-1.0,pcis->vec1_B));
2318     PetscCall(VecSet(work,0.0));
2319     PetscCall(VecScatterBegin(pcis->global_to_B,mat_ctx->temp_solution_B,work,ADD_VALUES,SCATTER_REVERSE));
2320     PetscCall(VecScatterEnd(pcis->global_to_B,mat_ctx->temp_solution_B,work,ADD_VALUES,SCATTER_REVERSE));
2321     /* PetscCall(PCBDDCScalingRestriction(mat_ctx->pc,work,mat_ctx->temp_solution_B)); */
2322     PetscCall(VecScatterBegin(pcis->global_to_B,work,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD));
2323     PetscCall(VecScatterEnd(pcis->global_to_B,work,mat_ctx->temp_solution_B,INSERT_VALUES,SCATTER_FORWARD));
2324     PetscCall(VecPointwiseMult(mat_ctx->temp_solution_B,pcis->D,mat_ctx->temp_solution_B));
2325   }
2326   /* BDDC rhs */
2327   PetscCall(VecCopy(mat_ctx->temp_solution_B,pcis->vec1_B));
2328   if (pcbddc->switch_static) PetscCall(VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D));
2329   /* apply BDDC */
2330   PetscCall(PetscArrayzero(pcbddc->benign_p0,pcbddc->benign_n));
2331   PetscCall(PCBDDCApplyInterfacePreconditioner(mat_ctx->pc,PETSC_FALSE));
2332   PetscCall(PetscArrayzero(pcbddc->benign_p0,pcbddc->benign_n));
2333 
2334   /* Application of B_delta and assembling of rhs for fetidp fluxes */
2335   PetscCall(MatMult(mat_ctx->B_delta,pcis->vec1_B,mat_ctx->lambda_local));
2336   PetscCall(VecScatterBegin(mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD));
2337   PetscCall(VecScatterEnd(mat_ctx->l2g_lambda,mat_ctx->lambda_local,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD));
2338   /* Add contribution to interface pressures */
2339   if (mat_ctx->l2g_p) {
2340     PetscCall(MatMult(mat_ctx->B_BB,pcis->vec1_B,mat_ctx->vP));
2341     if (pcbddc->switch_static) PetscCall(MatMultAdd(mat_ctx->B_BI,pcis->vec1_D,mat_ctx->vP,mat_ctx->vP));
2342     PetscCall(VecScatterBegin(mat_ctx->l2g_p,mat_ctx->vP,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD));
2343     PetscCall(VecScatterEnd(mat_ctx->l2g_p,mat_ctx->vP,fetidp_flux_rhs,ADD_VALUES,SCATTER_FORWARD));
2344   }
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 /*@
2349  PCBDDCMatFETIDPGetRHS - Compute the right-hand side for FETI-DP linear system using the physical right-hand side
2350 
2351    Collective
2352 
2353    Input Parameters:
2354 +  fetidp_mat      - the FETI-DP matrix object obtained by a call to PCBDDCCreateFETIDPOperators
2355 -  standard_rhs    - the right-hand side of the original linear system
2356 
2357    Output Parameters:
2358 .  fetidp_flux_rhs - the right-hand side for the FETI-DP linear system
2359 
2360    Level: developer
2361 
2362    Notes:
2363 
2364 .seealso: `PCBDDC`, `PCBDDCCreateFETIDPOperators()`, `PCBDDCMatFETIDPGetSolution()`
2365 @*/
2366 PetscErrorCode PCBDDCMatFETIDPGetRHS(Mat fetidp_mat, Vec standard_rhs, Vec fetidp_flux_rhs)
2367 {
2368   FETIDPMat_ctx  mat_ctx;
2369 
2370   PetscFunctionBegin;
2371   PetscValidHeaderSpecific(fetidp_mat,MAT_CLASSID,1);
2372   PetscValidHeaderSpecific(standard_rhs,VEC_CLASSID,2);
2373   PetscValidHeaderSpecific(fetidp_flux_rhs,VEC_CLASSID,3);
2374   PetscCall(MatShellGetContext(fetidp_mat,&mat_ctx));
2375   PetscUseMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetRHS_C",(Mat,Vec,Vec),(fetidp_mat,standard_rhs,fetidp_flux_rhs));
2376   PetscFunctionReturn(0);
2377 }
2378 
2379 static PetscErrorCode PCBDDCMatFETIDPGetSolution_BDDC(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
2380 {
2381   FETIDPMat_ctx  mat_ctx;
2382   PC_IS*         pcis;
2383   PC_BDDC*       pcbddc;
2384   Vec            work;
2385 
2386   PetscFunctionBegin;
2387   PetscCall(MatShellGetContext(fetidp_mat,&mat_ctx));
2388   pcis = (PC_IS*)mat_ctx->pc->data;
2389   pcbddc = (PC_BDDC*)mat_ctx->pc->data;
2390 
2391   /* apply B_delta^T */
2392   PetscCall(VecSet(pcis->vec1_B,0.));
2393   PetscCall(VecScatterBegin(mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
2394   PetscCall(VecScatterEnd(mat_ctx->l2g_lambda,fetidp_flux_sol,mat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE));
2395   PetscCall(MatMultTranspose(mat_ctx->B_delta,mat_ctx->lambda_local,pcis->vec1_B));
2396   if (mat_ctx->l2g_p) {
2397     PetscCall(VecScatterBegin(mat_ctx->l2g_p,fetidp_flux_sol,mat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE));
2398     PetscCall(VecScatterEnd(mat_ctx->l2g_p,fetidp_flux_sol,mat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE));
2399     PetscCall(MatMultAdd(mat_ctx->Bt_BB,mat_ctx->vP,pcis->vec1_B,pcis->vec1_B));
2400   }
2401 
2402   /* compute rhs for BDDC application */
2403   PetscCall(VecAYPX(pcis->vec1_B,-1.0,mat_ctx->temp_solution_B));
2404   if (pcbddc->switch_static) {
2405     PetscCall(VecCopy(mat_ctx->temp_solution_D,pcis->vec1_D));
2406     if (mat_ctx->l2g_p) {
2407       PetscCall(VecScale(mat_ctx->vP,-1.));
2408       PetscCall(MatMultAdd(mat_ctx->Bt_BI,mat_ctx->vP,pcis->vec1_D,pcis->vec1_D));
2409     }
2410   }
2411 
2412   /* apply BDDC */
2413   PetscCall(PetscArrayzero(pcbddc->benign_p0,pcbddc->benign_n));
2414   PetscCall(PCBDDCApplyInterfacePreconditioner(mat_ctx->pc,PETSC_FALSE));
2415 
2416   /* put values into global vector */
2417   if (pcbddc->ChangeOfBasisMatrix) work = pcbddc->work_change;
2418   else work = standard_sol;
2419   PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_B,work,INSERT_VALUES,SCATTER_REVERSE));
2420   PetscCall(VecScatterEnd(pcis->global_to_B,pcis->vec1_B,work,INSERT_VALUES,SCATTER_REVERSE));
2421   if (!pcbddc->switch_static) {
2422     /* compute values into the interior if solved for the partially subassembled Schur complement */
2423     PetscCall(MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec1_D));
2424     PetscCall(VecAYPX(pcis->vec1_D,-1.0,mat_ctx->temp_solution_D));
2425     PetscCall(PetscLogEventBegin(PC_BDDC_Solves[pcbddc->current_level][0],mat_ctx->pc,0,0,0));
2426     PetscCall(KSPSolve(pcbddc->ksp_D,pcis->vec1_D,pcis->vec1_D));
2427     PetscCall(PetscLogEventEnd(PC_BDDC_Solves[pcbddc->current_level][0],mat_ctx->pc,0,0,0));
2428     /* Cannot propagate up error in KSPSolve() because there is no access to the PC */
2429   }
2430 
2431   PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec1_D,work,INSERT_VALUES,SCATTER_REVERSE));
2432   PetscCall(VecScatterEnd(pcis->global_to_D,pcis->vec1_D,work,INSERT_VALUES,SCATTER_REVERSE));
2433   /* add p0 solution to final solution */
2434   PetscCall(PCBDDCBenignGetOrSetP0(mat_ctx->pc,work,PETSC_FALSE));
2435   if (pcbddc->ChangeOfBasisMatrix) PetscCall(MatMult(pcbddc->ChangeOfBasisMatrix,work,standard_sol));
2436   PetscCall(PCPostSolve_BDDC(mat_ctx->pc,NULL,NULL,standard_sol));
2437   if (mat_ctx->g2g_p) {
2438     PetscCall(VecScatterBegin(mat_ctx->g2g_p,fetidp_flux_sol,standard_sol,INSERT_VALUES,SCATTER_REVERSE));
2439     PetscCall(VecScatterEnd(mat_ctx->g2g_p,fetidp_flux_sol,standard_sol,INSERT_VALUES,SCATTER_REVERSE));
2440   }
2441   PetscFunctionReturn(0);
2442 }
2443 
2444 static PetscErrorCode PCView_BDDCIPC(PC pc, PetscViewer viewer)
2445 {
2446   BDDCIPC_ctx    bddcipc_ctx;
2447   PetscBool      isascii;
2448 
2449   PetscFunctionBegin;
2450   PetscCall(PCShellGetContext(pc,&bddcipc_ctx));
2451   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
2452   if (isascii) {
2453     PetscCall(PetscViewerASCIIPrintf(viewer,"BDDC interface preconditioner\n"));
2454   }
2455   PetscCall(PetscViewerASCIIPushTab(viewer));
2456   PetscCall(PCView(bddcipc_ctx->bddc,viewer));
2457   PetscCall(PetscViewerASCIIPopTab(viewer));
2458   PetscFunctionReturn(0);
2459 }
2460 
2461 static PetscErrorCode PCSetUp_BDDCIPC(PC pc)
2462 {
2463   BDDCIPC_ctx    bddcipc_ctx;
2464   PetscBool      isbddc;
2465   Vec            vv;
2466   IS             is;
2467   PC_IS          *pcis;
2468 
2469   PetscFunctionBegin;
2470   PetscCall(PCShellGetContext(pc,&bddcipc_ctx));
2471   PetscCall(PetscObjectTypeCompare((PetscObject)bddcipc_ctx->bddc,PCBDDC,&isbddc));
2472   PetscCheck(isbddc,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Invalid type %s. Must be of type bddc",((PetscObject)bddcipc_ctx->bddc)->type_name);
2473   PetscCall(PCSetUp(bddcipc_ctx->bddc));
2474 
2475   /* create interface scatter */
2476   pcis = (PC_IS*)(bddcipc_ctx->bddc->data);
2477   PetscCall(VecScatterDestroy(&bddcipc_ctx->g2l));
2478   PetscCall(MatCreateVecs(pc->pmat,&vv,NULL));
2479   PetscCall(ISRenumber(pcis->is_B_global,NULL,NULL,&is));
2480   PetscCall(VecScatterCreate(vv,is,pcis->vec1_B,NULL,&bddcipc_ctx->g2l));
2481   PetscCall(ISDestroy(&is));
2482   PetscCall(VecDestroy(&vv));
2483   PetscFunctionReturn(0);
2484 }
2485 
2486 static PetscErrorCode PCApply_BDDCIPC(PC pc, Vec r, Vec x)
2487 {
2488   BDDCIPC_ctx    bddcipc_ctx;
2489   PC_IS          *pcis;
2490   VecScatter     tmps;
2491 
2492   PetscFunctionBegin;
2493   PetscCall(PCShellGetContext(pc,&bddcipc_ctx));
2494   pcis = (PC_IS*)(bddcipc_ctx->bddc->data);
2495   tmps = pcis->global_to_B;
2496   pcis->global_to_B = bddcipc_ctx->g2l;
2497   PetscCall(PCBDDCScalingRestriction(bddcipc_ctx->bddc,r,pcis->vec1_B));
2498   PetscCall(PCBDDCApplyInterfacePreconditioner(bddcipc_ctx->bddc,PETSC_FALSE));
2499   PetscCall(PCBDDCScalingExtension(bddcipc_ctx->bddc,pcis->vec1_B,x));
2500   pcis->global_to_B = tmps;
2501   PetscFunctionReturn(0);
2502 }
2503 
2504 static PetscErrorCode PCApplyTranspose_BDDCIPC(PC pc, Vec r, Vec x)
2505 {
2506   BDDCIPC_ctx    bddcipc_ctx;
2507   PC_IS          *pcis;
2508   VecScatter     tmps;
2509 
2510   PetscFunctionBegin;
2511   PetscCall(PCShellGetContext(pc,&bddcipc_ctx));
2512   pcis = (PC_IS*)(bddcipc_ctx->bddc->data);
2513   tmps = pcis->global_to_B;
2514   pcis->global_to_B = bddcipc_ctx->g2l;
2515   PetscCall(PCBDDCScalingRestriction(bddcipc_ctx->bddc,r,pcis->vec1_B));
2516   PetscCall(PCBDDCApplyInterfacePreconditioner(bddcipc_ctx->bddc,PETSC_TRUE));
2517   PetscCall(PCBDDCScalingExtension(bddcipc_ctx->bddc,pcis->vec1_B,x));
2518   pcis->global_to_B = tmps;
2519   PetscFunctionReturn(0);
2520 }
2521 
2522 static PetscErrorCode PCDestroy_BDDCIPC(PC pc)
2523 {
2524   BDDCIPC_ctx    bddcipc_ctx;
2525 
2526   PetscFunctionBegin;
2527   PetscCall(PCShellGetContext(pc,&bddcipc_ctx));
2528   PetscCall(PCDestroy(&bddcipc_ctx->bddc));
2529   PetscCall(VecScatterDestroy(&bddcipc_ctx->g2l));
2530   PetscCall(PetscFree(bddcipc_ctx));
2531   PetscFunctionReturn(0);
2532 }
2533 
2534 /*@
2535  PCBDDCMatFETIDPGetSolution - Compute the physical solution using the solution of the FETI-DP linear system
2536 
2537    Collective
2538 
2539    Input Parameters:
2540 +  fetidp_mat      - the FETI-DP matrix obtained by a call to PCBDDCCreateFETIDPOperators
2541 -  fetidp_flux_sol - the solution of the FETI-DP linear system
2542 
2543    Output Parameters:
2544 .  standard_sol    - the solution defined on the physical domain
2545 
2546    Level: developer
2547 
2548    Notes:
2549 
2550 .seealso: `PCBDDC`, `PCBDDCCreateFETIDPOperators()`, `PCBDDCMatFETIDPGetRHS()`
2551 @*/
2552 PetscErrorCode PCBDDCMatFETIDPGetSolution(Mat fetidp_mat, Vec fetidp_flux_sol, Vec standard_sol)
2553 {
2554   FETIDPMat_ctx  mat_ctx;
2555 
2556   PetscFunctionBegin;
2557   PetscValidHeaderSpecific(fetidp_mat,MAT_CLASSID,1);
2558   PetscValidHeaderSpecific(fetidp_flux_sol,VEC_CLASSID,2);
2559   PetscValidHeaderSpecific(standard_sol,VEC_CLASSID,3);
2560   PetscCall(MatShellGetContext(fetidp_mat,&mat_ctx));
2561   PetscUseMethod(mat_ctx->pc,"PCBDDCMatFETIDPGetSolution_C",(Mat,Vec,Vec),(fetidp_mat,fetidp_flux_sol,standard_sol));
2562   PetscFunctionReturn(0);
2563 }
2564 
2565 static PetscErrorCode PCBDDCCreateFETIDPOperators_BDDC(PC pc, PetscBool fully_redundant, const char* prefix, Mat *fetidp_mat, PC *fetidp_pc)
2566 {
2567 
2568   FETIDPMat_ctx  fetidpmat_ctx;
2569   Mat            newmat;
2570   FETIDPPC_ctx   fetidppc_ctx;
2571   PC             newpc;
2572   MPI_Comm       comm;
2573 
2574   PetscFunctionBegin;
2575   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
2576   /* FETI-DP matrix */
2577   PetscCall(PCBDDCCreateFETIDPMatContext(pc,&fetidpmat_ctx));
2578   fetidpmat_ctx->fully_redundant = fully_redundant;
2579   PetscCall(PCBDDCSetupFETIDPMatContext(fetidpmat_ctx));
2580   PetscCall(MatCreateShell(comm,fetidpmat_ctx->n,fetidpmat_ctx->n,fetidpmat_ctx->N,fetidpmat_ctx->N,fetidpmat_ctx,&newmat));
2581   PetscCall(PetscObjectSetName((PetscObject)newmat,!fetidpmat_ctx->l2g_lambda_only ? "F" : "G"));
2582   PetscCall(MatShellSetOperation(newmat,MATOP_MULT,(void (*)(void))FETIDPMatMult));
2583   PetscCall(MatShellSetOperation(newmat,MATOP_MULT_TRANSPOSE,(void (*)(void))FETIDPMatMultTranspose));
2584   PetscCall(MatShellSetOperation(newmat,MATOP_DESTROY,(void (*)(void))PCBDDCDestroyFETIDPMat));
2585   /* propagate MatOptions */
2586   {
2587     PC_BDDC   *pcbddc = (PC_BDDC*)fetidpmat_ctx->pc->data;
2588     PetscBool isset,issym;
2589 
2590     PetscCall(MatIsSymmetricKnown(pc->mat,&isset,&issym));
2591     if ((isset && issym) || pcbddc->symmetric_primal) PetscCall(MatSetOption(newmat,MAT_SYMMETRIC,PETSC_TRUE));
2592   }
2593   PetscCall(MatSetOptionsPrefix(newmat,prefix));
2594   PetscCall(MatAppendOptionsPrefix(newmat,"fetidp_"));
2595   PetscCall(MatSetUp(newmat));
2596   /* FETI-DP preconditioner */
2597   PetscCall(PCBDDCCreateFETIDPPCContext(pc,&fetidppc_ctx));
2598   PetscCall(PCBDDCSetupFETIDPPCContext(newmat,fetidppc_ctx));
2599   PetscCall(PCCreate(comm,&newpc));
2600   PetscCall(PCSetOperators(newpc,newmat,newmat));
2601   PetscCall(PCSetOptionsPrefix(newpc,prefix));
2602   PetscCall(PCAppendOptionsPrefix(newpc,"fetidp_"));
2603   PetscCall(PCSetErrorIfFailure(newpc,pc->erroriffailure));
2604   if (!fetidpmat_ctx->l2g_lambda_only) { /* standard FETI-DP */
2605     PetscCall(PCSetType(newpc,PCSHELL));
2606     PetscCall(PCShellSetName(newpc,"FETI-DP multipliers"));
2607     PetscCall(PCShellSetContext(newpc,fetidppc_ctx));
2608     PetscCall(PCShellSetApply(newpc,FETIDPPCApply));
2609     PetscCall(PCShellSetApplyTranspose(newpc,FETIDPPCApplyTranspose));
2610     PetscCall(PCShellSetView(newpc,FETIDPPCView));
2611     PetscCall(PCShellSetDestroy(newpc,PCBDDCDestroyFETIDPPC));
2612   } else { /* saddle-point FETI-DP */
2613     Mat       M;
2614     PetscInt  psize;
2615     PetscBool fake = PETSC_FALSE, isfieldsplit;
2616 
2617     PetscCall(ISViewFromOptions(fetidpmat_ctx->lagrange,NULL,"-lag_view"));
2618     PetscCall(ISViewFromOptions(fetidpmat_ctx->pressure,NULL,"-press_view"));
2619     PetscCall(PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_PPmat",(PetscObject*)&M));
2620     PetscCall(PCSetType(newpc,PCFIELDSPLIT));
2621     PetscCall(PCFieldSplitSetIS(newpc,"lag",fetidpmat_ctx->lagrange));
2622     PetscCall(PCFieldSplitSetIS(newpc,"p",fetidpmat_ctx->pressure));
2623     PetscCall(PCFieldSplitSetType(newpc,PC_COMPOSITE_SCHUR));
2624     PetscCall(PCFieldSplitSetSchurFactType(newpc,PC_FIELDSPLIT_SCHUR_FACT_DIAG));
2625     PetscCall(ISGetSize(fetidpmat_ctx->pressure,&psize));
2626     if (psize != M->rmap->N) {
2627       Mat      M2;
2628       PetscInt lpsize;
2629 
2630       fake = PETSC_TRUE;
2631       PetscCall(ISGetLocalSize(fetidpmat_ctx->pressure,&lpsize));
2632       PetscCall(MatCreate(comm,&M2));
2633       PetscCall(MatSetType(M2,MATAIJ));
2634       PetscCall(MatSetSizes(M2,lpsize,lpsize,psize,psize));
2635       PetscCall(MatSetUp(M2));
2636       PetscCall(MatAssemblyBegin(M2,MAT_FINAL_ASSEMBLY));
2637       PetscCall(MatAssemblyEnd(M2,MAT_FINAL_ASSEMBLY));
2638       PetscCall(PCFieldSplitSetSchurPre(newpc,PC_FIELDSPLIT_SCHUR_PRE_USER,M2));
2639       PetscCall(MatDestroy(&M2));
2640     } else {
2641       PetscCall(PCFieldSplitSetSchurPre(newpc,PC_FIELDSPLIT_SCHUR_PRE_USER,M));
2642     }
2643     PetscCall(PCFieldSplitSetSchurScale(newpc,1.0));
2644 
2645     /* we need to setfromoptions and setup here to access the blocks */
2646     PetscCall(PCSetFromOptions(newpc));
2647     PetscCall(PCSetUp(newpc));
2648 
2649     /* user may have changed the type (e.g. -fetidp_pc_type none) */
2650     PetscCall(PetscObjectTypeCompare((PetscObject)newpc,PCFIELDSPLIT,&isfieldsplit));
2651     if (isfieldsplit) {
2652       KSP       *ksps;
2653       PC        ppc,lagpc;
2654       PetscInt  nn;
2655       PetscBool ismatis,matisok = PETSC_FALSE,check = PETSC_FALSE;
2656 
2657       /* set the solver for the (0,0) block */
2658       PetscCall(PCFieldSplitSchurGetSubKSP(newpc,&nn,&ksps));
2659       if (!nn) { /* not of type PC_COMPOSITE_SCHUR */
2660         PetscCall(PCFieldSplitGetSubKSP(newpc,&nn,&ksps));
2661         if (!fake) { /* pass pmat to the pressure solver */
2662           Mat F;
2663 
2664           PetscCall(KSPGetOperators(ksps[1],&F,NULL));
2665           PetscCall(KSPSetOperators(ksps[1],F,M));
2666         }
2667       } else {
2668         PetscBool issym,isset;
2669         Mat       S;
2670 
2671         PetscCall(PCFieldSplitSchurGetS(newpc,&S));
2672         PetscCall(MatIsSymmetricKnown(newmat,&isset,&issym));
2673         if (isset) PetscCall(MatSetOption(S,MAT_SYMMETRIC,issym));
2674       }
2675       PetscCall(KSPGetPC(ksps[0],&lagpc));
2676       PetscCall(PCSetType(lagpc,PCSHELL));
2677       PetscCall(PCShellSetName(lagpc,"FETI-DP multipliers"));
2678       PetscCall(PCShellSetContext(lagpc,fetidppc_ctx));
2679       PetscCall(PCShellSetApply(lagpc,FETIDPPCApply));
2680       PetscCall(PCShellSetApplyTranspose(lagpc,FETIDPPCApplyTranspose));
2681       PetscCall(PCShellSetView(lagpc,FETIDPPCView));
2682       PetscCall(PCShellSetDestroy(lagpc,PCBDDCDestroyFETIDPPC));
2683 
2684       /* Olof's idea: interface Schur complement preconditioner for the mass matrix */
2685       PetscCall(KSPGetPC(ksps[1],&ppc));
2686       if (fake) {
2687         BDDCIPC_ctx    bddcipc_ctx;
2688         PetscContainer c;
2689 
2690         matisok = PETSC_TRUE;
2691 
2692         /* create inner BDDC solver */
2693         PetscCall(PetscNew(&bddcipc_ctx));
2694         PetscCall(PCCreate(comm,&bddcipc_ctx->bddc));
2695         PetscCall(PCSetType(bddcipc_ctx->bddc,PCBDDC));
2696         PetscCall(PCSetOperators(bddcipc_ctx->bddc,M,M));
2697         PetscCall(PetscObjectQuery((PetscObject)pc,"__KSPFETIDP_pCSR",(PetscObject*)&c));
2698         PetscCall(PetscObjectTypeCompare((PetscObject)M,MATIS,&ismatis));
2699         if (c && ismatis) {
2700           Mat      lM;
2701           PetscInt *csr,n;
2702 
2703           PetscCall(MatISGetLocalMat(M,&lM));
2704           PetscCall(MatGetSize(lM,&n,NULL));
2705           PetscCall(PetscContainerGetPointer(c,(void**)&csr));
2706           PetscCall(PCBDDCSetLocalAdjacencyGraph(bddcipc_ctx->bddc,n,csr,csr + (n + 1),PETSC_COPY_VALUES));
2707           PetscCall(MatISRestoreLocalMat(M,&lM));
2708         }
2709         PetscCall(PCSetOptionsPrefix(bddcipc_ctx->bddc,((PetscObject)ksps[1])->prefix));
2710         PetscCall(PCSetErrorIfFailure(bddcipc_ctx->bddc,pc->erroriffailure));
2711         PetscCall(PCSetFromOptions(bddcipc_ctx->bddc));
2712 
2713         /* wrap the interface application */
2714         PetscCall(PCSetType(ppc,PCSHELL));
2715         PetscCall(PCShellSetName(ppc,"FETI-DP pressure"));
2716         PetscCall(PCShellSetContext(ppc,bddcipc_ctx));
2717         PetscCall(PCShellSetSetUp(ppc,PCSetUp_BDDCIPC));
2718         PetscCall(PCShellSetApply(ppc,PCApply_BDDCIPC));
2719         PetscCall(PCShellSetApplyTranspose(ppc,PCApplyTranspose_BDDCIPC));
2720         PetscCall(PCShellSetView(ppc,PCView_BDDCIPC));
2721         PetscCall(PCShellSetDestroy(ppc,PCDestroy_BDDCIPC));
2722       }
2723 
2724       /* determine if we need to assemble M to construct a preconditioner */
2725       if (!matisok) {
2726         PetscCall(PetscObjectTypeCompare((PetscObject)M,MATIS,&ismatis));
2727         PetscCall(PetscObjectTypeCompareAny((PetscObject)ppc,&matisok,PCBDDC,PCJACOBI,PCNONE,PCMG,""));
2728         if (ismatis && !matisok) {
2729           PetscCall(MatConvert(M,MATAIJ,MAT_INPLACE_MATRIX,&M));
2730         }
2731       }
2732 
2733       /* run the subproblems to check convergence */
2734       PetscCall(PetscOptionsGetBool(NULL,((PetscObject)newmat)->prefix,"-check_saddlepoint",&check,NULL));
2735       if (check) {
2736         PetscInt i;
2737 
2738         for (i=0;i<nn;i++) {
2739           KSP       kspC;
2740           PC        pc;
2741           Mat       F,pF;
2742           Vec       x,y;
2743           PetscBool isschur,prec = PETSC_TRUE;
2744 
2745           PetscCall(KSPCreate(PetscObjectComm((PetscObject)ksps[i]),&kspC));
2746           PetscCall(KSPSetOptionsPrefix(kspC,((PetscObject)ksps[i])->prefix));
2747           PetscCall(KSPAppendOptionsPrefix(kspC,"check_"));
2748           PetscCall(KSPGetOperators(ksps[i],&F,&pF));
2749           PetscCall(PetscObjectTypeCompare((PetscObject)F,MATSCHURCOMPLEMENT,&isschur));
2750           if (isschur) {
2751             KSP  kspS,kspS2;
2752             Mat  A00,pA00,A10,A01,A11;
2753             char prefix[256];
2754 
2755             PetscCall(MatSchurComplementGetKSP(F,&kspS));
2756             PetscCall(MatSchurComplementGetSubMatrices(F,&A00,&pA00,&A01,&A10,&A11));
2757             PetscCall(MatCreateSchurComplement(A00,pA00,A01,A10,A11,&F));
2758             PetscCall(MatSchurComplementGetKSP(F,&kspS2));
2759             PetscCall(PetscSNPrintf(prefix,sizeof(prefix),"%sschur_",((PetscObject)kspC)->prefix));
2760             PetscCall(KSPSetOptionsPrefix(kspS2,prefix));
2761             PetscCall(KSPGetPC(kspS2,&pc));
2762             PetscCall(PCSetType(pc,PCKSP));
2763             PetscCall(PCKSPSetKSP(pc,kspS));
2764             PetscCall(KSPSetFromOptions(kspS2));
2765             PetscCall(KSPGetPC(kspS2,&pc));
2766             PetscCall(PCSetUseAmat(pc,PETSC_TRUE));
2767           } else {
2768             PetscCall(PetscObjectReference((PetscObject)F));
2769           }
2770           PetscCall(KSPSetFromOptions(kspC));
2771           PetscCall(PetscOptionsGetBool(NULL,((PetscObject)kspC)->prefix,"-preconditioned",&prec,NULL));
2772           if (prec)  {
2773             PetscCall(KSPGetPC(ksps[i],&pc));
2774             PetscCall(KSPSetPC(kspC,pc));
2775           }
2776           PetscCall(KSPSetOperators(kspC,F,pF));
2777           PetscCall(MatCreateVecs(F,&x,&y));
2778           PetscCall(VecSetRandom(x,NULL));
2779           PetscCall(MatMult(F,x,y));
2780           PetscCall(KSPSolve(kspC,y,x));
2781           PetscCall(KSPCheckSolve(kspC,pc,x));
2782           PetscCall(KSPDestroy(&kspC));
2783           PetscCall(MatDestroy(&F));
2784           PetscCall(VecDestroy(&x));
2785           PetscCall(VecDestroy(&y));
2786         }
2787       }
2788       PetscCall(PetscFree(ksps));
2789     }
2790   }
2791   /* return pointers for objects created */
2792   *fetidp_mat = newmat;
2793   *fetidp_pc  = newpc;
2794   PetscFunctionReturn(0);
2795 }
2796 
2797 /*@C
2798  PCBDDCCreateFETIDPOperators - Create FETI-DP operators
2799 
2800    Collective
2801 
2802    Input Parameters:
2803 +  pc - the BDDC preconditioning context (setup should have been called before)
2804 .  fully_redundant - true for a fully redundant set of Lagrange multipliers
2805 -  prefix - optional options database prefix for the objects to be created (can be NULL)
2806 
2807    Output Parameters:
2808 +  fetidp_mat - shell FETI-DP matrix object
2809 -  fetidp_pc  - shell Dirichlet preconditioner for FETI-DP matrix
2810 
2811    Level: developer
2812 
2813    Notes:
2814      Currently the only operations provided for FETI-DP matrix are MatMult and MatMultTranspose
2815 
2816 .seealso: `PCBDDC`, `PCBDDCMatFETIDPGetRHS()`, `PCBDDCMatFETIDPGetSolution()`
2817 @*/
2818 PetscErrorCode PCBDDCCreateFETIDPOperators(PC pc, PetscBool fully_redundant, const char *prefix, Mat *fetidp_mat, PC *fetidp_pc)
2819 {
2820   PetscFunctionBegin;
2821   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2822   if (pc->setupcalled) {
2823     PetscUseMethod(pc,"PCBDDCCreateFETIDPOperators_C",(PC,PetscBool,const char*,Mat*,PC*),(pc,fully_redundant,prefix,fetidp_mat,fetidp_pc));
2824   } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"You must call PCSetup_BDDC() first");
2825   PetscFunctionReturn(0);
2826 }
2827 /* -------------------------------------------------------------------------- */
2828 /*MC
2829    PCBDDC - Balancing Domain Decomposition by Constraints.
2830 
2831    An implementation of the BDDC preconditioner based on the bibliography found below.
2832 
2833    The matrix to be preconditioned (Pmat) must be of type MATIS.
2834 
2835    Currently works with MATIS matrices with local matrices of type MATSEQAIJ, MATSEQBAIJ or MATSEQSBAIJ, either with real or complex numbers.
2836 
2837    It also works with unsymmetric and indefinite problems.
2838 
2839    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.
2840 
2841    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).
2842 
2843    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()
2844    Additional information on dofs can be provided by using PCBDDCSetDofsSplitting(), PCBDDCSetDirichletBoundaries(), PCBDDCSetNeumannBoundaries(), and PCBDDCSetPrimalVerticesIS() and their local counterparts.
2845 
2846    Constraints can be customized by attaching a MatNullSpace object to the MATIS matrix via MatSetNearNullSpace(). Non-singular modes are retained via SVD.
2847 
2848    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.
2849    User defined change of basis can be passed to PCBDDC by using PCBDDCSetChangeOfBasisMat()
2850 
2851    The PETSc implementation also supports multilevel BDDC [3]. Coarse grids are partitioned using a MatPartitioning object.
2852 
2853    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.
2854 
2855    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.
2856 
2857    Options Database Keys (some of them, run with -help for a complete list):
2858 
2859 +    -pc_bddc_use_vertices <true> - use or not vertices in primal space
2860 .    -pc_bddc_use_edges <true> - use or not edges in primal space
2861 .    -pc_bddc_use_faces <false> - use or not faces in primal space
2862 .    -pc_bddc_symmetric <true> - symmetric computation of primal basis functions. Specify false for unsymmetric problems
2863 .    -pc_bddc_use_change_of_basis <false> - use change of basis approach (on edges only)
2864 .    -pc_bddc_use_change_on_faces <false> - use change of basis approach on faces if change of basis has been requested
2865 .    -pc_bddc_switch_static <false> - switches from M_2 (default) to M_3 operator (see reference article [1])
2866 .    -pc_bddc_levels <0> - maximum number of levels for multilevel
2867 .    -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)
2868 .    -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)
2869 .    -pc_bddc_use_deluxe_scaling <false> - use deluxe scaling
2870 .    -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)
2871 .    -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)
2872 -    -pc_bddc_check_level <0> - set verbosity level of debugging output
2873 
2874    Options for Dirichlet, Neumann or coarse solver can be set with
2875 .vb
2876       -pc_bddc_dirichlet_
2877       -pc_bddc_neumann_
2878       -pc_bddc_coarse_
2879 .ve
2880    e.g. -pc_bddc_dirichlet_ksp_type richardson -pc_bddc_dirichlet_pc_type gamg. PCBDDC uses by default KSPPREONLY and PCLU.
2881 
2882    When using a multilevel approach, solvers' options at the N-th level (N > 1) can be specified as
2883 .vb
2884       -pc_bddc_dirichlet_lN_
2885       -pc_bddc_neumann_lN_
2886       -pc_bddc_coarse_lN_
2887 .ve
2888    Note that level number ranges from the finest (0) to the coarsest (N).
2889    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.
2890 .vb
2891      -pc_bddc_coarse_pc_bddc_adaptive_threshold 5 -pc_bddc_coarse_l1_pc_bddc_redistribute 3
2892 .ve
2893    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
2894 
2895    References:
2896 +  * - C. R. Dohrmann. "An approximate BDDC preconditioner", Numerical Linear Algebra with Applications Volume 14, Issue 2, pages 149--168, March 2007
2897 .  * - 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
2898 .  * - J. Mandel, B. Sousedik, C. R. Dohrmann. "Multispace and Multilevel BDDC", Computing Volume 83, Issue 2--3, pages 55--85, November 2008
2899 -  * - 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
2900 
2901    Level: intermediate
2902 
2903    Developer Notes:
2904 
2905    Contributed by Stefano Zampini
2906 
2907 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `MATIS`
2908 M*/
2909 
2910 PETSC_EXTERN PetscErrorCode PCCreate_BDDC(PC pc)
2911 {
2912   PC_BDDC             *pcbddc;
2913 
2914   PetscFunctionBegin;
2915   PetscCall(PetscNewLog(pc,&pcbddc));
2916   pc->data = pcbddc;
2917 
2918   /* create PCIS data structure */
2919   PetscCall(PCISCreate(pc));
2920 
2921   /* create local graph structure */
2922   PetscCall(PCBDDCGraphCreate(&pcbddc->mat_graph));
2923 
2924   /* BDDC nonzero defaults */
2925   pcbddc->use_nnsp                  = PETSC_TRUE;
2926   pcbddc->use_local_adj             = PETSC_TRUE;
2927   pcbddc->use_vertices              = PETSC_TRUE;
2928   pcbddc->use_edges                 = PETSC_TRUE;
2929   pcbddc->symmetric_primal          = PETSC_TRUE;
2930   pcbddc->vertex_size               = 1;
2931   pcbddc->recompute_topography      = PETSC_TRUE;
2932   pcbddc->coarse_size               = -1;
2933   pcbddc->use_exact_dirichlet_trick = PETSC_TRUE;
2934   pcbddc->coarsening_ratio          = 8;
2935   pcbddc->coarse_eqs_per_proc       = 1;
2936   pcbddc->benign_compute_correction = PETSC_TRUE;
2937   pcbddc->nedfield                  = -1;
2938   pcbddc->nedglobal                 = PETSC_TRUE;
2939   pcbddc->graphmaxcount             = PETSC_MAX_INT;
2940   pcbddc->sub_schurs_layers         = -1;
2941   pcbddc->adaptive_threshold[0]     = 0.0;
2942   pcbddc->adaptive_threshold[1]     = 0.0;
2943 
2944   /* function pointers */
2945   pc->ops->apply               = PCApply_BDDC;
2946   pc->ops->applytranspose      = PCApplyTranspose_BDDC;
2947   pc->ops->setup               = PCSetUp_BDDC;
2948   pc->ops->destroy             = PCDestroy_BDDC;
2949   pc->ops->setfromoptions      = PCSetFromOptions_BDDC;
2950   pc->ops->view                = PCView_BDDC;
2951   pc->ops->applyrichardson     = NULL;
2952   pc->ops->applysymmetricleft  = NULL;
2953   pc->ops->applysymmetricright = NULL;
2954   pc->ops->presolve            = PCPreSolve_BDDC;
2955   pc->ops->postsolve           = PCPostSolve_BDDC;
2956   pc->ops->reset               = PCReset_BDDC;
2957 
2958   /* composing function */
2959   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDiscreteGradient_C",PCBDDCSetDiscreteGradient_BDDC));
2960   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDivergenceMat_C",PCBDDCSetDivergenceMat_BDDC));
2961   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetChangeOfBasisMat_C",PCBDDCSetChangeOfBasisMat_BDDC));
2962   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesLocalIS_C",PCBDDCSetPrimalVerticesLocalIS_BDDC));
2963   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetPrimalVerticesIS_C",PCBDDCSetPrimalVerticesIS_BDDC));
2964   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetPrimalVerticesLocalIS_C",PCBDDCGetPrimalVerticesLocalIS_BDDC));
2965   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetPrimalVerticesIS_C",PCBDDCGetPrimalVerticesIS_BDDC));
2966   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetCoarseningRatio_C",PCBDDCSetCoarseningRatio_BDDC));
2967   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevel_C",PCBDDCSetLevel_BDDC));
2968   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetUseExactDirichlet_C",PCBDDCSetUseExactDirichlet_BDDC));
2969   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLevels_C",PCBDDCSetLevels_BDDC));
2970   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundaries_C",PCBDDCSetDirichletBoundaries_BDDC));
2971   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDirichletBoundariesLocal_C",PCBDDCSetDirichletBoundariesLocal_BDDC));
2972   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundaries_C",PCBDDCSetNeumannBoundaries_BDDC));
2973   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetNeumannBoundariesLocal_C",PCBDDCSetNeumannBoundariesLocal_BDDC));
2974   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundaries_C",PCBDDCGetDirichletBoundaries_BDDC));
2975   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetDirichletBoundariesLocal_C",PCBDDCGetDirichletBoundariesLocal_BDDC));
2976   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundaries_C",PCBDDCGetNeumannBoundaries_BDDC));
2977   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCGetNeumannBoundariesLocal_C",PCBDDCGetNeumannBoundariesLocal_BDDC));
2978   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplitting_C",PCBDDCSetDofsSplitting_BDDC));
2979   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetDofsSplittingLocal_C",PCBDDCSetDofsSplittingLocal_BDDC));
2980   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCSetLocalAdjacencyGraph_C",PCBDDCSetLocalAdjacencyGraph_BDDC));
2981   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCCreateFETIDPOperators_C",PCBDDCCreateFETIDPOperators_BDDC));
2982   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetRHS_C",PCBDDCMatFETIDPGetRHS_BDDC));
2983   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCBDDCMatFETIDPGetSolution_C",PCBDDCMatFETIDPGetSolution_BDDC));
2984   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCPreSolveChangeRHS_C",PCPreSolveChangeRHS_BDDC));
2985   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",PCSetCoordinates_BDDC));
2986   PetscFunctionReturn(0);
2987 }
2988 
2989 /*@C
2990  PCBDDCInitializePackage - This function initializes everything in the PCBDDC package. It is called
2991     from PCInitializePackage().
2992 
2993  Level: developer
2994 
2995  .seealso: `PetscInitialize()`
2996 @*/
2997 PetscErrorCode PCBDDCInitializePackage(void)
2998 {
2999   int            i;
3000 
3001   PetscFunctionBegin;
3002   if (PCBDDCPackageInitialized) PetscFunctionReturn(0);
3003   PCBDDCPackageInitialized = PETSC_TRUE;
3004   PetscCall(PetscRegisterFinalize(PCBDDCFinalizePackage));
3005 
3006   /* general events */
3007   PetscCall(PetscLogEventRegister("PCBDDCTopo",PC_CLASSID,&PC_BDDC_Topology[0]));
3008   PetscCall(PetscLogEventRegister("PCBDDCLKSP",PC_CLASSID,&PC_BDDC_LocalSolvers[0]));
3009   PetscCall(PetscLogEventRegister("PCBDDCLWor",PC_CLASSID,&PC_BDDC_LocalWork[0]));
3010   PetscCall(PetscLogEventRegister("PCBDDCCorr",PC_CLASSID,&PC_BDDC_CorrectionSetUp[0]));
3011   PetscCall(PetscLogEventRegister("PCBDDCASet",PC_CLASSID,&PC_BDDC_ApproxSetUp[0]));
3012   PetscCall(PetscLogEventRegister("PCBDDCAApp",PC_CLASSID,&PC_BDDC_ApproxApply[0]));
3013   PetscCall(PetscLogEventRegister("PCBDDCCSet",PC_CLASSID,&PC_BDDC_CoarseSetUp[0]));
3014   PetscCall(PetscLogEventRegister("PCBDDCCKSP",PC_CLASSID,&PC_BDDC_CoarseSolver[0]));
3015   PetscCall(PetscLogEventRegister("PCBDDCAdap",PC_CLASSID,&PC_BDDC_AdaptiveSetUp[0]));
3016   PetscCall(PetscLogEventRegister("PCBDDCScal",PC_CLASSID,&PC_BDDC_Scaling[0]));
3017   PetscCall(PetscLogEventRegister("PCBDDCSchr",PC_CLASSID,&PC_BDDC_Schurs[0]));
3018   PetscCall(PetscLogEventRegister("PCBDDCDirS",PC_CLASSID,&PC_BDDC_Solves[0][0]));
3019   PetscCall(PetscLogEventRegister("PCBDDCNeuS",PC_CLASSID,&PC_BDDC_Solves[0][1]));
3020   PetscCall(PetscLogEventRegister("PCBDDCCoaS",PC_CLASSID,&PC_BDDC_Solves[0][2]));
3021   for (i=1;i<PETSC_PCBDDC_MAXLEVELS;i++) {
3022     char ename[32];
3023 
3024     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCTopo l%02d",i));
3025     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Topology[i]));
3026     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCLKSP l%02d",i));
3027     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_LocalSolvers[i]));
3028     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCLWor l%02d",i));
3029     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_LocalWork[i]));
3030     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCCorr l%02d",i));
3031     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_CorrectionSetUp[i]));
3032     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCASet l%02d",i));
3033     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_ApproxSetUp[i]));
3034     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCAApp l%02d",i));
3035     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_ApproxApply[i]));
3036     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCCSet l%02d",i));
3037     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_CoarseSetUp[i]));
3038     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCCKSP l%02d",i));
3039     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_CoarseSolver[i]));
3040     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCAdap l%02d",i));
3041     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_AdaptiveSetUp[i]));
3042     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCScal l%02d",i));
3043     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Scaling[i]));
3044     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCSchr l%02d",i));
3045     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Schurs[i]));
3046     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCDirS l%02d",i));
3047     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Solves[i][0]));
3048     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCNeuS l%02d",i));
3049     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Solves[i][1]));
3050     PetscCall(PetscSNPrintf(ename,sizeof(ename),"PCBDDCCoaS l%02d",i));
3051     PetscCall(PetscLogEventRegister(ename,PC_CLASSID,&PC_BDDC_Solves[i][2]));
3052   }
3053   PetscFunctionReturn(0);
3054 }
3055 
3056 /*@C
3057  PCBDDCFinalizePackage - This function frees everything from the PCBDDC package. It is
3058     called from PetscFinalize() automatically.
3059 
3060  Level: developer
3061 
3062  .seealso: `PetscFinalize()`
3063 @*/
3064 PetscErrorCode PCBDDCFinalizePackage(void)
3065 {
3066   PetscFunctionBegin;
3067   PCBDDCPackageInitialized = PETSC_FALSE;
3068   PetscFunctionReturn(0);
3069 }
3070