1 #include <petsc/private/kspimpl.h> /*I <petscksp.h> I*/ 2 #include <../src/ksp/pc/impls/bddc/bddc.h> 3 #include <../src/ksp/pc/impls/bddc/bddcprivate.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",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",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",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",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",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,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",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",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 PetscCheckFalse(fid < 0 || fid >= pcbddc->n_ISForDofsLocal,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %D, max %D",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 PetscCheckFalse(fid < 0 || fid >= pcbddc->n_ISForDofs,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Invalid field id for pressure %D, max %D",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 %D and %D 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 %D x %D",PAM,PAN); 1040 PetscCheck(pam == pan,PetscObjectComm((PetscObject)ksp),PETSC_ERR_USER,"Local sizes of pressure matrix must be equal, unsupported %D x %D",pam,pan); 1041 PetscCheckFalse(pam != am && pam != pl && pam != pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local rows %D for pressure matrix! Supported are %D, %D or %D",pam,am,pl,pIl); 1042 PetscCheckFalse(pan != an && pan != pl && pan != pIl,PETSC_COMM_SELF,PETSC_ERR_USER,"Invalid number of local columns %D for pressure matrix! Supported are %D, %D or %D",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) { 1132 PetscCall(KSPSetResidualHistory(fetidp->innerksp,ksp->res_hist,ksp->res_hist_max,ksp->res_hist_reset)); 1133 } 1134 PetscCall(KSPSetErrorIfNotConverged(fetidp->innerksp,ksp->errorifnotconverged)); 1135 PetscCall(KSPSetUp(fetidp->innerksp)); 1136 PetscFunctionReturn(0); 1137 } 1138 1139 static PetscErrorCode KSPSolve_FETIDP(KSP ksp) 1140 { 1141 Mat F,A; 1142 MatNullSpace nsp; 1143 Vec X,B,Xl,Bl; 1144 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1145 PC_BDDC *pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1146 KSPConvergedReason reason; 1147 PC pc; 1148 PCFailedReason pcreason; 1149 PetscInt hist_len; 1150 1151 PetscFunctionBegin; 1152 PetscCall(PetscCitationsRegister(citation,&cited)); 1153 if (fetidp->saddlepoint) { 1154 PetscCall(PetscCitationsRegister(citation2,&cited2)); 1155 } 1156 PetscCall(KSPGetOperators(ksp,&A,NULL)); 1157 PetscCall(KSPGetRhs(ksp,&B)); 1158 PetscCall(KSPGetSolution(ksp,&X)); 1159 PetscCall(KSPGetOperators(fetidp->innerksp,&F,NULL)); 1160 PetscCall(KSPGetRhs(fetidp->innerksp,&Bl)); 1161 PetscCall(KSPGetSolution(fetidp->innerksp,&Xl)); 1162 PetscCall(PCBDDCMatFETIDPGetRHS(F,B,Bl)); 1163 if (ksp->transpose_solve) { 1164 PetscCall(KSPSolveTranspose(fetidp->innerksp,Bl,Xl)); 1165 } else { 1166 PetscCall(KSPSolve(fetidp->innerksp,Bl,Xl)); 1167 } 1168 PetscCall(KSPGetConvergedReason(fetidp->innerksp,&reason)); 1169 PetscCall(KSPGetPC(fetidp->innerksp,&pc)); 1170 PetscCall(PCGetFailedReason(pc,&pcreason)); 1171 if ((reason < 0 && reason != KSP_DIVERGED_ITS) || pcreason) { 1172 PetscInt its; 1173 PetscCall(KSPGetIterationNumber(fetidp->innerksp,&its)); 1174 ksp->reason = KSP_DIVERGED_PC_FAILED; 1175 PetscCall(VecSetInf(Xl)); 1176 PetscCall(PetscInfo(ksp,"Inner KSP solve failed: %s %s at iteration %D",KSPConvergedReasons[reason],PCFailedReasons[pcreason],its)); 1177 } 1178 PetscCall(PCBDDCMatFETIDPGetSolution(F,Xl,X)); 1179 PetscCall(MatGetNullSpace(A,&nsp)); 1180 if (nsp) { 1181 PetscCall(MatNullSpaceRemove(nsp,X)); 1182 } 1183 /* update ksp with stats from inner ksp */ 1184 PetscCall(KSPGetConvergedReason(fetidp->innerksp,&ksp->reason)); 1185 PetscCall(KSPGetIterationNumber(fetidp->innerksp,&ksp->its)); 1186 ksp->totalits += ksp->its; 1187 PetscCall(KSPGetResidualHistory(fetidp->innerksp,NULL,&hist_len)); 1188 ksp->res_hist_len = (size_t) hist_len; 1189 /* restore defaults for inner BDDC (Pre/PostSolve flags) */ 1190 pcbddc->temp_solution_used = PETSC_FALSE; 1191 pcbddc->rhs_change = PETSC_FALSE; 1192 pcbddc->exact_dirichlet_trick_app = PETSC_FALSE; 1193 PetscFunctionReturn(0); 1194 } 1195 1196 static PetscErrorCode KSPReset_FETIDP(KSP ksp) 1197 { 1198 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1199 PC_BDDC *pcbddc; 1200 1201 PetscFunctionBegin; 1202 PetscCall(ISDestroy(&fetidp->pP)); 1203 PetscCall(VecDestroy(&fetidp->rhs_flip)); 1204 /* avoid PCReset that does not take into account ref counting */ 1205 PetscCall(PCDestroy(&fetidp->innerbddc)); 1206 PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc)); 1207 PetscCall(PCSetType(fetidp->innerbddc,PCBDDC)); 1208 pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1209 pcbddc->symmetric_primal = PETSC_FALSE; 1210 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc)); 1211 PetscCall(KSPDestroy(&fetidp->innerksp)); 1212 fetidp->saddlepoint = PETSC_FALSE; 1213 fetidp->matstate = -1; 1214 fetidp->matnnzstate = -1; 1215 fetidp->statechanged = PETSC_TRUE; 1216 PetscFunctionReturn(0); 1217 } 1218 1219 static PetscErrorCode KSPDestroy_FETIDP(KSP ksp) 1220 { 1221 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1222 1223 PetscFunctionBegin; 1224 PetscCall(KSPReset_FETIDP(ksp)); 1225 PetscCall(PCDestroy(&fetidp->innerbddc)); 1226 PetscCall(KSPDestroy(&fetidp->innerksp)); 1227 PetscCall(PetscFree(fetidp->monctx)); 1228 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",NULL)); 1229 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",NULL)); 1230 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",NULL)); 1231 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",NULL)); 1232 PetscCall(PetscFree(ksp->data)); 1233 PetscFunctionReturn(0); 1234 } 1235 1236 static PetscErrorCode KSPView_FETIDP(KSP ksp,PetscViewer viewer) 1237 { 1238 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1239 PetscBool iascii; 1240 1241 PetscFunctionBegin; 1242 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 1243 if (iascii) { 1244 PetscCall(PetscViewerASCIIPrintf(viewer," fully redundant: %d\n",fetidp->fully_redundant)); 1245 PetscCall(PetscViewerASCIIPrintf(viewer," saddle point: %d\n",fetidp->saddlepoint)); 1246 PetscCall(PetscViewerASCIIPrintf(viewer,"Inner KSP solver details\n")); 1247 } 1248 PetscCall(PetscViewerASCIIPushTab(viewer)); 1249 PetscCall(KSPView(fetidp->innerksp,viewer)); 1250 PetscCall(PetscViewerASCIIPopTab(viewer)); 1251 if (iascii) { 1252 PetscCall(PetscViewerASCIIPrintf(viewer,"Inner BDDC solver details\n")); 1253 } 1254 PetscCall(PetscViewerASCIIPushTab(viewer)); 1255 PetscCall(PCView(fetidp->innerbddc,viewer)); 1256 PetscCall(PetscViewerASCIIPopTab(viewer)); 1257 PetscFunctionReturn(0); 1258 } 1259 1260 static PetscErrorCode KSPSetFromOptions_FETIDP(PetscOptionItems *PetscOptionsObject,KSP ksp) 1261 { 1262 KSP_FETIDP *fetidp = (KSP_FETIDP*)ksp->data; 1263 1264 PetscFunctionBegin; 1265 /* set options prefixes for the inner objects, since the parent prefix will be valid at this point */ 1266 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerksp,((PetscObject)ksp)->prefix)); 1267 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerksp,"fetidp_")); 1268 if (!fetidp->userbddc) { 1269 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fetidp->innerbddc,((PetscObject)ksp)->prefix)); 1270 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)fetidp->innerbddc,"fetidp_bddc_")); 1271 } 1272 PetscOptionsHeadBegin(PetscOptionsObject,"KSP FETIDP options"); 1273 PetscCall(PetscOptionsBool("-ksp_fetidp_fullyredundant","Use fully redundant multipliers","none",fetidp->fully_redundant,&fetidp->fully_redundant,NULL)); 1274 PetscCall(PetscOptionsBool("-ksp_fetidp_saddlepoint","Activates support for saddle-point problems",NULL,fetidp->saddlepoint,&fetidp->saddlepoint,NULL)); 1275 PetscCall(PetscOptionsBool("-ksp_fetidp_check","Activates verbose debugging output FETI-DP operators",NULL,fetidp->check,&fetidp->check,NULL)); 1276 PetscOptionsHeadEnd(); 1277 PetscCall(PCSetFromOptions(fetidp->innerbddc)); 1278 PetscFunctionReturn(0); 1279 } 1280 1281 /*MC 1282 KSPFETIDP - The FETI-DP method 1283 1284 This class implements the FETI-DP method [1]. 1285 The matrix for the KSP must be of type MATIS. 1286 The FETI-DP linear system (automatically generated constructing an internal PCBDDC object) is solved using an internal KSP object. 1287 1288 Options Database Keys: 1289 + -ksp_fetidp_fullyredundant <false> - use a fully redundant set of Lagrange multipliers 1290 . -ksp_fetidp_saddlepoint <false> - activates support for saddle point problems, see [2] 1291 . -ksp_fetidp_saddlepoint_flip <false> - usually, an incompressible Stokes problem is written as 1292 | A B^T | | v | = | f | 1293 | B 0 | | p | = | g | 1294 with B representing -\int_\Omega \nabla \cdot u q. 1295 If -ksp_fetidp_saddlepoint_flip is true, the code assumes that the user provides it as 1296 | A B^T | | v | = | f | 1297 |-B 0 | | p | = |-g | 1298 . -ksp_fetidp_pressure_field <-1> - activates support for saddle point problems, and identifies the pressure field id. 1299 If this information is not provided, the pressure field is detected by using MatFindZeroDiagonals(). 1300 - -ksp_fetidp_pressure_all <false> - if false, uses the interface pressures, as described in [2]. If true, uses the entire pressure field. 1301 1302 Level: Advanced 1303 1304 Notes: 1305 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., 1306 .vb 1307 -fetidp_ksp_type gmres -fetidp_bddc_pc_bddc_symmetric false 1308 .ve 1309 will use GMRES for the solution of the linear system on the Lagrange multipliers, generated using a non-symmetric PCBDDC. 1310 1311 For saddle point problems with continuous pressures, the preconditioned operator for the pressure solver can be specified with KSPFETIDPSetPressureOperator(). 1312 Alternatively, the pressure operator is extracted from the precondioned matrix (if it is different from the linear solver matrix). 1313 If none of the above, an identity matrix will be created; the user then needs to scale it through a Richardson solver. 1314 Options for the pressure solver can be prefixed with -fetidp_fielsplit_p_, E.g. 1315 .vb 1316 -fetidp_fielsplit_p_ksp_type preonly -fetidp_fielsplit_p_pc_type lu -fetidp_fielsplit_p_pc_factor_mat_solver_type mumps 1317 .ve 1318 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 1319 non-redundant multipliers, i.e. -ksp_fetidp_fullyredundant false. Options for the scaling solver are prefixed by -fetidp_bddelta_, E.g. 1320 .vb 1321 -fetidp_bddelta_pc_factor_mat_solver_type mumps -fetidp_bddelta_pc_type lu 1322 .ve 1323 1324 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. 1325 1326 The converged reason and number of iterations computed are passed from the inner KSP to this KSP at the end of the solution. 1327 1328 Developer Notes: 1329 Even though this method does not directly use any norms, the user is allowed to set the KSPNormType to any value. 1330 This is so users do not have to change KSPNormType options when they switch from other KSP methods to this one. 1331 1332 References: 1333 + * - 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 1334 - * - 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 1335 1336 .seealso: MATIS, PCBDDC, KSPFETIDPSetInnerBDDC(), KSPFETIDPGetInnerBDDC(), KSPFETIDPGetInnerKSP() 1337 M*/ 1338 PETSC_EXTERN PetscErrorCode KSPCreate_FETIDP(KSP ksp) 1339 { 1340 KSP_FETIDP *fetidp; 1341 KSP_FETIDPMon *monctx; 1342 PC_BDDC *pcbddc; 1343 PC pc; 1344 1345 PetscFunctionBegin; 1346 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,3)); 1347 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_RIGHT,2)); 1348 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2)); 1349 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_RIGHT,2)); 1350 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,2)); 1351 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_RIGHT,2)); 1352 PetscCall(KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,2)); 1353 1354 PetscCall(PetscNewLog(ksp,&fetidp)); 1355 fetidp->matstate = -1; 1356 fetidp->matnnzstate = -1; 1357 fetidp->statechanged = PETSC_TRUE; 1358 1359 ksp->data = (void*)fetidp; 1360 ksp->ops->setup = KSPSetUp_FETIDP; 1361 ksp->ops->solve = KSPSolve_FETIDP; 1362 ksp->ops->destroy = KSPDestroy_FETIDP; 1363 ksp->ops->computeeigenvalues = KSPComputeEigenvalues_FETIDP; 1364 ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_FETIDP; 1365 ksp->ops->view = KSPView_FETIDP; 1366 ksp->ops->setfromoptions = KSPSetFromOptions_FETIDP; 1367 ksp->ops->buildsolution = KSPBuildSolution_FETIDP; 1368 ksp->ops->buildresidual = KSPBuildResidualDefault; 1369 PetscCall(KSPGetPC(ksp,&pc)); 1370 PetscCall(PCSetType(pc,PCNONE)); 1371 /* create the inner KSP for the Lagrange multipliers */ 1372 PetscCall(KSPCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerksp)); 1373 PetscCall(KSPGetPC(fetidp->innerksp,&pc)); 1374 PetscCall(PCSetType(pc,PCNONE)); 1375 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerksp)); 1376 /* monitor */ 1377 PetscCall(PetscNew(&monctx)); 1378 monctx->parentksp = ksp; 1379 fetidp->monctx = monctx; 1380 PetscCall(KSPMonitorSet(fetidp->innerksp,KSPMonitor_FETIDP,fetidp->monctx,NULL)); 1381 /* create the inner BDDC */ 1382 PetscCall(PCCreate(PetscObjectComm((PetscObject)ksp),&fetidp->innerbddc)); 1383 PetscCall(PCSetType(fetidp->innerbddc,PCBDDC)); 1384 /* make sure we always obtain a consistent FETI-DP matrix 1385 for symmetric problems, the user can always customize it through the command line */ 1386 pcbddc = (PC_BDDC*)fetidp->innerbddc->data; 1387 pcbddc->symmetric_primal = PETSC_FALSE; 1388 PetscCall(PetscLogObjectParent((PetscObject)ksp,(PetscObject)fetidp->innerbddc)); 1389 /* composed functions */ 1390 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetInnerBDDC_C",KSPFETIDPSetInnerBDDC_FETIDP)); 1391 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerBDDC_C",KSPFETIDPGetInnerBDDC_FETIDP)); 1392 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPGetInnerKSP_C",KSPFETIDPGetInnerKSP_FETIDP)); 1393 PetscCall(PetscObjectComposeFunction((PetscObject)ksp,"KSPFETIDPSetPressureOperator_C",KSPFETIDPSetPressureOperator_FETIDP)); 1394 /* need to call KSPSetUp_FETIDP even with KSP_SETUP_NEWMATRIX */ 1395 ksp->setupnewmatrix = PETSC_TRUE; 1396 PetscFunctionReturn(0); 1397 } 1398