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