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