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