1 #include <petsc/private/kspimpl.h> /*I <petscksp.h> I*/ 2 #include <petsc/private/pcbddcimpl.h> 3 #include <petsc/private/pcbddcprivateimpl.h> 4 #include <petscdm.h> 5 6 static PetscBool cited = PETSC_FALSE; 7 static PetscBool cited2 = PETSC_FALSE; 8 static const char citation[] = 9 "@article{ZampiniPCBDDC,\n" 10 "author = {Stefano Zampini},\n" 11 "title = {{PCBDDC}: A Class of Robust Dual-Primal Methods in {PETS}c},\n" 12 "journal = {SIAM Journal on Scientific Computing},\n" 13 "volume = {38},\n" 14 "number = {5},\n" 15 "pages = {S282-S306},\n" 16 "year = {2016},\n" 17 "doi = {10.1137/15M1025785},\n" 18 "URL = {http://dx.doi.org/10.1137/15M1025785},\n" 19 "eprint = {http://dx.doi.org/10.1137/15M1025785}\n" 20 "}\n" 21 "@article{ZampiniDualPrimal,\n" 22 "author = {Stefano Zampini},\n" 23 "title = {{D}ual-{P}rimal methods for the cardiac {B}idomain model},\n" 24 "volume = {24},\n" 25 "number = {04},\n" 26 "pages = {667-696},\n" 27 "year = {2014},\n" 28 "doi = {10.1142/S0218202513500632},\n" 29 "URL = {https://www.worldscientific.com/doi/abs/10.1142/S0218202513500632},\n" 30 "eprint = {https://www.worldscientific.com/doi/pdf/10.1142/S0218202513500632}\n" 31 "}\n"; 32 static const char citation2[] = 33 "@article{li2013nonoverlapping,\n" 34 "title={A nonoverlapping domain decomposition method for incompressible Stokes equations with continuous pressures},\n" 35 "author={Li, Jing and Tu, Xuemin},\n" 36 "journal={SIAM Journal on Numerical Analysis},\n" 37 "volume={51},\n" 38 "number={2},\n" 39 "pages={1235--1253},\n" 40 "year={2013},\n" 41 "publisher={Society for Industrial and Applied Mathematics}\n" 42 "}\n"; 43 44 /* 45 This file implements the FETI-DP method in PETSc as part of KSP. 46 */ 47 typedef struct { 48 KSP parentksp; 49 } KSP_FETIDPMon; 50 51 typedef struct { 52 KSP innerksp; /* the KSP for the Lagrange multipliers */ 53 PC innerbddc; /* the inner BDDC object */ 54 PetscBool fully_redundant; /* true for using a fully redundant set of multipliers */ 55 PetscBool userbddc; /* true if the user provided the PCBDDC object */ 56 PetscBool saddlepoint; /* support for saddle point problems */ 57 IS pP; /* index set for pressure variables */ 58 Vec rhs_flip; /* see KSPFETIDPSetUpOperators */ 59 KSP_FETIDPMon *monctx; /* monitor context, used to pass user defined monitors 60 in the physical space */ 61 PetscObjectState matstate; /* these are needed just in the saddle point case */ 62 PetscObjectState matnnzstate; /* where we are going to use MatZeroRows on pmat */ 63 PetscBool statechanged; 64 PetscBool check; 65 } KSP_FETIDP; 66 67 static PetscErrorCode KSPFETIDPSetPressureOperator_FETIDP(KSP ksp, Mat P) 68 { 69 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 70 71 PetscFunctionBegin; 72 if (P) fetidp->saddlepoint = PETSC_TRUE; 73 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject)P)); 74 PetscFunctionReturn(0); 75 } 76 77 /*@ 78 KSPFETIDPSetPressureOperator - Sets the operator used to setup the pressure preconditioner for saddle point FETI-DP. 79 80 Collective on ksp 81 82 Input Parameters: 83 + ksp - the FETI-DP Krylov solver 84 - P - the linear operator to be preconditioned, usually the mass matrix. 85 86 Level: advanced 87 88 Notes: 89 The operator can be either passed in a) monolithic global ordering, b) pressure-only global ordering 90 or c) interface pressure ordering (if -ksp_fetidp_pressure_all false). 91 In cases b) and c), the pressure ordering of dofs needs to satisfy 92 pid_1 < pid_2 iff gid_1 < gid_2 93 where pid_1 and pid_2 are two different pressure dof numbers and gid_1 and gid_2 the corresponding 94 id in the monolithic global ordering. 95 96 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPGetInnerBDDC`, `KSPFETIDPGetInnerKSP`, `KSPSetOperators` 97 @*/ 98 PetscErrorCode KSPFETIDPSetPressureOperator(KSP ksp, Mat P) 99 { 100 PetscFunctionBegin; 101 PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); 102 if (P) PetscValidHeaderSpecific(P,MAT_CLASSID,2); 103 PetscTryMethod(ksp,"KSPFETIDPSetPressureOperator_C",(KSP,Mat),(ksp,P)); 104 PetscFunctionReturn(0); 105 } 106 107 static PetscErrorCode KSPFETIDPGetInnerKSP_FETIDP(KSP ksp, KSP* innerksp) 108 { 109 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 110 111 PetscFunctionBegin; 112 *innerksp = fetidp->innerksp; 113 PetscFunctionReturn(0); 114 } 115 116 /*@ 117 KSPFETIDPGetInnerKSP - Gets the KSP object for the Lagrange multipliers 118 119 Input Parameters: 120 + ksp - the FETI-DP KSP 121 - innerksp - the KSP for the multipliers 122 123 Level: advanced 124 125 Notes: 126 127 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC`, `KSPFETIDPGetInnerBDDC` 128 @*/ 129 PetscErrorCode KSPFETIDPGetInnerKSP(KSP ksp, KSP* innerksp) 130 { 131 PetscFunctionBegin; 132 PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); 133 PetscValidPointer(innerksp,2); 134 PetscUseMethod(ksp,"KSPFETIDPGetInnerKSP_C",(KSP,KSP*),(ksp,innerksp)); 135 PetscFunctionReturn(0); 136 } 137 138 static PetscErrorCode KSPFETIDPGetInnerBDDC_FETIDP(KSP ksp, PC* pc) 139 { 140 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 141 142 PetscFunctionBegin; 143 *pc = fetidp->innerbddc; 144 PetscFunctionReturn(0); 145 } 146 147 /*@ 148 KSPFETIDPGetInnerBDDC - Gets the BDDC preconditioner used to setup the FETI-DP matrix for the Lagrange multipliers 149 150 Input Parameters: 151 + ksp - the FETI-DP Krylov solver 152 - pc - the BDDC preconditioner 153 154 Level: advanced 155 156 Notes: 157 158 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC`, `KSPFETIDPGetInnerKSP` 159 @*/ 160 PetscErrorCode KSPFETIDPGetInnerBDDC(KSP ksp, PC* pc) 161 { 162 PetscFunctionBegin; 163 PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); 164 PetscValidPointer(pc,2); 165 PetscUseMethod(ksp,"KSPFETIDPGetInnerBDDC_C",(KSP,PC*),(ksp,pc)); 166 PetscFunctionReturn(0); 167 } 168 169 static PetscErrorCode KSPFETIDPSetInnerBDDC_FETIDP(KSP ksp, PC pc) 170 { 171 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 172 173 PetscFunctionBegin; 174 PetscCall(PetscObjectReference((PetscObject)pc)); 175 PetscCall(PCDestroy(&fetidp->innerbddc)); 176 fetidp->innerbddc = pc; 177 fetidp->userbddc = PETSC_TRUE; 178 PetscFunctionReturn(0); 179 } 180 181 /*@ 182 KSPFETIDPSetInnerBDDC - Sets the BDDC preconditioner used to setup the FETI-DP matrix for the Lagrange multipliers 183 184 Collective on ksp 185 186 Input Parameters: 187 + ksp - the FETI-DP Krylov solver 188 - pc - the BDDC preconditioner 189 190 Level: advanced 191 192 Notes: 193 194 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPGetInnerBDDC`, `KSPFETIDPGetInnerKSP` 195 @*/ 196 PetscErrorCode KSPFETIDPSetInnerBDDC(KSP ksp, PC pc) 197 { 198 PetscBool isbddc; 199 200 PetscFunctionBegin; 201 PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); 202 PetscValidHeaderSpecific(pc,PC_CLASSID,2); 203 PetscCall(PetscObjectTypeCompare((PetscObject)pc,PCBDDC,&isbddc)); 204 PetscCheck(isbddc,PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_WRONG,"KSPFETIDPSetInnerBDDC need a PCBDDC preconditioner"); 205 PetscTryMethod(ksp,"KSPFETIDPSetInnerBDDC_C",(KSP,PC),(ksp,pc)); 206 PetscFunctionReturn(0); 207 } 208 209 static PetscErrorCode KSPBuildSolution_FETIDP(KSP ksp,Vec v,Vec *V) 210 { 211 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 212 Mat F; 213 Vec Xl; 214 215 PetscFunctionBegin; 216 PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL)); 217 PetscCall(KSPBuildSolution(fetidp->innerksp,NULL,&Xl)); 218 if (v) { 219 PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,v)); 220 *V = v; 221 } else { 222 PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,*V)); 223 } 224 PetscFunctionReturn(0); 225 } 226 227 static PetscErrorCode KSPMonitor_FETIDP(KSP ksp,PetscInt it,PetscReal rnorm,void* ctx) 228 { 229 KSP_FETIDPMon *monctx = (KSP_FETIDPMon*)ctx; 230 231 PetscFunctionBegin; 232 PetscCall(KSPMonitor(monctx->parentksp,it,rnorm)); 233 PetscFunctionReturn(0); 234 } 235 236 static PetscErrorCode KSPComputeEigenvalues_FETIDP(KSP ksp,PetscInt nmax,PetscReal *r,PetscReal *c,PetscInt *neig) 237 { 238 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 239 240 PetscFunctionBegin; 241 PetscCall(KSPComputeEigenvalues(fetidp->innerksp,nmax,r,c,neig)); 242 PetscFunctionReturn(0); 243 } 244 245 static PetscErrorCode KSPComputeExtremeSingularValues_FETIDP(KSP ksp,PetscReal *emax,PetscReal *emin) 246 { 247 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 248 249 PetscFunctionBegin; 250 PetscCall(KSPComputeExtremeSingularValues(fetidp->innerksp,emax,emin)); 251 PetscFunctionReturn(0); 252 } 253 254 static PetscErrorCode KSPFETIDPCheckOperators(KSP ksp, PetscViewer viewer) 255 { 256 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 257 PC_BDDC *pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 258 PC_IS *pcis = (PC_IS*)fetidp->innerbddc->data; 259 Mat_IS *matis = (Mat_IS*)fetidp->innerbddc->pmat->data; 260 Mat F; 261 FETIDPMat_ctx fetidpmat_ctx; 262 Vec test_vec,test_vec_p = NULL,fetidp_global; 263 IS dirdofs,isvert; 264 MPI_Comm comm = PetscObjectComm((PetscObject)ksp); 265 PetscScalar sval,*array; 266 PetscReal val,rval; 267 const PetscInt *vertex_indices; 268 PetscInt i,n_vertices; 269 PetscBool isascii; 270 271 PetscFunctionBegin; 272 PetscCheckSameComm(ksp,1,viewer,2); 273 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii)); 274 PetscCheck(isascii,comm,PETSC_ERR_SUP,"Unsupported viewer"); 275 PetscCall(PetscViewerASCIIPrintf(viewer,"----------FETI-DP MAT --------------\n")); 276 PetscCall(PetscViewerASCIIAddTab(viewer,2)); 277 PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL)); 278 PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO)); 279 PetscCall(MatView(F,viewer)); 280 PetscCall(PetscViewerPopFormat(viewer)); 281 PetscCall(PetscViewerASCIISubtractTab(viewer,2)); 282 PetscCall(MatShellGetContext(F,&fetidpmat_ctx)); 283 PetscCall(PetscViewerASCIIPrintf(viewer,"----------FETI-DP TESTS--------------\n")); 284 PetscCall(PetscViewerASCIIPrintf(viewer,"All tests should return zero!\n")); 285 PetscCall(PetscViewerASCIIPrintf(viewer,"FETIDP MAT context in the ")); 286 if (fetidp->fully_redundant) { 287 PetscCall(PetscViewerASCIIPrintf(viewer,"fully redundant case for lagrange multipliers.\n")); 288 } else { 289 PetscCall(PetscViewerASCIIPrintf(viewer,"Non-fully redundant case for lagrange multiplier.\n")); 290 } 291 PetscCall(PetscViewerFlush(viewer)); 292 293 /* Get Vertices used to define the BDDC */ 294 PetscCall(PCBDDCGraphGetCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&isvert)); 295 PetscCall(ISGetLocalSize(isvert,&n_vertices)); 296 PetscCall(ISGetIndices(isvert,&vertex_indices)); 297 298 /******************************************************************/ 299 /* TEST A/B: Test numbering of global fetidp dofs */ 300 /******************************************************************/ 301 PetscCall(MatCreateVecs(F,&fetidp_global,NULL)); 302 PetscCall(VecDuplicate(fetidpmat_ctx->lambda_local,&test_vec)); 303 PetscCall(VecSet(fetidp_global,1.0)); 304 PetscCall(VecSet(test_vec,1.)); 305 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 306 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 307 if (fetidpmat_ctx->l2g_p) { 308 PetscCall(VecDuplicate(fetidpmat_ctx->vP,&test_vec_p)); 309 PetscCall(VecSet(test_vec_p,1.)); 310 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidp_global,fetidpmat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE)); 311 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidp_global,fetidpmat_ctx->vP,INSERT_VALUES,SCATTER_REVERSE)); 312 } 313 PetscCall(VecAXPY(test_vec,-1.0,fetidpmat_ctx->lambda_local)); 314 PetscCall(VecNorm(test_vec,NORM_INFINITY,&val)); 315 PetscCall(VecDestroy(&test_vec)); 316 PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm)); 317 PetscCall(PetscViewerASCIIPrintf(viewer,"A: CHECK glob to loc: % 1.14e\n",(double)rval)); 318 319 if (fetidpmat_ctx->l2g_p) { 320 PetscCall(VecAXPY(test_vec_p,-1.0,fetidpmat_ctx->vP)); 321 PetscCall(VecNorm(test_vec_p,NORM_INFINITY,&val)); 322 PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm)); 323 PetscCall(PetscViewerASCIIPrintf(viewer,"A: CHECK glob to loc (p): % 1.14e\n",(double)rval)); 324 } 325 326 if (fetidp->fully_redundant) { 327 PetscCall(VecSet(fetidp_global,0.0)); 328 PetscCall(VecSet(fetidpmat_ctx->lambda_local,0.5)); 329 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 330 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 331 PetscCall(VecSum(fetidp_global,&sval)); 332 val = PetscRealPart(sval)-fetidpmat_ctx->n_lambda; 333 PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm)); 334 PetscCall(PetscViewerASCIIPrintf(viewer,"B: CHECK loc to glob: % 1.14e\n",(double)rval)); 335 } 336 337 if (fetidpmat_ctx->l2g_p) { 338 PetscCall(VecSet(pcis->vec1_N,1.0)); 339 PetscCall(VecSet(pcis->vec1_global,0.0)); 340 PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 341 PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 342 343 PetscCall(VecSet(fetidp_global,0.0)); 344 PetscCall(VecSet(fetidpmat_ctx->vP,-1.0)); 345 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 346 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 347 PetscCall(VecScatterBegin(fetidpmat_ctx->g2g_p,fetidp_global,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 348 PetscCall(VecScatterEnd(fetidpmat_ctx->g2g_p,fetidp_global,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 349 PetscCall(VecScatterBegin(fetidpmat_ctx->g2g_p,pcis->vec1_global,fetidp_global,INSERT_VALUES,SCATTER_FORWARD)); 350 PetscCall(VecScatterEnd(fetidpmat_ctx->g2g_p,pcis->vec1_global,fetidp_global,INSERT_VALUES,SCATTER_FORWARD)); 351 PetscCall(VecSum(fetidp_global,&sval)); 352 val = PetscRealPart(sval); 353 PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm)); 354 PetscCall(PetscViewerASCIIPrintf(viewer,"B: CHECK loc to glob (p): % 1.14e\n",(double)rval)); 355 } 356 357 /******************************************************************/ 358 /* TEST C: It should hold B_delta*w=0, w\in\widehat{W} */ 359 /* This is the meaning of the B matrix */ 360 /******************************************************************/ 361 362 PetscCall(VecSetRandom(pcis->vec1_N,NULL)); 363 PetscCall(VecSet(pcis->vec1_global,0.0)); 364 PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 365 PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_N,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE)); 366 PetscCall(VecScatterBegin(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD)); 367 PetscCall(VecScatterEnd(matis->rctx,pcis->vec1_global,pcis->vec1_N,INSERT_VALUES,SCATTER_FORWARD)); 368 PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 369 PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 370 /* Action of B_delta */ 371 PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local)); 372 PetscCall(VecSet(fetidp_global,0.0)); 373 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 374 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 375 PetscCall(VecNorm(fetidp_global,NORM_INFINITY,&val)); 376 PetscCall(PetscViewerASCIIPrintf(viewer,"C: CHECK infty norm of B_delta*w (w continuous): % 1.14e\n",(double)val)); 377 378 /******************************************************************/ 379 /* TEST D: It should hold E_Dw = w - P_Dw w\in\widetilde{W} */ 380 /* E_D = R_D^TR */ 381 /* P_D = B_{D,delta}^T B_{delta} */ 382 /* eq.44 Mandel Tezaur and Dohrmann 2005 */ 383 /******************************************************************/ 384 385 /* compute a random vector in \widetilde{W} */ 386 PetscCall(VecSetRandom(pcis->vec1_N,NULL)); 387 /* set zero at vertices and essential dofs */ 388 PetscCall(VecGetArray(pcis->vec1_N,&array)); 389 for (i=0;i<n_vertices;i++) array[vertex_indices[i]] = 0.0; 390 PetscCall(PCBDDCGraphGetDirichletDofs(pcbddc->mat_graph,&dirdofs)); 391 if (dirdofs) { 392 const PetscInt *idxs; 393 PetscInt ndir; 394 395 PetscCall(ISGetLocalSize(dirdofs,&ndir)); 396 PetscCall(ISGetIndices(dirdofs,&idxs)); 397 for (i=0;i<ndir;i++) array[idxs[i]] = 0.0; 398 PetscCall(ISRestoreIndices(dirdofs,&idxs)); 399 } 400 PetscCall(VecRestoreArray(pcis->vec1_N,&array)); 401 /* store w for final comparison */ 402 PetscCall(VecDuplicate(pcis->vec1_B,&test_vec)); 403 PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,test_vec,INSERT_VALUES,SCATTER_FORWARD)); 404 PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,test_vec,INSERT_VALUES,SCATTER_FORWARD)); 405 406 /* Jump operator P_D : results stored in pcis->vec1_B */ 407 /* Action of B_delta */ 408 PetscCall(MatMult(fetidpmat_ctx->B_delta,test_vec,fetidpmat_ctx->lambda_local)); 409 PetscCall(VecSet(fetidp_global,0.0)); 410 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 411 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 412 /* Action of B_Ddelta^T */ 413 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 414 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 415 PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B)); 416 417 /* Average operator E_D : results stored in pcis->vec2_B */ 418 PetscCall(PCBDDCScalingExtension(fetidpmat_ctx->pc,test_vec,pcis->vec1_global)); 419 PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_global,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 420 PetscCall(VecScatterEnd(pcis->global_to_B,pcis->vec1_global,pcis->vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 421 422 /* test E_D=I-P_D */ 423 PetscCall(VecAXPY(pcis->vec1_B,1.0,pcis->vec2_B)); 424 PetscCall(VecAXPY(pcis->vec1_B,-1.0,test_vec)); 425 PetscCall(VecNorm(pcis->vec1_B,NORM_INFINITY,&val)); 426 PetscCall(VecDestroy(&test_vec)); 427 PetscCallMPI(MPI_Reduce(&val,&rval,1,MPIU_REAL,MPIU_MAX,0,comm)); 428 PetscCall(PetscViewerASCIIPrintf(viewer,"%d: CHECK infty norm of E_D + P_D - I: %1.14e\n",PetscGlobalRank,(double)val)); 429 430 /******************************************************************/ 431 /* TEST E: It should hold R_D^TP_Dw=0 w\in\widetilde{W} */ 432 /* eq.48 Mandel Tezaur and Dohrmann 2005 */ 433 /******************************************************************/ 434 435 PetscCall(VecSetRandom(pcis->vec1_N,NULL)); 436 /* set zero at vertices and essential dofs */ 437 PetscCall(VecGetArray(pcis->vec1_N,&array)); 438 for (i=0;i<n_vertices;i++) array[vertex_indices[i]] = 0.0; 439 if (dirdofs) { 440 const PetscInt *idxs; 441 PetscInt ndir; 442 443 PetscCall(ISGetLocalSize(dirdofs,&ndir)); 444 PetscCall(ISGetIndices(dirdofs,&idxs)); 445 for (i=0;i<ndir;i++) array[idxs[i]] = 0.0; 446 PetscCall(ISRestoreIndices(dirdofs,&idxs)); 447 } 448 PetscCall(VecRestoreArray(pcis->vec1_N,&array)); 449 450 /* Jump operator P_D : results stored in pcis->vec1_B */ 451 452 PetscCall(VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 453 PetscCall(VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 454 /* Action of B_delta */ 455 PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local)); 456 PetscCall(VecSet(fetidp_global,0.0)); 457 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 458 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,fetidp_global,ADD_VALUES,SCATTER_FORWARD)); 459 /* Action of B_Ddelta^T */ 460 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 461 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 462 PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B)); 463 /* scaling */ 464 PetscCall(PCBDDCScalingExtension(fetidpmat_ctx->pc,pcis->vec1_B,pcis->vec1_global)); 465 PetscCall(VecNorm(pcis->vec1_global,NORM_INFINITY,&val)); 466 PetscCall(PetscViewerASCIIPrintf(viewer,"E: CHECK infty norm of R^T_D P_D: % 1.14e\n",(double)val)); 467 468 if (!fetidp->fully_redundant) { 469 /******************************************************************/ 470 /* TEST F: It should holds B_{delta}B^T_{D,delta}=I */ 471 /* Corollary thm 14 Mandel Tezaur and Dohrmann 2005 */ 472 /******************************************************************/ 473 PetscCall(VecDuplicate(fetidp_global,&test_vec)); 474 PetscCall(VecSetRandom(fetidp_global,NULL)); 475 if (fetidpmat_ctx->l2g_p) { 476 PetscCall(VecSet(fetidpmat_ctx->vP,0.)); 477 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,INSERT_VALUES,SCATTER_FORWARD)); 478 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_p,fetidpmat_ctx->vP,fetidp_global,INSERT_VALUES,SCATTER_FORWARD)); 479 } 480 /* Action of B_Ddelta^T */ 481 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 482 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidp_global,fetidpmat_ctx->lambda_local,INSERT_VALUES,SCATTER_REVERSE)); 483 PetscCall(MatMultTranspose(fetidpmat_ctx->B_Ddelta,fetidpmat_ctx->lambda_local,pcis->vec1_B)); 484 /* Action of B_delta */ 485 PetscCall(MatMult(fetidpmat_ctx->B_delta,pcis->vec1_B,fetidpmat_ctx->lambda_local)); 486 PetscCall(VecSet(test_vec,0.0)); 487 PetscCall(VecScatterBegin(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,test_vec,ADD_VALUES,SCATTER_FORWARD)); 488 PetscCall(VecScatterEnd(fetidpmat_ctx->l2g_lambda,fetidpmat_ctx->lambda_local,test_vec,ADD_VALUES,SCATTER_FORWARD)); 489 PetscCall(VecAXPY(fetidp_global,-1.,test_vec)); 490 PetscCall(VecNorm(fetidp_global,NORM_INFINITY,&val)); 491 PetscCall(PetscViewerASCIIPrintf(viewer,"E: CHECK infty norm of P^T_D - I: % 1.14e\n",(double)val)); 492 PetscCall(VecDestroy(&test_vec)); 493 } 494 PetscCall(PetscViewerASCIIPrintf(viewer,"-------------------------------------\n")); 495 PetscCall(PetscViewerFlush(viewer)); 496 PetscCall(VecDestroy(&test_vec_p)); 497 PetscCall(ISDestroy(&dirdofs)); 498 PetscCall(VecDestroy(&fetidp_global)); 499 PetscCall(ISRestoreIndices(isvert,&vertex_indices)); 500 PetscCall(PCBDDCGraphRestoreCandidatesIS(pcbddc->mat_graph,NULL,NULL,NULL,NULL,&isvert)); 501 PetscFunctionReturn(0); 502 } 503 504 static PetscErrorCode KSPFETIDPSetUpOperators(KSP ksp) 505 { 506 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 507 PC_BDDC *pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 508 Mat A,Ap; 509 PetscInt fid = -1; 510 PetscMPIInt size; 511 PetscBool ismatis,pisz = PETSC_FALSE,allp = PETSC_FALSE,schp = PETSC_FALSE; 512 PetscBool flip = PETSC_FALSE; /* Usually, Stokes is written (B = -\int_\Omega \nabla \cdot u q) 513 | A B'| | v | = | f | 514 | B 0 | | p | = | g | 515 If -ksp_fetidp_saddlepoint_flip is true, the code assumes it is written as 516 | A B'| | v | = | f | 517 |-B 0 | | p | = |-g | 518 */ 519 PetscObjectState matstate, matnnzstate; 520 521 PetscFunctionBegin; 522 PetscOptionsBegin(PetscObjectComm((PetscObject)ksp),((PetscObject)ksp)->prefix,"FETI-DP options","PC"); 523 PetscCall(PetscOptionsInt("-ksp_fetidp_pressure_field","Field id for pressures for saddle-point problems",NULL,fid,&fid,NULL)); 524 PetscCall(PetscOptionsBool("-ksp_fetidp_pressure_all","Use the whole pressure set instead of just that at the interface",NULL,allp,&allp,NULL)); 525 PetscCall(PetscOptionsBool("-ksp_fetidp_saddlepoint_flip","Flip the sign of the pressure-velocity (lower-left) block",NULL,flip,&flip,NULL)); 526 PetscCall(PetscOptionsBool("-ksp_fetidp_pressure_schur","Use a BDDC solver for pressure",NULL,schp,&schp,NULL)); 527 PetscOptionsEnd(); 528 529 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ksp),&size)); 530 fetidp->saddlepoint = (fid >= 0 ? PETSC_TRUE : fetidp->saddlepoint); 531 if (size == 1) fetidp->saddlepoint = PETSC_FALSE; 532 533 PetscCall(KSPGetOperators(ksp,&A,&Ap)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)A,MATIS,&ismatis)); 535 PetscCheck(ismatis,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Amat should be of type MATIS"); 536 537 /* Quiet return if the matrix states are unchanged. 538 Needed only for the saddle point case since it uses MatZeroRows 539 on a matrix that may not have changed */ 540 PetscCall(PetscObjectStateGet((PetscObject)A,&matstate)); 541 PetscCall(MatGetNonzeroState(A,&matnnzstate)); 542 if (matstate == fetidp->matstate && matnnzstate == fetidp->matnnzstate) PetscFunctionReturn(0); 543 fetidp->matstate = matstate; 544 fetidp->matnnzstate = matnnzstate; 545 fetidp->statechanged = fetidp->saddlepoint; 546 547 /* see if we have some fields attached */ 548 if (!pcbddc->n_ISForDofsLocal && !pcbddc->n_ISForDofs) { 549 DM dm; 550 PetscContainer c; 551 552 PetscCall(KSPGetDM(ksp,&dm)); 553 PetscCall(PetscObjectQuery((PetscObject)A,"_convert_nest_lfields",(PetscObject*)&c)); 554 if (dm) { 555 IS *fields; 556 PetscInt nf,i; 557 558 PetscCall(DMCreateFieldDecomposition(dm,&nf,NULL,&fields,NULL)); 559 PetscCall(PCBDDCSetDofsSplitting(fetidp->innerbddc,nf,fields)); 560 for (i=0;i<nf;i++) { 561 PetscCall(ISDestroy(&fields[i])); 562 } 563 PetscCall(PetscFree(fields)); 564 } else if (c) { 565 MatISLocalFields lf; 566 567 PetscCall(PetscContainerGetPointer(c,(void**)&lf)); 568 PetscCall(PCBDDCSetDofsSplittingLocal(fetidp->innerbddc,lf->nr,lf->rf)); 569 } 570 } 571 572 if (!fetidp->saddlepoint) { 573 PetscCall(PCSetOperators(fetidp->innerbddc,A,A)); 574 } else { 575 Mat nA,lA,PPmat; 576 MatNullSpace nnsp; 577 IS pP; 578 PetscInt totP; 579 580 PetscCall(MatISGetLocalMat(A,&lA)); 581 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",(PetscObject)lA)); 582 583 pP = fetidp->pP; 584 if (!pP) { /* first time, need to compute pressure dofs */ 585 PC_IS *pcis = (PC_IS*)fetidp->innerbddc->data; 586 Mat_IS *matis = (Mat_IS*)(A->data); 587 ISLocalToGlobalMapping l2g; 588 IS lP = NULL,II,pII,lPall,Pall,is1,is2; 589 const PetscInt *idxs; 590 PetscInt nl,ni,*widxs; 591 PetscInt i,j,n_neigh,*neigh,*n_shared,**shared,*count; 592 PetscInt rst,ren,n; 593 PetscBool ploc; 594 595 PetscCall(MatGetLocalSize(A,&nl,NULL)); 596 PetscCall(MatGetOwnershipRange(A,&rst,&ren)); 597 PetscCall(MatGetLocalSize(lA,&n,NULL)); 598 PetscCall(MatISGetLocalToGlobalMapping(A,&l2g,NULL)); 599 600 if (!pcis->is_I_local) { /* need to compute interior dofs */ 601 PetscCall(PetscCalloc1(n,&count)); 602 PetscCall(ISLocalToGlobalMappingGetInfo(l2g,&n_neigh,&neigh,&n_shared,&shared)); 603 for (i=1;i<n_neigh;i++) 604 for (j=0;j<n_shared[i];j++) 605 count[shared[i][j]] += 1; 606 for (i=0,j=0;i<n;i++) if (!count[i]) count[j++] = i; 607 PetscCall(ISLocalToGlobalMappingRestoreInfo(l2g,&n_neigh,&neigh,&n_shared,&shared)); 608 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,j,count,PETSC_OWN_POINTER,&II)); 609 } else { 610 PetscCall(PetscObjectReference((PetscObject)pcis->is_I_local)); 611 II = pcis->is_I_local; 612 } 613 614 /* interior dofs in layout */ 615 PetscCall(PetscArrayzero(matis->sf_leafdata,n)); 616 PetscCall(PetscArrayzero(matis->sf_rootdata,nl)); 617 PetscCall(ISGetLocalSize(II,&ni)); 618 PetscCall(ISGetIndices(II,&idxs)); 619 for (i=0;i<ni;i++) matis->sf_leafdata[idxs[i]] = 1; 620 PetscCall(ISRestoreIndices(II,&idxs)); 621 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 622 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 623 PetscCall(PetscMalloc1(PetscMax(nl,n),&widxs)); 624 for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst; 625 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&pII)); 626 627 /* pressure dofs */ 628 Pall = NULL; 629 lPall = NULL; 630 ploc = PETSC_FALSE; 631 if (fid < 0) { /* zero pressure block */ 632 PetscInt np; 633 634 PetscCall(MatFindZeroDiagonals(A,&Pall)); 635 PetscCall(ISGetSize(Pall,&np)); 636 if (!np) { /* zero-block not found, defaults to last field (if set) */ 637 fid = pcbddc->n_ISForDofsLocal ? pcbddc->n_ISForDofsLocal - 1 : pcbddc->n_ISForDofs - 1; 638 PetscCall(ISDestroy(&Pall)); 639 } else if (!pcbddc->n_ISForDofsLocal && !pcbddc->n_ISForDofs) { 640 PetscCall(PCBDDCSetDofsSplitting(fetidp->innerbddc,1,&Pall)); 641 } 642 } 643 if (!Pall) { /* look for registered fields */ 644 if (pcbddc->n_ISForDofsLocal) { 645 PetscInt np; 646 647 PetscCheck(fid >= 0 && fid < pcbddc->n_ISForDofsLocal,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %" PetscInt_FMT ", max %" PetscInt_FMT,fid,pcbddc->n_ISForDofsLocal); 648 /* need a sequential IS */ 649 PetscCall(ISGetLocalSize(pcbddc->ISForDofsLocal[fid],&np)); 650 PetscCall(ISGetIndices(pcbddc->ISForDofsLocal[fid],&idxs)); 651 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,np,idxs,PETSC_COPY_VALUES,&lPall)); 652 PetscCall(ISRestoreIndices(pcbddc->ISForDofsLocal[fid],&idxs)); 653 ploc = PETSC_TRUE; 654 } else if (pcbddc->n_ISForDofs) { 655 PetscCheck(fid >= 0 && fid < pcbddc->n_ISForDofs,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %" PetscInt_FMT ", max %" PetscInt_FMT,fid,pcbddc->n_ISForDofs); 656 PetscCall(PetscObjectReference((PetscObject)pcbddc->ISForDofs[fid])); 657 Pall = pcbddc->ISForDofs[fid]; 658 } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Cannot detect pressure field! Use KSPFETIDPGetInnerBDDC() + PCBDDCSetDofsSplitting or PCBDDCSetDofsSplittingLocal"); 659 } 660 661 /* if the user requested the entire pressure, 662 remove the interior pressure dofs from II (or pII) */ 663 if (allp) { 664 if (ploc) { 665 IS nII; 666 PetscCall(ISDifference(II,lPall,&nII)); 667 PetscCall(ISDestroy(&II)); 668 II = nII; 669 } else { 670 IS nII; 671 PetscCall(ISDifference(pII,Pall,&nII)); 672 PetscCall(ISDestroy(&pII)); 673 pII = nII; 674 } 675 } 676 if (ploc) { 677 PetscCall(ISDifference(lPall,II,&lP)); 678 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lP",(PetscObject)lP)); 679 } else { 680 PetscCall(ISDifference(Pall,pII,&pP)); 681 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",(PetscObject)pP)); 682 /* need all local pressure dofs */ 683 PetscCall(PetscArrayzero(matis->sf_leafdata,n)); 684 PetscCall(PetscArrayzero(matis->sf_rootdata,nl)); 685 PetscCall(ISGetLocalSize(Pall,&ni)); 686 PetscCall(ISGetIndices(Pall,&idxs)); 687 for (i=0;i<ni;i++) matis->sf_rootdata[idxs[i]-rst] = 1; 688 PetscCall(ISRestoreIndices(Pall,&idxs)); 689 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 690 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 691 for (i=0,ni=0;i<n;i++) if (matis->sf_leafdata[i]) widxs[ni++] = i; 692 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,ni,widxs,PETSC_COPY_VALUES,&lPall)); 693 } 694 695 if (!Pall) { 696 PetscCall(PetscArrayzero(matis->sf_leafdata,n)); 697 PetscCall(PetscArrayzero(matis->sf_rootdata,nl)); 698 PetscCall(ISGetLocalSize(lPall,&ni)); 699 PetscCall(ISGetIndices(lPall,&idxs)); 700 for (i=0;i<ni;i++) matis->sf_leafdata[idxs[i]] = 1; 701 PetscCall(ISRestoreIndices(lPall,&idxs)); 702 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 703 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 704 for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst; 705 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&Pall)); 706 } 707 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject)Pall)); 708 709 if (flip) { 710 PetscInt npl; 711 PetscCall(ISGetLocalSize(Pall,&npl)); 712 PetscCall(ISGetIndices(Pall,&idxs)); 713 PetscCall(MatCreateVecs(A,NULL,&fetidp->rhs_flip)); 714 PetscCall(VecSet(fetidp->rhs_flip,1.)); 715 PetscCall(VecSetOption(fetidp->rhs_flip,VEC_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE)); 716 for (i=0;i<npl;i++) { 717 PetscCall(VecSetValue(fetidp->rhs_flip,idxs[i],-1.,INSERT_VALUES)); 718 } 719 PetscCall(VecAssemblyBegin(fetidp->rhs_flip)); 720 PetscCall(VecAssemblyEnd(fetidp->rhs_flip)); 721 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_flip",(PetscObject)fetidp->rhs_flip)); 722 PetscCall(ISRestoreIndices(Pall,&idxs)); 723 } 724 PetscCall(ISDestroy(&Pall)); 725 PetscCall(ISDestroy(&pII)); 726 727 /* local selected pressures in subdomain-wise and global ordering */ 728 PetscCall(PetscArrayzero(matis->sf_leafdata,n)); 729 PetscCall(PetscArrayzero(matis->sf_rootdata,nl)); 730 if (!ploc) { 731 PetscInt *widxs2; 732 733 PetscCheck(pP,PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Missing parallel pressure IS"); 734 PetscCall(ISGetLocalSize(pP,&ni)); 735 PetscCall(ISGetIndices(pP,&idxs)); 736 for (i=0;i<ni;i++) matis->sf_rootdata[idxs[i]-rst] = 1; 737 PetscCall(ISRestoreIndices(pP,&idxs)); 738 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 739 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 740 for (i=0,ni=0;i<n;i++) if (matis->sf_leafdata[i]) widxs[ni++] = i; 741 PetscCall(PetscMalloc1(ni,&widxs2)); 742 PetscCall(ISLocalToGlobalMappingApply(l2g,ni,widxs,widxs2)); 743 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,ni,widxs,PETSC_COPY_VALUES,&lP)); 744 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lP",(PetscObject)lP)); 745 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs2,PETSC_OWN_POINTER,&is1)); 746 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_gP",(PetscObject)is1)); 747 PetscCall(ISDestroy(&is1)); 748 } else { 749 PetscCheck(lP,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing sequential pressure IS"); 750 PetscCall(ISGetLocalSize(lP,&ni)); 751 PetscCall(ISGetIndices(lP,&idxs)); 752 for (i=0;i<ni;i++) 753 if (idxs[i] >=0 && idxs[i] < n) 754 matis->sf_leafdata[idxs[i]] = 1; 755 PetscCall(ISRestoreIndices(lP,&idxs)); 756 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 757 PetscCall(ISLocalToGlobalMappingApply(l2g,ni,idxs,widxs)); 758 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&is1)); 759 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_gP",(PetscObject)is1)); 760 PetscCall(ISDestroy(&is1)); 761 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,matis->sf_leafdata,matis->sf_rootdata,MPI_REPLACE)); 762 for (i=0,ni=0;i<nl;i++) if (matis->sf_rootdata[i]) widxs[ni++] = i+rst; 763 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),ni,widxs,PETSC_COPY_VALUES,&pP)); 764 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",(PetscObject)pP)); 765 } 766 PetscCall(PetscFree(widxs)); 767 768 /* If there's any "interior pressure", 769 we may want to use a discrete harmonic solver instead 770 of a Stokes harmonic for the Dirichlet preconditioner 771 Need to extract the interior velocity dofs in interior dofs ordering (iV) 772 and interior pressure dofs in local ordering (iP) */ 773 if (!allp) { 774 ISLocalToGlobalMapping l2g_t; 775 776 PetscCall(ISDifference(lPall,lP,&is1)); 777 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_iP",(PetscObject)is1)); 778 PetscCall(ISDifference(II,is1,&is2)); 779 PetscCall(ISDestroy(&is1)); 780 PetscCall(ISLocalToGlobalMappingCreateIS(II,&l2g_t)); 781 PetscCall(ISGlobalToLocalMappingApplyIS(l2g_t,IS_GTOLM_DROP,is2,&is1)); 782 PetscCall(ISGetLocalSize(is1,&i)); 783 PetscCall(ISGetLocalSize(is2,&j)); 784 PetscCheck(i == j,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent local sizes %" PetscInt_FMT " and %" PetscInt_FMT " for iV",i,j); 785 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_iV",(PetscObject)is1)); 786 PetscCall(ISLocalToGlobalMappingDestroy(&l2g_t)); 787 PetscCall(ISDestroy(&is1)); 788 PetscCall(ISDestroy(&is2)); 789 } 790 PetscCall(ISDestroy(&II)); 791 792 /* exclude selected pressures from the inner BDDC */ 793 if (pcbddc->DirichletBoundariesLocal) { 794 IS list[2],plP,isout; 795 PetscInt np; 796 797 /* need a parallel IS */ 798 PetscCall(ISGetLocalSize(lP,&np)); 799 PetscCall(ISGetIndices(lP,&idxs)); 800 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),np,idxs,PETSC_USE_POINTER,&plP)); 801 list[0] = plP; 802 list[1] = pcbddc->DirichletBoundariesLocal; 803 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)ksp),2,list,&isout)); 804 PetscCall(ISSortRemoveDups(isout)); 805 PetscCall(ISDestroy(&plP)); 806 PetscCall(ISRestoreIndices(lP,&idxs)); 807 PetscCall(PCBDDCSetDirichletBoundariesLocal(fetidp->innerbddc,isout)); 808 PetscCall(ISDestroy(&isout)); 809 } else if (pcbddc->DirichletBoundaries) { 810 IS list[2],isout; 811 812 list[0] = pP; 813 list[1] = pcbddc->DirichletBoundaries; 814 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)ksp),2,list,&isout)); 815 PetscCall(ISSortRemoveDups(isout)); 816 PetscCall(PCBDDCSetDirichletBoundaries(fetidp->innerbddc,isout)); 817 PetscCall(ISDestroy(&isout)); 818 } else { 819 IS plP; 820 PetscInt np; 821 822 /* need a parallel IS */ 823 PetscCall(ISGetLocalSize(lP,&np)); 824 PetscCall(ISGetIndices(lP,&idxs)); 825 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)ksp),np,idxs,PETSC_COPY_VALUES,&plP)); 826 PetscCall(PCBDDCSetDirichletBoundariesLocal(fetidp->innerbddc,plP)); 827 PetscCall(ISDestroy(&plP)); 828 PetscCall(ISRestoreIndices(lP,&idxs)); 829 } 830 831 /* save CSR information for the pressure BDDC solver (if any) */ 832 if (schp) { 833 PetscInt np,nt; 834 835 PetscCall(MatGetSize(matis->A,&nt,NULL)); 836 PetscCall(ISGetLocalSize(lP,&np)); 837 if (np) { 838 PetscInt *xadj = pcbddc->mat_graph->xadj; 839 PetscInt *adjn = pcbddc->mat_graph->adjncy; 840 PetscInt nv = pcbddc->mat_graph->nvtxs_csr; 841 842 if (nv && nv == nt) { 843 ISLocalToGlobalMapping pmap; 844 PetscInt *schp_csr,*schp_xadj,*schp_adjn,p; 845 PetscContainer c; 846 847 PetscCall(ISLocalToGlobalMappingCreateIS(lPall,&pmap)); 848 PetscCall(ISGetIndices(lPall,&idxs)); 849 for (p = 0, nv = 0; p < np; p++) { 850 PetscInt x,n = idxs[p]; 851 852 PetscCall(ISGlobalToLocalMappingApply(pmap,IS_GTOLM_DROP,xadj[n+1]-xadj[n],adjn+xadj[n],&x,NULL)); 853 nv += x; 854 } 855 PetscCall(PetscMalloc1(np + 1 + nv,&schp_csr)); 856 schp_xadj = schp_csr; 857 schp_adjn = schp_csr + np + 1; 858 for (p = 0, schp_xadj[0] = 0; p < np; p++) { 859 PetscInt x,n = idxs[p]; 860 861 PetscCall(ISGlobalToLocalMappingApply(pmap,IS_GTOLM_DROP,xadj[n+1]-xadj[n],adjn+xadj[n],&x,schp_adjn + schp_xadj[p])); 862 schp_xadj[p+1] = schp_xadj[p] + x; 863 } 864 PetscCall(ISRestoreIndices(lPall,&idxs)); 865 PetscCall(ISLocalToGlobalMappingDestroy(&pmap)); 866 PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&c)); 867 PetscCall(PetscContainerSetPointer(c,schp_csr)); 868 PetscCall(PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault)); 869 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pCSR",(PetscObject)c)); 870 PetscCall(PetscContainerDestroy(&c)); 871 872 } 873 } 874 } 875 PetscCall(ISDestroy(&lPall)); 876 PetscCall(ISDestroy(&lP)); 877 fetidp->pP = pP; 878 } 879 880 /* total number of selected pressure dofs */ 881 PetscCall(ISGetSize(fetidp->pP,&totP)); 882 883 /* Set operator for inner BDDC */ 884 if (totP || fetidp->rhs_flip) { 885 PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&nA)); 886 } else { 887 PetscCall(PetscObjectReference((PetscObject)A)); 888 nA = A; 889 } 890 if (fetidp->rhs_flip) { 891 PetscCall(MatDiagonalScale(nA,fetidp->rhs_flip,NULL)); 892 if (totP) { 893 Mat lA2; 894 895 PetscCall(MatISGetLocalMat(nA,&lA)); 896 PetscCall(MatDuplicate(lA,MAT_COPY_VALUES,&lA2)); 897 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",(PetscObject)lA2)); 898 PetscCall(MatDestroy(&lA2)); 899 } 900 } 901 902 if (totP) { 903 PetscCall(MatSetOption(nA,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE)); 904 PetscCall(MatZeroRowsColumnsIS(nA,fetidp->pP,1.,NULL,NULL)); 905 } else { 906 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_lA",NULL)); 907 } 908 PetscCall(MatGetNearNullSpace(Ap,&nnsp)); 909 if (!nnsp) { 910 PetscCall(MatGetNullSpace(Ap,&nnsp)); 911 } 912 if (!nnsp) { 913 PetscCall(MatGetNearNullSpace(A,&nnsp)); 914 } 915 if (!nnsp) { 916 PetscCall(MatGetNullSpace(A,&nnsp)); 917 } 918 PetscCall(MatSetNearNullSpace(nA,nnsp)); 919 PetscCall(PCSetOperators(fetidp->innerbddc,nA,nA)); 920 PetscCall(MatDestroy(&nA)); 921 922 /* non-zero rhs on interior dofs when applying the preconditioner */ 923 if (totP) pcbddc->switch_static = PETSC_TRUE; 924 925 /* if there are no interface pressures, set inner bddc flag for benign saddle point */ 926 if (!totP) { 927 pcbddc->benign_saddle_point = PETSC_TRUE; 928 pcbddc->compute_nonetflux = PETSC_TRUE; 929 } 930 931 /* Operators for pressure preconditioner */ 932 if (totP) { 933 /* Extract pressure block if needed */ 934 if (!pisz) { 935 Mat C; 936 IS nzrows = NULL; 937 938 PetscCall(MatCreateSubMatrix(A,fetidp->pP,fetidp->pP,MAT_INITIAL_MATRIX,&C)); 939 PetscCall(MatFindNonzeroRows(C,&nzrows)); 940 if (nzrows) { 941 PetscInt i; 942 943 PetscCall(ISGetSize(nzrows,&i)); 944 PetscCall(ISDestroy(&nzrows)); 945 if (!i) pisz = PETSC_TRUE; 946 } 947 if (!pisz) { 948 PetscCall(MatScale(C,-1.)); /* i.e. Almost Incompressible Elasticity, Stokes discretized with Q1xQ1_stabilized */ 949 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_C",(PetscObject)C)); 950 } 951 PetscCall(MatDestroy(&C)); 952 } 953 /* Divergence mat */ 954 if (!pcbddc->divudotp) { 955 Mat B; 956 IS P; 957 IS l2l = NULL; 958 PetscBool save; 959 960 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&P)); 961 if (!pisz) { 962 IS F,V; 963 PetscInt m,M; 964 965 PetscCall(MatGetOwnershipRange(A,&m,&M)); 966 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),M-m,m,1,&F)); 967 PetscCall(ISComplement(P,m,M,&V)); 968 PetscCall(MatCreateSubMatrix(A,P,V,MAT_INITIAL_MATRIX,&B)); 969 { 970 Mat_IS *Bmatis = (Mat_IS*)B->data; 971 PetscCall(PetscObjectReference((PetscObject)Bmatis->getsub_cis)); 972 l2l = Bmatis->getsub_cis; 973 } 974 PetscCall(ISDestroy(&V)); 975 PetscCall(ISDestroy(&F)); 976 } else { 977 PetscCall(MatCreateSubMatrix(A,P,NULL,MAT_INITIAL_MATRIX,&B)); 978 } 979 save = pcbddc->compute_nonetflux; /* SetDivergenceMat activates nonetflux computation */ 980 PetscCall(PCBDDCSetDivergenceMat(fetidp->innerbddc,B,PETSC_FALSE,l2l)); 981 pcbddc->compute_nonetflux = save; 982 PetscCall(MatDestroy(&B)); 983 PetscCall(ISDestroy(&l2l)); 984 } 985 if (A != Ap) { /* user has provided a different Pmat, this always superseeds the setter (TODO: is it OK?) */ 986 /* use monolithic operator, we restrict later */ 987 PetscCall(KSPFETIDPSetPressureOperator(ksp,Ap)); 988 } 989 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject*)&PPmat)); 990 991 /* PPmat not present, use some default choice */ 992 if (!PPmat) { 993 Mat C; 994 995 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_C",(PetscObject*)&C)); 996 if (!schp && C) { /* non-zero pressure block, most likely Almost Incompressible Elasticity */ 997 PetscCall(KSPFETIDPSetPressureOperator(ksp,C)); 998 } else if (!pisz && schp) { /* we need the whole pressure mass matrix to define the interface BDDC */ 999 IS P; 1000 1001 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&P)); 1002 PetscCall(MatCreateSubMatrix(A,P,P,MAT_INITIAL_MATRIX,&C)); 1003 PetscCall(MatScale(C,-1.)); 1004 PetscCall(KSPFETIDPSetPressureOperator(ksp,C)); 1005 PetscCall(MatDestroy(&C)); 1006 } else { /* identity (need to be scaled properly by the user using e.g. a Richardson method */ 1007 PetscInt nl; 1008 1009 PetscCall(ISGetLocalSize(fetidp->pP,&nl)); 1010 PetscCall(MatCreate(PetscObjectComm((PetscObject)ksp),&C)); 1011 PetscCall(MatSetSizes(C,nl,nl,totP,totP)); 1012 PetscCall(MatSetType(C,MATAIJ)); 1013 PetscCall(MatMPIAIJSetPreallocation(C,1,NULL,0,NULL)); 1014 PetscCall(MatSeqAIJSetPreallocation(C,1,NULL)); 1015 PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY)); 1016 PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY)); 1017 PetscCall(MatShift(C,1.)); 1018 PetscCall(KSPFETIDPSetPressureOperator(ksp,C)); 1019 PetscCall(MatDestroy(&C)); 1020 } 1021 } 1022 1023 /* Preconditioned operator for the pressure block */ 1024 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_PPmat",(PetscObject*)&PPmat)); 1025 if (PPmat) { 1026 Mat C; 1027 IS Pall; 1028 PetscInt AM,PAM,PAN,pam,pan,am,an,pl,pIl,pAg,pIg; 1029 1030 PetscCall(PetscObjectQuery((PetscObject)fetidp->innerbddc,"__KSPFETIDP_aP",(PetscObject*)&Pall)); 1031 PetscCall(MatGetSize(A,&AM,NULL)); 1032 PetscCall(MatGetSize(PPmat,&PAM,&PAN)); 1033 PetscCall(ISGetSize(Pall,&pAg)); 1034 PetscCall(ISGetSize(fetidp->pP,&pIg)); 1035 PetscCall(MatGetLocalSize(PPmat,&pam,&pan)); 1036 PetscCall(MatGetLocalSize(A,&am,&an)); 1037 PetscCall(ISGetLocalSize(Pall,&pIl)); 1038 PetscCall(ISGetLocalSize(fetidp->pP,&pl)); 1039 PetscCheck(PAM == PAN,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Pressure matrix must be square, unsupported %" PetscInt_FMT " x %" PetscInt_FMT,PAM,PAN); 1040 PetscCheck(pam == pan,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Local sizes of pressure matrix must be equal, unsupported %" PetscInt_FMT " x %" PetscInt_FMT,pam,pan); 1041 PetscCheck(pam == am || pam == pl || pam == pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local rows %" PetscInt_FMT " for pressure matrix! Supported are %" PetscInt_FMT ", %" PetscInt_FMT " or %" PetscInt_FMT,pam,am,pl,pIl); 1042 PetscCheck(pan == an || pan == pl || pan == pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local columns %" PetscInt_FMT " for pressure matrix! Supported are %" PetscInt_FMT ", %" PetscInt_FMT " or %" PetscInt_FMT,pan,an,pl,pIl); 1043 if (PAM == AM) { /* monolithic ordering, restrict to pressure */ 1044 if (schp) { 1045 PetscCall(MatCreateSubMatrix(PPmat,Pall,Pall,MAT_INITIAL_MATRIX,&C)); 1046 } else { 1047 PetscCall(MatCreateSubMatrix(PPmat,fetidp->pP,fetidp->pP,MAT_INITIAL_MATRIX,&C)); 1048 } 1049 } else if (pAg == PAM) { /* global ordering for pressure only */ 1050 if (!allp && !schp) { /* solving for interface pressure only */ 1051 IS restr; 1052 1053 PetscCall(ISRenumber(fetidp->pP,NULL,NULL,&restr)); 1054 PetscCall(MatCreateSubMatrix(PPmat,restr,restr,MAT_INITIAL_MATRIX,&C)); 1055 PetscCall(ISDestroy(&restr)); 1056 } else { 1057 PetscCall(PetscObjectReference((PetscObject)PPmat)); 1058 C = PPmat; 1059 } 1060 } else if (pIg == PAM) { /* global ordering for selected pressure only */ 1061 PetscCheck(!schp,PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Need the entire matrix"); 1062 PetscCall(PetscObjectReference((PetscObject)PPmat)); 1063 C = PPmat; 1064 } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Unable to use the pressure matrix"); 1065 1066 PetscCall(KSPFETIDPSetPressureOperator(ksp,C)); 1067 PetscCall(MatDestroy(&C)); 1068 } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Missing Pmat for pressure block"); 1069 } else { /* totP == 0 */ 1070 PetscCall(PetscObjectCompose((PetscObject)fetidp->innerbddc,"__KSPFETIDP_pP",NULL)); 1071 } 1072 } 1073 PetscFunctionReturn(0); 1074 } 1075 1076 static PetscErrorCode KSPSetUp_FETIDP(KSP ksp) 1077 { 1078 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1079 PC_BDDC *pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1080 PetscBool flg; 1081 1082 PetscFunctionBegin; 1083 PetscCall(KSPFETIDPSetUpOperators(ksp)); 1084 /* set up BDDC */ 1085 PetscCall(PCSetErrorIfFailure(fetidp->innerbddc,ksp->errorifnotconverged)); 1086 PetscCall(PCSetUp(fetidp->innerbddc)); 1087 /* FETI-DP as it is implemented needs an exact coarse solver */ 1088 if (pcbddc->coarse_ksp) { 1089 PetscCall(KSPSetTolerances(pcbddc->coarse_ksp,PETSC_SMALL,PETSC_SMALL,PETSC_DEFAULT,1000)); 1090 PetscCall(KSPSetNormType(pcbddc->coarse_ksp,KSP_NORM_DEFAULT)); 1091 } 1092 /* FETI-DP as it is implemented needs exact local Neumann solvers */ 1093 PetscCall(KSPSetTolerances(pcbddc->ksp_R,PETSC_SMALL,PETSC_SMALL,PETSC_DEFAULT,1000)); 1094 PetscCall(KSPSetNormType(pcbddc->ksp_R,KSP_NORM_DEFAULT)); 1095 1096 /* setup FETI-DP operators 1097 If fetidp->statechanged is true, we need to update the operators 1098 needed in the saddle-point case. This should be replaced 1099 by a better logic when the FETI-DP matrix and preconditioner will 1100 have their own classes */ 1101 if (pcbddc->new_primal_space || fetidp->statechanged) { 1102 Mat F; /* the FETI-DP matrix */ 1103 PC D; /* the FETI-DP preconditioner */ 1104 PetscCall(KSPReset(fetidp->innerksp)); 1105 PetscCall(PCBDDCCreateFETIDPOperators(fetidp->innerbddc,fetidp->fully_redundant,((PetscObject)ksp)->prefix,&F,&D)); 1106 PetscCall(KSPSetOperators(fetidp->innerksp,F,F)); 1107 PetscCall(KSPSetTolerances(fetidp->innerksp,ksp->rtol,ksp->abstol,ksp->divtol,ksp->max_it)); 1108 PetscCall(KSPSetPC(fetidp->innerksp,D)); 1109 PetscCall(PetscObjectIncrementTabLevel((PetscObject)D,(PetscObject)fetidp->innerksp,0)); 1110 PetscCall(KSPSetFromOptions(fetidp->innerksp)); 1111 PetscCall(MatCreateVecs(F,&(fetidp->innerksp)->vec_rhs,&(fetidp->innerksp)->vec_sol)); 1112 PetscCall(MatDestroy(&F)); 1113 PetscCall(PCDestroy(&D)); 1114 if (fetidp->check) { 1115 PetscViewer viewer; 1116 1117 if (!pcbddc->dbg_viewer) { 1118 viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)ksp)); 1119 } else { 1120 viewer = pcbddc->dbg_viewer; 1121 } 1122 PetscCall(KSPFETIDPCheckOperators(ksp,viewer)); 1123 } 1124 } 1125 fetidp->statechanged = PETSC_FALSE; 1126 pcbddc->new_primal_space = PETSC_FALSE; 1127 1128 /* propagate settings to the inner solve */ 1129 PetscCall(KSPGetComputeSingularValues(ksp,&flg)); 1130 PetscCall(KSPSetComputeSingularValues(fetidp->innerksp,flg)); 1131 if (ksp->res_hist) PetscCall(KSPSetResidualHistory(fetidp->innerksp,ksp->res_hist,ksp->res_hist_max,ksp->res_hist_reset)); 1132 PetscCall(KSPSetErrorIfNotConverged(fetidp->innerksp,ksp->errorifnotconverged)); 1133 PetscCall(KSPSetUp(fetidp->innerksp)); 1134 PetscFunctionReturn(0); 1135 } 1136 1137 static PetscErrorCode KSPSolve_FETIDP(KSP ksp) 1138 { 1139 Mat F,A; 1140 MatNullSpace nsp; 1141 Vec X,B,Xl,Bl; 1142 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1143 PC_BDDC *pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1144 KSPConvergedReason reason; 1145 PC pc; 1146 PCFailedReason pcreason; 1147 PetscInt hist_len; 1148 1149 PetscFunctionBegin; 1150 PetscCall(PetscCitationsRegister(citation,&cited)); 1151 if (fetidp->saddlepoint) { 1152 PetscCall(PetscCitationsRegister(citation2,&cited2)); 1153 } 1154 PetscCall(KSPGetOperators(ksp,&A,NULL)); 1155 PetscCall(KSPGetRhs(ksp,&B)); 1156 PetscCall(KSPGetSolution(ksp,&X)); 1157 PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL)); 1158 PetscCall(KSPGetRhs(fetidp->innerksp,&Bl)); 1159 PetscCall(KSPGetSolution(fetidp->innerksp,&Xl)); 1160 PetscCall(PCBDDCMatFETIDPGetRHS(F,B,Bl)); 1161 if (ksp->transpose_solve) { 1162 PetscCall(KSPSolveTranspose(fetidp->innerksp,Bl,Xl)); 1163 } else { 1164 PetscCall(KSPSolve(fetidp->innerksp,Bl,Xl)); 1165 } 1166 PetscCall(KSPGetConvergedReason(fetidp->innerksp,&reason)); 1167 PetscCall(KSPGetPC(fetidp->innerksp,&pc)); 1168 PetscCall(PCGetFailedReason(pc,&pcreason)); 1169 if ((reason < 0 && reason != KSP_DIVERGED_ITS) || pcreason) { 1170 PetscInt its; 1171 PetscCall(KSPGetIterationNumber(fetidp->innerksp,&its)); 1172 ksp->reason = KSP_DIVERGED_PC_FAILED; 1173 PetscCall(VecSetInf(Xl)); 1174 PetscCall(PetscInfo(ksp,"Inner KSP solve failed: %s %s at iteration %" PetscInt_FMT,KSPConvergedReasons[reason],PCFailedReasons[pcreason],its)); 1175 } 1176 PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,X)); 1177 PetscCall(MatGetNullSpace(A,&nsp)); 1178 if (nsp) PetscCall(MatNullSpaceRemove(nsp,X)); 1179 /* update ksp with stats from inner ksp */ 1180 PetscCall(KSPGetConvergedReason(fetidp->innerksp,&ksp->reason)); 1181 PetscCall(KSPGetIterationNumber(fetidp->innerksp,&ksp->its)); 1182 ksp->totalits += ksp->its; 1183 PetscCall(KSPGetResidualHistory(fetidp->innerksp,NULL,&hist_len)); 1184 ksp->res_hist_len = (size_t) hist_len; 1185 /* restore defaults for inner BDDC (Pre/PostSolve flags) */ 1186 pcbddc->temp_solution_used = PETSC_FALSE; 1187 pcbddc->rhs_change = PETSC_FALSE; 1188 pcbddc->exact_dirichlet_trick_app = PETSC_FALSE; 1189 PetscFunctionReturn(0); 1190 } 1191 1192 static PetscErrorCode KSPReset_FETIDP(KSP ksp) 1193 { 1194 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1195 PC_BDDC *pcbddc; 1196 1197 PetscFunctionBegin; 1198 PetscCall(ISDestroy(&fetidp->pP)); 1199 PetscCall(VecDestroy(&fetidp->rhs_flip)); 1200 /* avoid PCReset that does not take into account ref counting */ 1201 PetscCall(PCDestroy(&fetidp->innerbddc)); 1202 PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc)); 1203 PetscCall(PCSetType(fetidp->innerbddc,PCBDDC)); 1204 pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1205 pcbddc->symmetric_primal = PETSC_FALSE; 1206 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc)); 1207 PetscCall(KSPDestroy(&fetidp->innerksp)); 1208 fetidp->saddlepoint = PETSC_FALSE; 1209 fetidp->matstate = -1; 1210 fetidp->matnnzstate = -1; 1211 fetidp->statechanged = PETSC_TRUE; 1212 PetscFunctionReturn(0); 1213 } 1214 1215 static PetscErrorCode KSPDestroy_FETIDP(KSP ksp) 1216 { 1217 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1218 1219 PetscFunctionBegin; 1220 PetscCall(KSPReset_FETIDP(ksp)); 1221 PetscCall(PCDestroy(&fetidp->innerbddc)); 1222 PetscCall(KSPDestroy(&fetidp->innerksp)); 1223 PetscCall(PetscFree(fetidp->monctx)); 1224 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",NULL)); 1225 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",NULL)); 1226 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",NULL)); 1227 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",NULL)); 1228 PetscCall(PetscFree(ksp->data)); 1229 PetscFunctionReturn(0); 1230 } 1231 1232 static PetscErrorCode KSPView_FETIDP(KSP ksp,PetscViewer viewer) 1233 { 1234 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1235 PetscBool iascii; 1236 1237 PetscFunctionBegin; 1238 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 1239 if (iascii) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer," fully redundant: %d\n",fetidp->fully_redundant)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer," saddle point: %d\n",fetidp->saddlepoint)); 1242 PetscCall(PetscViewerASCIIPrintf(viewer,"Inner KSP solver details\n")); 1243 } 1244 PetscCall(PetscViewerASCIIPushTab(viewer)); 1245 PetscCall(KSPView(fetidp->innerksp,viewer)); 1246 PetscCall(PetscViewerASCIIPopTab(viewer)); 1247 if (iascii) { 1248 PetscCall(PetscViewerASCIIPrintf(viewer,"Inner BDDC solver details\n")); 1249 } 1250 PetscCall(PetscViewerASCIIPushTab(viewer)); 1251 PetscCall(PCView(fetidp->innerbddc,viewer)); 1252 PetscCall(PetscViewerASCIIPopTab(viewer)); 1253 PetscFunctionReturn(0); 1254 } 1255 1256 static PetscErrorCode KSPSetFromOptions_FETIDP(PetscOptionItems *PetscOptionsObject,KSP ksp) 1257 { 1258 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1259 1260 PetscFunctionBegin; 1261 /* set options prefixes for the inner objects, since the parent prefix will be valid at this point */ 1262 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerksp,((PetscObject)ksp)->prefix)); 1263 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerksp,"fetidp_")); 1264 if (!fetidp->userbddc) { 1265 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerbddc,((PetscObject)ksp)->prefix)); 1266 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerbddc,"fetidp_bddc_")); 1267 } 1268 PetscOptionsHeadBegin(PetscOptionsObject,"KSP FETIDP options"); 1269 PetscCall(PetscOptionsBool("-ksp_fetidp_fullyredundant","Use fully redundant multipliers","none",fetidp->fully_redundant,&fetidp->fully_redundant,NULL)); 1270 PetscCall(PetscOptionsBool("-ksp_fetidp_saddlepoint","Activates support for saddle-point problems",NULL,fetidp->saddlepoint,&fetidp->saddlepoint,NULL)); 1271 PetscCall(PetscOptionsBool("-ksp_fetidp_check","Activates verbose debugging output FETI-DP operators",NULL,fetidp->check,&fetidp->check,NULL)); 1272 PetscOptionsHeadEnd(); 1273 PetscCall(PCSetFromOptions(fetidp->innerbddc)); 1274 PetscFunctionReturn(0); 1275 } 1276 1277 /*MC 1278 KSPFETIDP - The FETI-DP method 1279 1280 This class implements the FETI-DP method [1]. 1281 The matrix for the KSP must be of type MATIS. 1282 The FETI-DP linear system (automatically generated constructing an internal PCBDDC object) is solved using an internal KSP object. 1283 1284 Options Database Keys: 1285 + -ksp_fetidp_fullyredundant <false> - use a fully redundant set of Lagrange multipliers 1286 . -ksp_fetidp_saddlepoint <false> - activates support for saddle point problems, see [2] 1287 . -ksp_fetidp_saddlepoint_flip <false> - usually, an incompressible Stokes problem is written as 1288 | A B^T | | v | = | f | 1289 | B 0 | | p | = | g | 1290 with B representing -\int_\Omega \nabla \cdot u q. 1291 If -ksp_fetidp_saddlepoint_flip is true, the code assumes that the user provides it as 1292 | A B^T | | v | = | f | 1293 |-B 0 | | p | = |-g | 1294 . -ksp_fetidp_pressure_field <-1> - activates support for saddle point problems, and identifies the pressure field id. 1295 If this information is not provided, the pressure field is detected by using MatFindZeroDiagonals(). 1296 - -ksp_fetidp_pressure_all <false> - if false, uses the interface pressures, as described in [2]. If true, uses the entire pressure field. 1297 1298 Level: Advanced 1299 1300 Notes: 1301 Options for the inner KSP and for the customization of the PCBDDC object can be specified at command line by using the prefixes -fetidp_ and -fetidp_bddc_. E.g., 1302 .vb 1303 -fetidp_ksp_type gmres -fetidp_bddc_pc_bddc_symmetric false 1304 .ve 1305 will use GMRES for the solution of the linear system on the Lagrange multipliers, generated using a non-symmetric PCBDDC. 1306 1307 For saddle point problems with continuous pressures, the preconditioned operator for the pressure solver can be specified with KSPFETIDPSetPressureOperator(). 1308 Alternatively, the pressure operator is extracted from the precondioned matrix (if it is different from the linear solver matrix). 1309 If none of the above, an identity matrix will be created; the user then needs to scale it through a Richardson solver. 1310 Options for the pressure solver can be prefixed with -fetidp_fielsplit_p_, E.g. 1311 .vb 1312 -fetidp_fielsplit_p_ksp_type preonly -fetidp_fielsplit_p_pc_type lu -fetidp_fielsplit_p_pc_factor_mat_solver_type mumps 1313 .ve 1314 In order to use the deluxe version of FETI-DP, you must customize the inner BDDC operator with -fetidp_bddc_pc_bddc_use_deluxe_scaling -fetidp_bddc_pc_bddc_deluxe_singlemat and use 1315 non-redundant multipliers, i.e. -ksp_fetidp_fullyredundant false. Options for the scaling solver are prefixed by -fetidp_bddelta_, E.g. 1316 .vb 1317 -fetidp_bddelta_pc_factor_mat_solver_type mumps -fetidp_bddelta_pc_type lu 1318 .ve 1319 1320 Some of the basic options such as the maximum number of iterations and tolerances are automatically passed from this KSP to the inner KSP that actually performs the iterations. 1321 1322 The converged reason and number of iterations computed are passed from the inner KSP to this KSP at the end of the solution. 1323 1324 Developer Notes: 1325 Even though this method does not directly use any norms, the user is allowed to set the KSPNormType to any value. 1326 This is so users do not have to change KSPNormType options when they switch from other KSP methods to this one. 1327 1328 References: 1329 + * - C. Farhat, M. Lesoinne, P. LeTallec, K. Pierson, and D. Rixen, FETI-DP: a dual-primal unified FETI method. I. A faster alternative to the two-level FETI method, Internat. J. Numer. Methods Engrg., 50 (2001), pp. 1523--1544 1330 - * - X. Tu, J. Li, A FETI-DP type domain decomposition algorithm for three-dimensional incompressible Stokes equations, SIAM J. Numer. Anal., 53 (2015), pp. 720-742 1331 1332 .seealso: `MATIS`, `PCBDDC`, `KSPFETIDPSetInnerBDDC()`, `KSPFETIDPGetInnerBDDC()`, `KSPFETIDPGetInnerKSP()` 1333 M*/ 1334 PETSC_EXTERN PetscErrorCode KSPCreate_FETIDP(KSP ksp) 1335 { 1336 KSP_FETIDP *fetidp; 1337 KSP_FETIDPMon *monctx; 1338 PC_BDDC *pcbddc; 1339 PC pc; 1340 1341 PetscFunctionBegin; 1342 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,3)); 1343 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_RIGHT,2)); 1344 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2)); 1345 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_RIGHT,2)); 1346 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,2)); 1347 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_RIGHT,2)); 1348 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,2)); 1349 1350 PetscCall(PetscNewLog(ksp,&fetidp)); 1351 fetidp->matstate = -1; 1352 fetidp->matnnzstate = -1; 1353 fetidp->statechanged = PETSC_TRUE; 1354 1355 ksp->data = (void*)fetidp; 1356 ksp->ops->setup = KSPSetUp_FETIDP; 1357 ksp->ops->solve = KSPSolve_FETIDP; 1358 ksp->ops->destroy = KSPDestroy_FETIDP; 1359 ksp->ops->computeeigenvalues = KSPComputeEigenvalues_FETIDP; 1360 ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_FETIDP; 1361 ksp->ops->view = KSPView_FETIDP; 1362 ksp->ops->setfromoptions = KSPSetFromOptions_FETIDP; 1363 ksp->ops->buildsolution = KSPBuildSolution_FETIDP; 1364 ksp->ops->buildresidual = KSPBuildResidualDefault; 1365 PetscCall(KSPGetPC(ksp,&pc)); 1366 PetscCall(PCSetType(pc,PCNONE)); 1367 /* create the inner KSP for the Lagrange multipliers */ 1368 PetscCall(KSPCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerksp)); 1369 PetscCall(KSPGetPC(fetidp->innerksp,&pc)); 1370 PetscCall(PCSetType(pc,PCNONE)); 1371 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerksp)); 1372 /* monitor */ 1373 PetscCall(PetscNew(&monctx)); 1374 monctx->parentksp = ksp; 1375 fetidp->monctx = monctx; 1376 PetscCall(KSPMonitorSet(fetidp->innerksp,KSPMonitor_FETIDP,fetidp->monctx,NULL)); 1377 /* create the inner BDDC */ 1378 PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc)); 1379 PetscCall(PCSetType(fetidp->innerbddc,PCBDDC)); 1380 /* make sure we always obtain a consistent FETI-DP matrix 1381 for symmetric problems, the user can always customize it through the command line */ 1382 pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1383 pcbddc->symmetric_primal = PETSC_FALSE; 1384 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc)); 1385 /* composed functions */ 1386 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",KSPFETIDPSetInnerBDDC_FETIDP)); 1387 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",KSPFETIDPGetInnerBDDC_FETIDP)); 1388 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",KSPFETIDPGetInnerKSP_FETIDP)); 1389 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",KSPFETIDPSetPressureOperator_FETIDP)); 1390 /* need to call KSPSetUp_FETIDP even with KSP_SETUP_NEWMATRIX */ 1391 ksp->setupnewmatrix = PETSC_TRUE; 1392 PetscFunctionReturn(0); 1393 } 1394