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