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