1 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 2 #include <petsc/private/kspimpl.h> /* This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/ 3 #include <petscdm.h> 4 5 const char *const PCFieldSplitSchurPreTypes[] = {"SELF", "SELFP", "A11", "USER", "FULL", "PCFieldSplitSchurPreType", "PC_FIELDSPLIT_SCHUR_PRE_", NULL}; 6 const char *const PCFieldSplitSchurFactTypes[] = {"DIAG", "LOWER", "UPPER", "FULL", "PCFieldSplitSchurFactType", "PC_FIELDSPLIT_SCHUR_FACT_", NULL}; 7 8 PetscLogEvent KSP_Solve_FS_0, KSP_Solve_FS_1, KSP_Solve_FS_S, KSP_Solve_FS_U, KSP_Solve_FS_L, KSP_Solve_FS_2, KSP_Solve_FS_3, KSP_Solve_FS_4; 9 10 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 11 struct _PC_FieldSplitLink { 12 KSP ksp; 13 Vec x, y, z; 14 char *splitname; 15 PetscInt nfields; 16 PetscInt *fields, *fields_col; 17 VecScatter sctx; 18 IS is, is_col; 19 PC_FieldSplitLink next, previous; 20 PetscLogEvent event; 21 22 /* Used only when setting coordinates with PCSetCoordinates */ 23 PetscInt dim; 24 PetscInt ndofs; 25 PetscReal *coords; 26 }; 27 28 typedef struct { 29 PCCompositeType type; 30 PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 31 PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */ 32 PetscInt bs; /* Block size for IS and Mat structures */ 33 PetscInt nsplits; /* Number of field divisions defined */ 34 Vec *x, *y, w1, w2; 35 Mat *mat; /* The diagonal block for each split */ 36 Mat *pmat; /* The preconditioning diagonal block for each split */ 37 Mat *Afield; /* The rows of the matrix associated with each split */ 38 PetscBool issetup; 39 40 /* Only used when Schur complement preconditioning is used */ 41 Mat B; /* The (0,1) block */ 42 Mat C; /* The (1,0) block */ 43 Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */ 44 Mat schurp; /* Assembled approximation to S built by MatSchurComplement to be used as a preconditioning matrix when solving with S */ 45 Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */ 46 PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */ 47 PCFieldSplitSchurFactType schurfactorization; 48 KSP kspschur; /* The solver for S */ 49 KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */ 50 PetscScalar schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */ 51 52 /* Only used when Golub-Kahan bidiagonalization preconditioning is used */ 53 Mat H; /* The modified matrix H = A00 + nu*A01*A01' */ 54 PetscReal gkbtol; /* Stopping tolerance for lower bound estimate */ 55 PetscInt gkbdelay; /* The delay window for the stopping criterion */ 56 PetscReal gkbnu; /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */ 57 PetscInt gkbmaxit; /* Maximum number of iterations for outer loop */ 58 PetscBool gkbmonitor; /* Monitor for gkb iterations and the lower bound error */ 59 PetscViewer gkbviewer; /* Viewer context for gkbmonitor */ 60 Vec u, v, d, Hu; /* Work vectors for the GKB algorithm */ 61 PetscScalar *vecz; /* Contains intermediate values, eg for lower bound */ 62 63 PC_FieldSplitLink head; 64 PetscBool isrestrict; /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */ 65 PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */ 66 PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */ 67 PetscBool diag_use_amat; /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 68 PetscBool offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 69 PetscBool detect; /* Whether to form 2-way split by finding zero diagonal entries */ 70 PetscBool coordinates_set; /* Whether PCSetCoordinates has been called */ 71 } PC_FieldSplit; 72 73 /* 74 Note: 75 there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 76 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 77 PC you could change this. 78 */ 79 80 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 81 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 82 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 83 { 84 switch (jac->schurpre) { 85 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 86 return jac->schur; 87 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: 88 return jac->schurp; 89 case PC_FIELDSPLIT_SCHUR_PRE_A11: 90 return jac->pmat[1]; 91 case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */ 92 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 93 default: 94 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 95 } 96 } 97 98 #include <petscdraw.h> 99 static PetscErrorCode PCView_FieldSplit(PC pc, PetscViewer viewer) 100 { 101 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 102 PetscBool iascii, isdraw; 103 PetscInt i, j; 104 PC_FieldSplitLink ilink = jac->head; 105 106 PetscFunctionBegin; 107 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 108 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 109 if (iascii) { 110 if (jac->bs > 0) { 111 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs)); 112 } else { 113 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits)); 114 } 115 if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n")); 116 if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for diagonal blocks\n")); 117 if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for off-diagonal blocks\n")); 118 PetscCall(PetscViewerASCIIPrintf(viewer, " Solver info for each split is in the following KSP objects:\n")); 119 for (i = 0; i < jac->nsplits; i++) { 120 if (ilink->fields) { 121 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i)); 122 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 123 for (j = 0; j < ilink->nfields; j++) { 124 if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ",")); 125 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j])); 126 } 127 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 128 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 129 } else { 130 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i)); 131 } 132 PetscCall(KSPView(ilink->ksp, viewer)); 133 ilink = ilink->next; 134 } 135 } 136 137 if (isdraw) { 138 PetscDraw draw; 139 PetscReal x, y, w, wd; 140 141 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 142 PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 143 w = 2 * PetscMin(1.0 - x, x); 144 wd = w / (jac->nsplits + 1); 145 x = x - wd * (jac->nsplits - 1) / 2.0; 146 for (i = 0; i < jac->nsplits; i++) { 147 PetscCall(PetscDrawPushCurrentPoint(draw, x, y)); 148 PetscCall(KSPView(ilink->ksp, viewer)); 149 PetscCall(PetscDrawPopCurrentPoint(draw)); 150 x += wd; 151 ilink = ilink->next; 152 } 153 } 154 PetscFunctionReturn(PETSC_SUCCESS); 155 } 156 157 static PetscErrorCode PCView_FieldSplit_Schur(PC pc, PetscViewer viewer) 158 { 159 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 160 PetscBool iascii, isdraw; 161 PetscInt i, j; 162 PC_FieldSplitLink ilink = jac->head; 163 MatSchurComplementAinvType atype; 164 165 PetscFunctionBegin; 166 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 167 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 168 if (iascii) { 169 if (jac->bs > 0) { 170 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with Schur preconditioner, blocksize = %" PetscInt_FMT ", factorization %s\n", jac->bs, PCFieldSplitSchurFactTypes[jac->schurfactorization])); 171 } else { 172 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with Schur preconditioner, factorization %s\n", PCFieldSplitSchurFactTypes[jac->schurfactorization])); 173 } 174 if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n")); 175 switch (jac->schurpre) { 176 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 177 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from S itself\n")); 178 break; 179 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: 180 if (jac->schur) { 181 PetscCall(MatSchurComplementGetAinvType(jac->schur, &atype)); 182 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from Sp, an assembled approximation to S, which uses A00's %sinverse\n", atype == MAT_SCHUR_COMPLEMENT_AINV_DIAG ? "diagonal's " : (atype == MAT_SCHUR_COMPLEMENT_AINV_BLOCK_DIAG ? "block diagonal's " : (atype == MAT_SCHUR_COMPLEMENT_AINV_FULL ? "full " : "lumped diagonal's ")))); 183 } 184 break; 185 case PC_FIELDSPLIT_SCHUR_PRE_A11: 186 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from A11\n")); 187 break; 188 case PC_FIELDSPLIT_SCHUR_PRE_FULL: 189 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from the exact Schur complement\n")); 190 break; 191 case PC_FIELDSPLIT_SCHUR_PRE_USER: 192 if (jac->schur_user) { 193 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from user provided matrix\n")); 194 } else { 195 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from A11\n")); 196 } 197 break; 198 default: 199 SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre); 200 } 201 PetscCall(PetscViewerASCIIPrintf(viewer, " Split info:\n")); 202 PetscCall(PetscViewerASCIIPushTab(viewer)); 203 for (i = 0; i < jac->nsplits; i++) { 204 if (ilink->fields) { 205 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i)); 206 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 207 for (j = 0; j < ilink->nfields; j++) { 208 if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ",")); 209 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j])); 210 } 211 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 212 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 213 } else { 214 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i)); 215 } 216 ilink = ilink->next; 217 } 218 PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for A00 block\n")); 219 PetscCall(PetscViewerASCIIPushTab(viewer)); 220 if (jac->head) { 221 PetscCall(KSPView(jac->head->ksp, viewer)); 222 } else PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n")); 223 PetscCall(PetscViewerASCIIPopTab(viewer)); 224 if (jac->head && jac->kspupper != jac->head->ksp) { 225 PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for upper A00 in upper triangular factor\n")); 226 PetscCall(PetscViewerASCIIPushTab(viewer)); 227 if (jac->kspupper) PetscCall(KSPView(jac->kspupper, viewer)); 228 else PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n")); 229 PetscCall(PetscViewerASCIIPopTab(viewer)); 230 } 231 PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for S = A11 - A10 inv(A00) A01\n")); 232 PetscCall(PetscViewerASCIIPushTab(viewer)); 233 if (jac->kspschur) { 234 PetscCall(KSPView(jac->kspschur, viewer)); 235 } else { 236 PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n")); 237 } 238 PetscCall(PetscViewerASCIIPopTab(viewer)); 239 PetscCall(PetscViewerASCIIPopTab(viewer)); 240 } else if (isdraw && jac->head) { 241 PetscDraw draw; 242 PetscReal x, y, w, wd, h; 243 PetscInt cnt = 2; 244 char str[32]; 245 246 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 247 PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 248 if (jac->kspupper != jac->head->ksp) cnt++; 249 w = 2 * PetscMin(1.0 - x, x); 250 wd = w / (cnt + 1); 251 252 PetscCall(PetscSNPrintf(str, 32, "Schur fact. %s", PCFieldSplitSchurFactTypes[jac->schurfactorization])); 253 PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h)); 254 y -= h; 255 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) { 256 PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11])); 257 } else { 258 PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[jac->schurpre])); 259 } 260 PetscCall(PetscDrawStringBoxed(draw, x + wd * (cnt - 1) / 2.0, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h)); 261 y -= h; 262 x = x - wd * (cnt - 1) / 2.0; 263 264 PetscCall(PetscDrawPushCurrentPoint(draw, x, y)); 265 PetscCall(KSPView(jac->head->ksp, viewer)); 266 PetscCall(PetscDrawPopCurrentPoint(draw)); 267 if (jac->kspupper != jac->head->ksp) { 268 x += wd; 269 PetscCall(PetscDrawPushCurrentPoint(draw, x, y)); 270 PetscCall(KSPView(jac->kspupper, viewer)); 271 PetscCall(PetscDrawPopCurrentPoint(draw)); 272 } 273 x += wd; 274 PetscCall(PetscDrawPushCurrentPoint(draw, x, y)); 275 PetscCall(KSPView(jac->kspschur, viewer)); 276 PetscCall(PetscDrawPopCurrentPoint(draw)); 277 } 278 PetscFunctionReturn(PETSC_SUCCESS); 279 } 280 281 static PetscErrorCode PCView_FieldSplit_GKB(PC pc, PetscViewer viewer) 282 { 283 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 284 PetscBool iascii, isdraw; 285 PetscInt i, j; 286 PC_FieldSplitLink ilink = jac->head; 287 288 PetscFunctionBegin; 289 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 290 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 291 if (iascii) { 292 if (jac->bs > 0) { 293 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs)); 294 } else { 295 PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits)); 296 } 297 if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n")); 298 if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for diagonal blocks\n")); 299 if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for off-diagonal blocks\n")); 300 301 PetscCall(PetscViewerASCIIPrintf(viewer, " Stopping tolerance=%.1e, delay in error estimate=%" PetscInt_FMT ", maximum iterations=%" PetscInt_FMT "\n", (double)jac->gkbtol, jac->gkbdelay, jac->gkbmaxit)); 302 PetscCall(PetscViewerASCIIPrintf(viewer, " Solver info for H = A00 + nu*A01*A01' matrix:\n")); 303 PetscCall(PetscViewerASCIIPushTab(viewer)); 304 305 if (ilink->fields) { 306 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Fields ")); 307 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 308 for (j = 0; j < ilink->nfields; j++) { 309 if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ",")); 310 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j])); 311 } 312 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 313 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 314 } else { 315 PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Defined by IS\n")); 316 } 317 PetscCall(KSPView(ilink->ksp, viewer)); 318 319 PetscCall(PetscViewerASCIIPopTab(viewer)); 320 } 321 322 if (isdraw) { 323 PetscDraw draw; 324 PetscReal x, y, w, wd; 325 326 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 327 PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y)); 328 w = 2 * PetscMin(1.0 - x, x); 329 wd = w / (jac->nsplits + 1); 330 x = x - wd * (jac->nsplits - 1) / 2.0; 331 for (i = 0; i < jac->nsplits; i++) { 332 PetscCall(PetscDrawPushCurrentPoint(draw, x, y)); 333 PetscCall(KSPView(ilink->ksp, viewer)); 334 PetscCall(PetscDrawPopCurrentPoint(draw)); 335 x += wd; 336 ilink = ilink->next; 337 } 338 } 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 /* Precondition: jac->bs is set to a meaningful value */ 343 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) 344 { 345 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 346 PetscInt i, nfields, *ifields, nfields_col, *ifields_col; 347 PetscBool flg, flg_col; 348 char optionname[128], splitname[8], optionname_col[128]; 349 350 PetscFunctionBegin; 351 PetscCall(PetscMalloc1(jac->bs, &ifields)); 352 PetscCall(PetscMalloc1(jac->bs, &ifields_col)); 353 for (i = 0, flg = PETSC_TRUE;; i++) { 354 PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i)); 355 PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i)); 356 PetscCall(PetscSNPrintf(optionname_col, sizeof(optionname_col), "-pc_fieldsplit_%" PetscInt_FMT "_fields_col", i)); 357 nfields = jac->bs; 358 nfields_col = jac->bs; 359 PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg)); 360 PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname_col, ifields_col, &nfields_col, &flg_col)); 361 if (!flg) break; 362 else if (flg && !flg_col) { 363 PetscCheck(nfields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields"); 364 PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields)); 365 } else { 366 PetscCheck(nfields && nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields"); 367 PetscCheck(nfields == nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Number of row and column fields must match"); 368 PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields_col)); 369 } 370 } 371 if (i > 0) { 372 /* Makes command-line setting of splits take precedence over setting them in code. 373 Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would 374 create new splits, which would probably not be what the user wanted. */ 375 jac->splitdefined = PETSC_TRUE; 376 } 377 PetscCall(PetscFree(ifields)); 378 PetscCall(PetscFree(ifields_col)); 379 PetscFunctionReturn(PETSC_SUCCESS); 380 } 381 382 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 383 { 384 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 385 PC_FieldSplitLink ilink = jac->head; 386 PetscBool fieldsplit_default = PETSC_FALSE, coupling = PETSC_FALSE; 387 PetscInt i; 388 389 PetscFunctionBegin; 390 /* 391 Kinda messy, but at least this now uses DMCreateFieldDecomposition(). 392 Should probably be rewritten. 393 */ 394 if (!ilink) { 395 PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_detect_coupling", &coupling, NULL)); 396 if (pc->dm && jac->dm_splits && !jac->detect && !coupling) { 397 PetscInt numFields, f, i, j; 398 char **fieldNames; 399 IS *fields; 400 DM *dms; 401 DM subdm[128]; 402 PetscBool flg; 403 404 PetscCall(DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms)); 405 /* Allow the user to prescribe the splits */ 406 for (i = 0, flg = PETSC_TRUE;; i++) { 407 PetscInt ifields[128]; 408 IS compField; 409 char optionname[128], splitname[8]; 410 PetscInt nfields = numFields; 411 412 PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i)); 413 PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg)); 414 if (!flg) break; 415 PetscCheck(numFields <= 128, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot currently support %" PetscInt_FMT " > 128 fields", numFields); 416 PetscCall(DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i])); 417 if (nfields == 1) { 418 PetscCall(PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField)); 419 } else { 420 PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i)); 421 PetscCall(PCFieldSplitSetIS(pc, splitname, compField)); 422 } 423 PetscCall(ISDestroy(&compField)); 424 for (j = 0; j < nfields; ++j) { 425 f = ifields[j]; 426 PetscCall(PetscFree(fieldNames[f])); 427 PetscCall(ISDestroy(&fields[f])); 428 } 429 } 430 if (i == 0) { 431 for (f = 0; f < numFields; ++f) { 432 PetscCall(PCFieldSplitSetIS(pc, fieldNames[f], fields[f])); 433 PetscCall(PetscFree(fieldNames[f])); 434 PetscCall(ISDestroy(&fields[f])); 435 } 436 } else { 437 for (j = 0; j < numFields; j++) PetscCall(DMDestroy(dms + j)); 438 PetscCall(PetscFree(dms)); 439 PetscCall(PetscMalloc1(i, &dms)); 440 for (j = 0; j < i; ++j) dms[j] = subdm[j]; 441 } 442 PetscCall(PetscFree(fieldNames)); 443 PetscCall(PetscFree(fields)); 444 if (dms) { 445 PetscCall(PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n")); 446 for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) { 447 const char *prefix; 448 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp), &prefix)); 449 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix)); 450 PetscCall(KSPSetDM(ilink->ksp, dms[i])); 451 PetscCall(KSPSetDMActive(ilink->ksp, PETSC_FALSE)); 452 { 453 PetscErrorCode (*func)(KSP, Mat, Mat, void *); 454 void *ctx; 455 456 PetscCall(DMKSPGetComputeOperators(pc->dm, &func, &ctx)); 457 PetscCall(DMKSPSetComputeOperators(dms[i], func, ctx)); 458 } 459 PetscCall(PetscObjectIncrementTabLevel((PetscObject)dms[i], (PetscObject)ilink->ksp, 0)); 460 PetscCall(DMDestroy(&dms[i])); 461 } 462 PetscCall(PetscFree(dms)); 463 } 464 } else { 465 if (jac->bs <= 0) { 466 if (pc->pmat) { 467 PetscCall(MatGetBlockSize(pc->pmat, &jac->bs)); 468 } else jac->bs = 1; 469 } 470 471 if (jac->detect) { 472 IS zerodiags, rest; 473 PetscInt nmin, nmax; 474 475 PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax)); 476 if (jac->diag_use_amat) { 477 PetscCall(MatFindZeroDiagonals(pc->mat, &zerodiags)); 478 } else { 479 PetscCall(MatFindZeroDiagonals(pc->pmat, &zerodiags)); 480 } 481 PetscCall(ISComplement(zerodiags, nmin, nmax, &rest)); 482 PetscCall(PCFieldSplitSetIS(pc, "0", rest)); 483 PetscCall(PCFieldSplitSetIS(pc, "1", zerodiags)); 484 PetscCall(ISDestroy(&zerodiags)); 485 PetscCall(ISDestroy(&rest)); 486 } else if (coupling) { 487 IS coupling, rest; 488 PetscInt nmin, nmax; 489 490 PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax)); 491 if (jac->offdiag_use_amat) { 492 PetscCall(MatFindOffBlockDiagonalEntries(pc->mat, &coupling)); 493 } else { 494 PetscCall(MatFindOffBlockDiagonalEntries(pc->pmat, &coupling)); 495 } 496 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc->mat), nmax - nmin, nmin, 1, &rest)); 497 PetscCall(ISSetIdentity(rest)); 498 PetscCall(PCFieldSplitSetIS(pc, "0", rest)); 499 PetscCall(PCFieldSplitSetIS(pc, "1", coupling)); 500 PetscCall(ISDestroy(&coupling)); 501 PetscCall(ISDestroy(&rest)); 502 } else { 503 PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_default", &fieldsplit_default, NULL)); 504 if (!fieldsplit_default) { 505 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 506 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 507 PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc)); 508 if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n")); 509 } 510 if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) { 511 Mat M = pc->pmat; 512 PetscBool isnest; 513 514 PetscCall(PetscInfo(pc, "Using default splitting of fields\n")); 515 PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &isnest)); 516 if (!isnest) { 517 M = pc->mat; 518 PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &isnest)); 519 } 520 if (isnest) { 521 IS *fields; 522 PetscInt nf; 523 524 PetscCall(MatNestGetSize(M, &nf, NULL)); 525 PetscCall(PetscMalloc1(nf, &fields)); 526 PetscCall(MatNestGetISs(M, fields, NULL)); 527 for (i = 0; i < nf; i++) PetscCall(PCFieldSplitSetIS(pc, NULL, fields[i])); 528 PetscCall(PetscFree(fields)); 529 } else { 530 for (i = 0; i < jac->bs; i++) { 531 char splitname[8]; 532 PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i)); 533 PetscCall(PCFieldSplitSetFields(pc, splitname, 1, &i, &i)); 534 } 535 jac->defaultsplit = PETSC_TRUE; 536 } 537 } 538 } 539 } 540 } else if (jac->nsplits == 1) { 541 IS is2; 542 PetscInt nmin, nmax; 543 544 PetscCheck(ilink->is, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Must provide at least two sets of fields to PCFieldSplit()"); 545 PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax)); 546 PetscCall(ISComplement(ilink->is, nmin, nmax, &is2)); 547 PetscCall(PCFieldSplitSetIS(pc, "1", is2)); 548 PetscCall(ISDestroy(&is2)); 549 } 550 551 PetscCheck(jac->nsplits >= 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unhandled case, must have at least two fields, not %" PetscInt_FMT, jac->nsplits); 552 PetscFunctionReturn(PETSC_SUCCESS); 553 } 554 555 static PetscErrorCode MatGolubKahanComputeExplicitOperator(Mat A, Mat B, Mat C, Mat *H, PetscReal gkbnu) 556 { 557 Mat BT, T; 558 PetscReal nrmT, nrmB; 559 560 PetscFunctionBegin; 561 PetscCall(MatHermitianTranspose(C, MAT_INITIAL_MATRIX, &T)); /* Test if augmented matrix is symmetric */ 562 PetscCall(MatAXPY(T, -1.0, B, DIFFERENT_NONZERO_PATTERN)); 563 PetscCall(MatNorm(T, NORM_1, &nrmT)); 564 PetscCall(MatNorm(B, NORM_1, &nrmB)); 565 PetscCheck(nrmB <= 0 || nrmT / nrmB < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix is not symmetric/hermitian, GKB is not applicable."); 566 567 /* Compute augmented Lagrangian matrix H = A00 + nu*A01*A01'. This corresponds to */ 568 /* setting N := 1/nu*I in [Ar13]. */ 569 PetscCall(MatHermitianTranspose(B, MAT_INITIAL_MATRIX, &BT)); 570 PetscCall(MatMatMult(B, BT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, H)); /* H = A01*A01' */ 571 PetscCall(MatAYPX(*H, gkbnu, A, DIFFERENT_NONZERO_PATTERN)); /* H = A00 + nu*A01*A01' */ 572 573 PetscCall(MatDestroy(&BT)); 574 PetscCall(MatDestroy(&T)); 575 PetscFunctionReturn(PETSC_SUCCESS); 576 } 577 578 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *value[], PetscBool *flg); 579 580 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 581 { 582 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 583 PC_FieldSplitLink ilink; 584 PetscInt i, nsplit; 585 PetscBool sorted, sorted_col; 586 587 PetscFunctionBegin; 588 pc->failedreason = PC_NOERROR; 589 PetscCall(PCFieldSplitSetDefaults(pc)); 590 nsplit = jac->nsplits; 591 ilink = jac->head; 592 593 /* get the matrices for each split */ 594 if (!jac->issetup) { 595 PetscInt rstart, rend, nslots, bs; 596 597 jac->issetup = PETSC_TRUE; 598 599 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 600 if (jac->defaultsplit || !ilink->is) { 601 if (jac->bs <= 0) jac->bs = nsplit; 602 } 603 604 /* MatCreateSubMatrix() for [S]BAIJ matrices can only work if the indices include entire blocks of the matrix */ 605 PetscCall(MatGetBlockSize(pc->pmat, &bs)); 606 if (bs > 1 && (jac->bs <= bs || jac->bs % bs)) { 607 PetscBool blk; 608 609 PetscCall(PetscObjectTypeCompareAny((PetscObject)pc->pmat, &blk, MATBAIJ, MATSBAIJ, MATSEQBAIJ, MATSEQSBAIJ, MATMPIBAIJ, MATMPISBAIJ, NULL)); 610 PetscCheck(!blk, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Cannot use MATBAIJ with PCFIELDSPLIT and currently set matrix and PC blocksizes"); 611 } 612 613 bs = jac->bs; 614 PetscCall(MatGetOwnershipRange(pc->pmat, &rstart, &rend)); 615 nslots = (rend - rstart) / bs; 616 for (i = 0; i < nsplit; i++) { 617 if (jac->defaultsplit) { 618 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + i, nsplit, &ilink->is)); 619 PetscCall(ISDuplicate(ilink->is, &ilink->is_col)); 620 } else if (!ilink->is) { 621 if (ilink->nfields > 1) { 622 PetscInt *ii, *jj, j, k, nfields = ilink->nfields, *fields = ilink->fields, *fields_col = ilink->fields_col; 623 PetscCall(PetscMalloc1(ilink->nfields * nslots, &ii)); 624 PetscCall(PetscMalloc1(ilink->nfields * nslots, &jj)); 625 for (j = 0; j < nslots; j++) { 626 for (k = 0; k < nfields; k++) { 627 ii[nfields * j + k] = rstart + bs * j + fields[k]; 628 jj[nfields * j + k] = rstart + bs * j + fields_col[k]; 629 } 630 } 631 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, ii, PETSC_OWN_POINTER, &ilink->is)); 632 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, jj, PETSC_OWN_POINTER, &ilink->is_col)); 633 PetscCall(ISSetBlockSize(ilink->is, nfields)); 634 PetscCall(ISSetBlockSize(ilink->is_col, nfields)); 635 } else { 636 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields[0], bs, &ilink->is)); 637 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields_col[0], bs, &ilink->is_col)); 638 } 639 } 640 PetscCall(ISSorted(ilink->is, &sorted)); 641 if (ilink->is_col) PetscCall(ISSorted(ilink->is_col, &sorted_col)); 642 PetscCheck(sorted && sorted_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Fields must be sorted when creating split"); 643 ilink = ilink->next; 644 } 645 } 646 647 ilink = jac->head; 648 if (!jac->pmat) { 649 Vec xtmp; 650 651 PetscCall(MatCreateVecs(pc->pmat, &xtmp, NULL)); 652 PetscCall(PetscMalloc1(nsplit, &jac->pmat)); 653 PetscCall(PetscMalloc2(nsplit, &jac->x, nsplit, &jac->y)); 654 for (i = 0; i < nsplit; i++) { 655 MatNullSpace sp; 656 657 /* Check for preconditioning matrix attached to IS */ 658 PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&jac->pmat[i])); 659 if (jac->pmat[i]) { 660 PetscCall(PetscObjectReference((PetscObject)jac->pmat[i])); 661 if (jac->type == PC_COMPOSITE_SCHUR) { 662 jac->schur_user = jac->pmat[i]; 663 664 PetscCall(PetscObjectReference((PetscObject)jac->schur_user)); 665 } 666 } else { 667 const char *prefix; 668 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->pmat[i])); 669 PetscCall(KSPGetOptionsPrefix(ilink->ksp, &prefix)); 670 PetscCall(MatSetOptionsPrefix(jac->pmat[i], prefix)); 671 PetscCall(MatSetFromOptions(jac->pmat[i])); 672 PetscCall(MatViewFromOptions(jac->pmat[i], NULL, "-mat_view")); 673 } 674 /* create work vectors for each split */ 675 PetscCall(MatCreateVecs(jac->pmat[i], &jac->x[i], &jac->y[i])); 676 ilink->x = jac->x[i]; 677 ilink->y = jac->y[i]; 678 ilink->z = NULL; 679 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 680 PetscCall(VecScatterCreate(xtmp, ilink->is, jac->x[i], NULL, &ilink->sctx)); 681 PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nearnullspace", (PetscObject *)&sp)); 682 if (sp) PetscCall(MatSetNearNullSpace(jac->pmat[i], sp)); 683 ilink = ilink->next; 684 } 685 PetscCall(VecDestroy(&xtmp)); 686 } else { 687 MatReuse scall; 688 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 689 for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->pmat[i])); 690 scall = MAT_INITIAL_MATRIX; 691 } else scall = MAT_REUSE_MATRIX; 692 693 for (i = 0; i < nsplit; i++) { 694 Mat pmat; 695 696 /* Check for preconditioning matrix attached to IS */ 697 PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&pmat)); 698 if (!pmat) PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, scall, &jac->pmat[i])); 699 ilink = ilink->next; 700 } 701 } 702 if (jac->diag_use_amat) { 703 ilink = jac->head; 704 if (!jac->mat) { 705 PetscCall(PetscMalloc1(nsplit, &jac->mat)); 706 for (i = 0; i < nsplit; i++) { 707 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->mat[i])); 708 ilink = ilink->next; 709 } 710 } else { 711 MatReuse scall; 712 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 713 for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->mat[i])); 714 scall = MAT_INITIAL_MATRIX; 715 } else scall = MAT_REUSE_MATRIX; 716 717 for (i = 0; i < nsplit; i++) { 718 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, scall, &jac->mat[i])); 719 ilink = ilink->next; 720 } 721 } 722 } else { 723 jac->mat = jac->pmat; 724 } 725 726 /* Check for null space attached to IS */ 727 ilink = jac->head; 728 for (i = 0; i < nsplit; i++) { 729 MatNullSpace sp; 730 731 PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nullspace", (PetscObject *)&sp)); 732 if (sp) PetscCall(MatSetNullSpace(jac->mat[i], sp)); 733 ilink = ilink->next; 734 } 735 736 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR && jac->type != PC_COMPOSITE_GKB) { 737 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 738 /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */ 739 ilink = jac->head; 740 if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) { 741 /* special case need where Afield[0] is not needed and only certain columns of Afield[1] are needed since update is only on those rows of the solution */ 742 if (!jac->Afield) { 743 PetscCall(PetscCalloc1(nsplit, &jac->Afield)); 744 if (jac->offdiag_use_amat) { 745 PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1])); 746 } else { 747 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1])); 748 } 749 } else { 750 MatReuse scall; 751 752 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 753 PetscCall(MatDestroy(&jac->Afield[1])); 754 scall = MAT_INITIAL_MATRIX; 755 } else scall = MAT_REUSE_MATRIX; 756 757 if (jac->offdiag_use_amat) { 758 PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, scall, &jac->Afield[1])); 759 } else { 760 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, scall, &jac->Afield[1])); 761 } 762 } 763 } else { 764 if (!jac->Afield) { 765 PetscCall(PetscMalloc1(nsplit, &jac->Afield)); 766 for (i = 0; i < nsplit; i++) { 767 if (jac->offdiag_use_amat) { 768 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i])); 769 } else { 770 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i])); 771 } 772 ilink = ilink->next; 773 } 774 } else { 775 MatReuse scall; 776 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 777 for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->Afield[i])); 778 scall = MAT_INITIAL_MATRIX; 779 } else scall = MAT_REUSE_MATRIX; 780 781 for (i = 0; i < nsplit; i++) { 782 if (jac->offdiag_use_amat) { 783 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, scall, &jac->Afield[i])); 784 } else { 785 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, scall, &jac->Afield[i])); 786 } 787 ilink = ilink->next; 788 } 789 } 790 } 791 } 792 793 if (jac->type == PC_COMPOSITE_SCHUR) { 794 IS ccis; 795 PetscBool isset, isspd; 796 PetscInt rstart, rend; 797 char lscname[256]; 798 PetscObject LSC_L; 799 PetscBool set, flg; 800 801 PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use Schur complement preconditioner you must have exactly 2 fields"); 802 803 /* If pc->mat is SPD, don't scale by -1 the Schur complement */ 804 if (jac->schurscale == (PetscScalar)-1.0) { 805 PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd)); 806 jac->schurscale = (isset && isspd) ? 1.0 : -1.0; 807 } 808 809 /* When extracting off-diagonal submatrices, we take complements from this range */ 810 PetscCall(MatGetOwnershipRangeColumn(pc->mat, &rstart, &rend)); 811 PetscCall(PetscObjectTypeCompareAny(jac->offdiag_use_amat ? (PetscObject)pc->mat : (PetscObject)pc->pmat, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 812 813 if (jac->schur) { 814 KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper; 815 MatReuse scall; 816 817 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 818 scall = MAT_INITIAL_MATRIX; 819 PetscCall(MatDestroy(&jac->B)); 820 PetscCall(MatDestroy(&jac->C)); 821 } else scall = MAT_REUSE_MATRIX; 822 823 PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner)); 824 ilink = jac->head; 825 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 826 if (jac->offdiag_use_amat) { 827 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, scall, &jac->B)); 828 } else { 829 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, scall, &jac->B)); 830 } 831 PetscCall(ISDestroy(&ccis)); 832 if (!flg) { 833 ilink = ilink->next; 834 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 835 if (jac->offdiag_use_amat) { 836 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, scall, &jac->C)); 837 } else { 838 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, scall, &jac->C)); 839 } 840 PetscCall(ISDestroy(&ccis)); 841 } else { 842 PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &set, &flg)); 843 if (set && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C)); 844 else PetscCall(MatCreateTranspose(jac->B, &jac->C)); 845 } 846 PetscCall(MatSchurComplementUpdateSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1])); 847 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) { 848 PetscCall(MatDestroy(&jac->schurp)); 849 PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp)); 850 } 851 if (kspA != kspInner) PetscCall(KSPSetOperators(kspA, jac->mat[0], jac->pmat[0])); 852 if (kspUpper != kspA) PetscCall(KSPSetOperators(kspUpper, jac->mat[0], jac->pmat[0])); 853 PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac))); 854 } else { 855 const char *Dprefix; 856 char schurprefix[256], schurmatprefix[256]; 857 char schurtestoption[256]; 858 MatNullSpace sp; 859 KSP kspt; 860 861 /* extract the A01 and A10 matrices */ 862 ilink = jac->head; 863 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 864 if (jac->offdiag_use_amat) { 865 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B)); 866 } else { 867 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B)); 868 } 869 PetscCall(ISDestroy(&ccis)); 870 ilink = ilink->next; 871 if (!flg) { 872 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 873 if (jac->offdiag_use_amat) { 874 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C)); 875 } else { 876 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C)); 877 } 878 PetscCall(ISDestroy(&ccis)); 879 } else { 880 PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &set, &flg)); 881 if (set && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C)); 882 else PetscCall(MatCreateTranspose(jac->B, &jac->C)); 883 } 884 /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */ 885 PetscCall(MatCreate(((PetscObject)jac->mat[0])->comm, &jac->schur)); 886 PetscCall(MatSetType(jac->schur, MATSCHURCOMPLEMENT)); 887 PetscCall(MatSchurComplementSetSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1])); 888 PetscCall(PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 889 PetscCall(MatSetOptionsPrefix(jac->schur, schurmatprefix)); 890 PetscCall(MatSchurComplementGetKSP(jac->schur, &kspt)); 891 PetscCall(KSPSetOptionsPrefix(kspt, schurmatprefix)); 892 893 /* Note: this is not true in general */ 894 PetscCall(MatGetNullSpace(jac->mat[1], &sp)); 895 if (sp) PetscCall(MatSetNullSpace(jac->schur, sp)); 896 897 PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname)); 898 PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, &flg)); 899 if (flg) { 900 DM dmInner; 901 KSP kspInner; 902 PC pcInner; 903 904 PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner)); 905 PetscCall(KSPReset(kspInner)); 906 PetscCall(KSPSetOperators(kspInner, jac->mat[0], jac->pmat[0])); 907 PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 908 /* Indent this deeper to emphasize the "inner" nature of this solver. */ 909 PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject)pc, 2)); 910 PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner->pc, (PetscObject)pc, 2)); 911 PetscCall(KSPSetOptionsPrefix(kspInner, schurprefix)); 912 913 /* Set DM for new solver */ 914 PetscCall(KSPGetDM(jac->head->ksp, &dmInner)); 915 PetscCall(KSPSetDM(kspInner, dmInner)); 916 PetscCall(KSPSetDMActive(kspInner, PETSC_FALSE)); 917 918 /* Defaults to PCKSP as preconditioner */ 919 PetscCall(KSPGetPC(kspInner, &pcInner)); 920 PetscCall(PCSetType(pcInner, PCKSP)); 921 PetscCall(PCKSPSetKSP(pcInner, jac->head->ksp)); 922 } else { 923 /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or 924 * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact, 925 * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for 926 * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make 927 * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used 928 * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */ 929 PetscCall(KSPSetType(jac->head->ksp, KSPGMRES)); 930 PetscCall(MatSchurComplementSetKSP(jac->schur, jac->head->ksp)); 931 } 932 PetscCall(KSPSetOperators(jac->head->ksp, jac->mat[0], jac->pmat[0])); 933 PetscCall(KSPSetFromOptions(jac->head->ksp)); 934 PetscCall(MatSetFromOptions(jac->schur)); 935 936 PetscCall(PetscObjectTypeCompare((PetscObject)jac->schur, MATSCHURCOMPLEMENT, &flg)); 937 if (flg) { /* Need to do this otherwise PCSetUp_KSP will overwrite the amat of jac->head->ksp */ 938 KSP kspInner; 939 PC pcInner; 940 941 PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner)); 942 PetscCall(KSPGetPC(kspInner, &pcInner)); 943 PetscCall(PetscObjectTypeCompare((PetscObject)pcInner, PCKSP, &flg)); 944 if (flg) { 945 KSP ksp; 946 947 PetscCall(PCKSPGetKSP(pcInner, &ksp)); 948 if (ksp == jac->head->ksp) PetscCall(PCSetUseAmat(pcInner, PETSC_TRUE)); 949 } 950 } 951 PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname)); 952 PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, &flg)); 953 if (flg) { 954 DM dmInner; 955 956 PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 957 PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper)); 958 PetscCall(KSPSetNestLevel(jac->kspupper, pc->kspnestlevel)); 959 PetscCall(KSPSetErrorIfNotConverged(jac->kspupper, pc->erroriffailure)); 960 PetscCall(KSPSetOptionsPrefix(jac->kspupper, schurprefix)); 961 PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper, (PetscObject)pc, 1)); 962 PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper->pc, (PetscObject)pc, 1)); 963 PetscCall(KSPGetDM(jac->head->ksp, &dmInner)); 964 PetscCall(KSPSetDM(jac->kspupper, dmInner)); 965 PetscCall(KSPSetDMActive(jac->kspupper, PETSC_FALSE)); 966 PetscCall(KSPSetFromOptions(jac->kspupper)); 967 PetscCall(KSPSetOperators(jac->kspupper, jac->mat[0], jac->pmat[0])); 968 PetscCall(VecDuplicate(jac->head->x, &jac->head->z)); 969 } else { 970 jac->kspupper = jac->head->ksp; 971 PetscCall(PetscObjectReference((PetscObject)jac->head->ksp)); 972 } 973 974 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp)); 975 PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspschur)); 976 PetscCall(KSPSetNestLevel(jac->kspschur, pc->kspnestlevel)); 977 PetscCall(KSPSetErrorIfNotConverged(jac->kspschur, pc->erroriffailure)); 978 PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspschur, (PetscObject)pc, 1)); 979 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 980 PC pcschur; 981 PetscCall(KSPGetPC(jac->kspschur, &pcschur)); 982 PetscCall(PCSetType(pcschur, PCNONE)); 983 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 984 } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) { 985 PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user)); 986 } 987 PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac))); 988 PetscCall(KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix)); 989 PetscCall(KSPSetOptionsPrefix(jac->kspschur, Dprefix)); 990 /* propagate DM */ 991 { 992 DM sdm; 993 PetscCall(KSPGetDM(jac->head->next->ksp, &sdm)); 994 if (sdm) { 995 PetscCall(KSPSetDM(jac->kspschur, sdm)); 996 PetscCall(KSPSetDMActive(jac->kspschur, PETSC_FALSE)); 997 } 998 } 999 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 1000 /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */ 1001 PetscCall(KSPSetFromOptions(jac->kspschur)); 1002 } 1003 PetscCall(MatAssemblyBegin(jac->schur, MAT_FINAL_ASSEMBLY)); 1004 PetscCall(MatAssemblyEnd(jac->schur, MAT_FINAL_ASSEMBLY)); 1005 1006 /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */ 1007 PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_L", ilink->splitname)); 1008 PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, (PetscObject *)&LSC_L)); 1009 if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, (PetscObject *)&LSC_L)); 1010 if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_L", (PetscObject)LSC_L)); 1011 PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_Lp", ilink->splitname)); 1012 PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, (PetscObject *)&LSC_L)); 1013 if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, (PetscObject *)&LSC_L)); 1014 if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_Lp", (PetscObject)LSC_L)); 1015 } else if (jac->type == PC_COMPOSITE_GKB) { 1016 IS ccis; 1017 PetscInt rstart, rend; 1018 1019 PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use GKB preconditioner you must have exactly 2 fields"); 1020 1021 ilink = jac->head; 1022 1023 /* When extracting off-diagonal submatrices, we take complements from this range */ 1024 PetscCall(MatGetOwnershipRangeColumn(pc->mat, &rstart, &rend)); 1025 1026 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 1027 if (jac->offdiag_use_amat) { 1028 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B)); 1029 } else { 1030 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B)); 1031 } 1032 PetscCall(ISDestroy(&ccis)); 1033 /* Create work vectors for GKB algorithm */ 1034 PetscCall(VecDuplicate(ilink->x, &jac->u)); 1035 PetscCall(VecDuplicate(ilink->x, &jac->Hu)); 1036 PetscCall(VecDuplicate(ilink->x, &jac->w2)); 1037 ilink = ilink->next; 1038 PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis)); 1039 if (jac->offdiag_use_amat) { 1040 PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C)); 1041 } else { 1042 PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C)); 1043 } 1044 PetscCall(ISDestroy(&ccis)); 1045 /* Create work vectors for GKB algorithm */ 1046 PetscCall(VecDuplicate(ilink->x, &jac->v)); 1047 PetscCall(VecDuplicate(ilink->x, &jac->d)); 1048 PetscCall(VecDuplicate(ilink->x, &jac->w1)); 1049 PetscCall(MatGolubKahanComputeExplicitOperator(jac->mat[0], jac->B, jac->C, &jac->H, jac->gkbnu)); 1050 PetscCall(PetscCalloc1(jac->gkbdelay, &jac->vecz)); 1051 1052 ilink = jac->head; 1053 PetscCall(KSPSetOperators(ilink->ksp, jac->H, jac->H)); 1054 if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp)); 1055 /* Create gkb_monitor context */ 1056 if (jac->gkbmonitor) { 1057 PetscInt tablevel; 1058 PetscCall(PetscViewerCreate(PETSC_COMM_WORLD, &jac->gkbviewer)); 1059 PetscCall(PetscViewerSetType(jac->gkbviewer, PETSCVIEWERASCII)); 1060 PetscCall(PetscObjectGetTabLevel((PetscObject)ilink->ksp, &tablevel)); 1061 PetscCall(PetscViewerASCIISetTab(jac->gkbviewer, tablevel)); 1062 PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)ilink->ksp, 1)); 1063 } 1064 } else { 1065 /* set up the individual splits' PCs */ 1066 i = 0; 1067 ilink = jac->head; 1068 while (ilink) { 1069 PetscCall(KSPSetOperators(ilink->ksp, jac->mat[i], jac->pmat[i])); 1070 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 1071 if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp)); 1072 i++; 1073 ilink = ilink->next; 1074 } 1075 } 1076 1077 /* Set coordinates to the sub PC objects whenever these are set */ 1078 if (jac->coordinates_set) { 1079 PC pc_coords; 1080 if (jac->type == PC_COMPOSITE_SCHUR) { 1081 // Head is first block. 1082 PetscCall(KSPGetPC(jac->head->ksp, &pc_coords)); 1083 PetscCall(PCSetCoordinates(pc_coords, jac->head->dim, jac->head->ndofs, jac->head->coords)); 1084 // Second one is Schur block, but its KSP object is in kspschur. 1085 PetscCall(KSPGetPC(jac->kspschur, &pc_coords)); 1086 PetscCall(PCSetCoordinates(pc_coords, jac->head->next->dim, jac->head->next->ndofs, jac->head->next->coords)); 1087 } else if (jac->type == PC_COMPOSITE_GKB) { 1088 PetscCall(PetscInfo(pc, "Warning: Setting coordinates does nothing for the GKB Fieldpslit preconditioner\n")); 1089 } else { 1090 ilink = jac->head; 1091 while (ilink) { 1092 PetscCall(KSPGetPC(ilink->ksp, &pc_coords)); 1093 PetscCall(PCSetCoordinates(pc_coords, ilink->dim, ilink->ndofs, ilink->coords)); 1094 ilink = ilink->next; 1095 } 1096 } 1097 } 1098 1099 jac->suboptionsset = PETSC_TRUE; 1100 PetscFunctionReturn(PETSC_SUCCESS); 1101 } 1102 1103 #define FieldSplitSplitSolveAdd(ilink, xx, yy) \ 1104 ((PetscErrorCode)(VecScatterBegin(ilink->sctx, xx, ilink->x, INSERT_VALUES, SCATTER_FORWARD) || VecScatterEnd(ilink->sctx, xx, ilink->x, INSERT_VALUES, SCATTER_FORWARD) || PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL) || \ 1105 KSPSolve(ilink->ksp, ilink->x, ilink->y) || KSPCheckSolve(ilink->ksp, pc, ilink->y) || PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL) || VecScatterBegin(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE) || \ 1106 VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE))) 1107 1108 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y) 1109 { 1110 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1111 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1112 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 1113 1114 PetscFunctionBegin; 1115 switch (jac->schurfactorization) { 1116 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 1117 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 1118 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1119 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1120 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1121 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1122 PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 1123 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1124 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1125 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1126 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1127 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1128 PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1129 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1130 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1131 PetscCall(VecScale(ilinkD->y, jac->schurscale)); 1132 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1133 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1134 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1135 break; 1136 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 1137 /* [A00 0; A10 S], suitable for left preconditioning */ 1138 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1139 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1140 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1141 PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 1142 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1143 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1144 PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x)); 1145 PetscCall(VecScale(ilinkD->x, -1.)); 1146 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1147 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1148 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1149 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1150 PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1151 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1152 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1153 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1154 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1155 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1156 break; 1157 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 1158 /* [A00 A01; 0 S], suitable for right preconditioning */ 1159 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1160 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1161 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1162 PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1163 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1164 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1165 PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x)); 1166 PetscCall(VecScale(ilinkA->x, -1.)); 1167 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 1168 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1169 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 1170 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1171 PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 1172 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1173 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1174 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1175 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1176 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1177 break; 1178 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 1179 /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */ 1180 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1181 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1182 PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL)); 1183 PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y)); 1184 PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y)); 1185 PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL)); 1186 PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x)); 1187 PetscCall(VecScale(ilinkD->x, -1.0)); 1188 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1189 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1190 1191 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1192 PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1193 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1194 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1195 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1196 1197 if (kspUpper == kspA) { 1198 PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y)); 1199 PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y)); 1200 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1201 PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 1202 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1203 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1204 } else { 1205 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1206 PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 1207 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1208 PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x)); 1209 PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL)); 1210 PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z)); 1211 PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z)); 1212 PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL)); 1213 PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z)); 1214 } 1215 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1216 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1217 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1218 } 1219 PetscFunctionReturn(PETSC_SUCCESS); 1220 } 1221 1222 static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y) 1223 { 1224 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1225 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1226 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 1227 1228 PetscFunctionBegin; 1229 switch (jac->schurfactorization) { 1230 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 1231 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 1232 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1233 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1234 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1235 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1236 PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 1237 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1238 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1239 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1240 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1241 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1242 PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1243 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1244 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1245 PetscCall(VecScale(ilinkD->y, jac->schurscale)); 1246 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1247 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1248 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1249 break; 1250 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 1251 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1252 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1253 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1254 PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 1255 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1256 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1257 PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 1258 PetscCall(VecScale(ilinkD->x, -1.)); 1259 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1260 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1261 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1262 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1263 PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1264 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1265 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1266 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1267 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1268 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1269 break; 1270 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 1271 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1272 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1273 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1274 PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1275 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1276 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1277 PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 1278 PetscCall(VecScale(ilinkA->x, -1.)); 1279 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 1280 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1281 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 1282 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1283 PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 1284 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1285 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1286 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1287 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1288 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1289 break; 1290 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 1291 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1292 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1293 PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 1294 PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y)); 1295 PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y)); 1296 PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 1297 PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 1298 PetscCall(VecScale(ilinkD->x, -1.0)); 1299 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1300 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 1301 1302 PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1303 PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1304 PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1305 PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1306 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1307 1308 if (kspLower == kspA) { 1309 PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y)); 1310 PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y)); 1311 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1312 PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 1313 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1314 PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1315 } else { 1316 PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1317 PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 1318 PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 1319 PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 1320 PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 1321 PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z)); 1322 PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z)); 1323 PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 1324 PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z)); 1325 } 1326 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1327 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1328 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1329 } 1330 PetscFunctionReturn(PETSC_SUCCESS); 1331 } 1332 1333 static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y) 1334 { 1335 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1336 PC_FieldSplitLink ilink = jac->head; 1337 PetscInt cnt, bs; 1338 1339 PetscFunctionBegin; 1340 if (jac->type == PC_COMPOSITE_ADDITIVE) { 1341 if (jac->defaultsplit) { 1342 PetscCall(VecGetBlockSize(x, &bs)); 1343 PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of x vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs); 1344 PetscCall(VecGetBlockSize(y, &bs)); 1345 PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of y vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs); 1346 PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 1347 while (ilink) { 1348 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1349 PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 1350 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1351 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1352 ilink = ilink->next; 1353 } 1354 PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 1355 } else { 1356 PetscCall(VecSet(y, 0.0)); 1357 while (ilink) { 1358 PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 1359 ilink = ilink->next; 1360 } 1361 } 1362 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 1363 PetscCall(VecSet(y, 0.0)); 1364 /* solve on first block for first block variables */ 1365 PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 1366 PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 1367 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1368 PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 1369 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1370 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1371 PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1372 PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1373 1374 /* compute the residual only onto second block variables using first block variables */ 1375 PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x)); 1376 ilink = ilink->next; 1377 PetscCall(VecScale(ilink->x, -1.0)); 1378 PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1379 PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1380 1381 /* solve on second block variables */ 1382 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1383 PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 1384 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1385 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1386 PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1387 PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1388 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1389 if (!jac->w1) { 1390 PetscCall(VecDuplicate(x, &jac->w1)); 1391 PetscCall(VecDuplicate(x, &jac->w2)); 1392 } 1393 PetscCall(VecSet(y, 0.0)); 1394 PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 1395 cnt = 1; 1396 while (ilink->next) { 1397 ilink = ilink->next; 1398 /* compute the residual only over the part of the vector needed */ 1399 PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x)); 1400 PetscCall(VecScale(ilink->x, -1.0)); 1401 PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1402 PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1403 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1404 PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 1405 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1406 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1407 PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1408 PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1409 } 1410 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1411 cnt -= 2; 1412 while (ilink->previous) { 1413 ilink = ilink->previous; 1414 /* compute the residual only over the part of the vector needed */ 1415 PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x)); 1416 PetscCall(VecScale(ilink->x, -1.0)); 1417 PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1418 PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1419 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1420 PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 1421 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1422 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1423 PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1424 PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1425 } 1426 } 1427 } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type); 1428 PetscFunctionReturn(PETSC_SUCCESS); 1429 } 1430 1431 static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y) 1432 { 1433 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1434 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1435 KSP ksp = ilinkA->ksp; 1436 Vec u, v, Hu, d, work1, work2; 1437 PetscScalar alpha, z, nrmz2, *vecz; 1438 PetscReal lowbnd, nu, beta; 1439 PetscInt j, iterGKB; 1440 1441 PetscFunctionBegin; 1442 PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1443 PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1444 PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 1445 PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1446 1447 u = jac->u; 1448 v = jac->v; 1449 Hu = jac->Hu; 1450 d = jac->d; 1451 work1 = jac->w1; 1452 work2 = jac->w2; 1453 vecz = jac->vecz; 1454 1455 /* Change RHS to comply with matrix regularization H = A + nu*B*B' */ 1456 /* Add q = q + nu*B*b */ 1457 if (jac->gkbnu) { 1458 nu = jac->gkbnu; 1459 PetscCall(VecScale(ilinkD->x, jac->gkbnu)); 1460 PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */ 1461 } else { 1462 /* Situation when no augmented Lagrangian is used. Then we set inner */ 1463 /* matrix N = I in [Ar13], and thus nu = 1. */ 1464 nu = 1; 1465 } 1466 1467 /* Transform rhs from [q,tilde{b}] to [0,b] */ 1468 PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 1469 PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y)); 1470 PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y)); 1471 PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 1472 PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1)); 1473 PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x */ 1474 1475 /* First step of algorithm */ 1476 PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/ 1477 KSPCheckDot(ksp, beta); 1478 beta = PetscSqrtReal(nu) * beta; 1479 PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c */ 1480 PetscCall(MatMult(jac->B, v, work2)); /* u = H^{-1}*B*v */ 1481 PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 1482 PetscCall(KSPSolve(ksp, work2, u)); 1483 PetscCall(KSPCheckSolve(ksp, pc, u)); 1484 PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 1485 PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 1486 PetscCall(VecDot(Hu, u, &alpha)); 1487 KSPCheckDot(ksp, alpha); 1488 PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1489 alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 1490 PetscCall(VecScale(u, 1.0 / alpha)); 1491 PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c */ 1492 1493 z = beta / alpha; 1494 vecz[1] = z; 1495 1496 /* Computation of first iterate x(1) and p(1) */ 1497 PetscCall(VecAXPY(ilinkA->y, z, u)); 1498 PetscCall(VecCopy(d, ilinkD->y)); 1499 PetscCall(VecScale(ilinkD->y, -z)); 1500 1501 iterGKB = 1; 1502 lowbnd = 2 * jac->gkbtol; 1503 if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1504 1505 while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) { 1506 iterGKB += 1; 1507 PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */ 1508 PetscCall(VecAXPBY(v, nu, -alpha, work1)); 1509 PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v */ 1510 beta = beta / PetscSqrtReal(nu); 1511 PetscCall(VecScale(v, 1.0 / beta)); 1512 PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */ 1513 PetscCall(MatMult(jac->H, u, Hu)); 1514 PetscCall(VecAXPY(work2, -beta, Hu)); 1515 PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 1516 PetscCall(KSPSolve(ksp, work2, u)); 1517 PetscCall(KSPCheckSolve(ksp, pc, u)); 1518 PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 1519 PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 1520 PetscCall(VecDot(Hu, u, &alpha)); 1521 KSPCheckDot(ksp, alpha); 1522 PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1523 alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 1524 PetscCall(VecScale(u, 1.0 / alpha)); 1525 1526 z = -beta / alpha * z; /* z <- beta/alpha*z */ 1527 vecz[0] = z; 1528 1529 /* Computation of new iterate x(i+1) and p(i+1) */ 1530 PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */ 1531 PetscCall(VecAXPY(ilinkA->y, z, u)); /* r = r + z*u */ 1532 PetscCall(VecAXPY(ilinkD->y, -z, d)); /* p = p - z*d */ 1533 PetscCall(MatMult(jac->H, ilinkA->y, Hu)); /* ||u||_H = u'*H*u */ 1534 PetscCall(VecDot(Hu, ilinkA->y, &nrmz2)); 1535 1536 /* Compute Lower Bound estimate */ 1537 if (iterGKB > jac->gkbdelay) { 1538 lowbnd = 0.0; 1539 for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]); 1540 lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2)); 1541 } 1542 1543 for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2]; 1544 if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1545 } 1546 1547 PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1548 PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1549 PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1550 PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1551 1552 PetscFunctionReturn(PETSC_SUCCESS); 1553 } 1554 1555 #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \ 1556 ((PetscErrorCode)(VecScatterBegin(ilink->sctx, xx, ilink->y, INSERT_VALUES, SCATTER_FORWARD) || VecScatterEnd(ilink->sctx, xx, ilink->y, INSERT_VALUES, SCATTER_FORWARD) || PetscLogEventBegin(ilink->event, ilink->ksp, ilink->y, ilink->x, NULL) || \ 1557 KSPSolveTranspose(ilink->ksp, ilink->y, ilink->x) || KSPCheckSolve(ilink->ksp, pc, ilink->x) || PetscLogEventEnd(ilink->event, ilink->ksp, ilink->y, ilink->x, NULL) || VecScatterBegin(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE) || \ 1558 VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE))) 1559 1560 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y) 1561 { 1562 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1563 PC_FieldSplitLink ilink = jac->head; 1564 PetscInt bs; 1565 1566 PetscFunctionBegin; 1567 if (jac->type == PC_COMPOSITE_ADDITIVE) { 1568 if (jac->defaultsplit) { 1569 PetscCall(VecGetBlockSize(x, &bs)); 1570 PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of x vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs); 1571 PetscCall(VecGetBlockSize(y, &bs)); 1572 PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of y vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs); 1573 PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 1574 while (ilink) { 1575 PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1576 PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y)); 1577 PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 1578 PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1579 ilink = ilink->next; 1580 } 1581 PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 1582 } else { 1583 PetscCall(VecSet(y, 0.0)); 1584 while (ilink) { 1585 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1586 ilink = ilink->next; 1587 } 1588 } 1589 } else { 1590 if (!jac->w1) { 1591 PetscCall(VecDuplicate(x, &jac->w1)); 1592 PetscCall(VecDuplicate(x, &jac->w2)); 1593 } 1594 PetscCall(VecSet(y, 0.0)); 1595 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1596 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1597 while (ilink->next) { 1598 ilink = ilink->next; 1599 PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 1600 PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 1601 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1602 } 1603 while (ilink->previous) { 1604 ilink = ilink->previous; 1605 PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 1606 PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 1607 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1608 } 1609 } else { 1610 while (ilink->next) { /* get to last entry in linked list */ 1611 ilink = ilink->next; 1612 } 1613 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1614 while (ilink->previous) { 1615 ilink = ilink->previous; 1616 PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 1617 PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 1618 PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1619 } 1620 } 1621 } 1622 PetscFunctionReturn(PETSC_SUCCESS); 1623 } 1624 1625 static PetscErrorCode PCReset_FieldSplit(PC pc) 1626 { 1627 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1628 PC_FieldSplitLink ilink = jac->head, next; 1629 1630 PetscFunctionBegin; 1631 while (ilink) { 1632 PetscCall(KSPDestroy(&ilink->ksp)); 1633 PetscCall(VecDestroy(&ilink->x)); 1634 PetscCall(VecDestroy(&ilink->y)); 1635 PetscCall(VecDestroy(&ilink->z)); 1636 PetscCall(VecScatterDestroy(&ilink->sctx)); 1637 PetscCall(ISDestroy(&ilink->is)); 1638 PetscCall(ISDestroy(&ilink->is_col)); 1639 PetscCall(PetscFree(ilink->splitname)); 1640 PetscCall(PetscFree(ilink->fields)); 1641 PetscCall(PetscFree(ilink->fields_col)); 1642 next = ilink->next; 1643 PetscCall(PetscFree(ilink)); 1644 ilink = next; 1645 } 1646 jac->head = NULL; 1647 PetscCall(PetscFree2(jac->x, jac->y)); 1648 if (jac->mat && jac->mat != jac->pmat) { 1649 PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat)); 1650 } else if (jac->mat) { 1651 jac->mat = NULL; 1652 } 1653 if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat)); 1654 if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield)); 1655 jac->nsplits = 0; 1656 PetscCall(VecDestroy(&jac->w1)); 1657 PetscCall(VecDestroy(&jac->w2)); 1658 PetscCall(MatDestroy(&jac->schur)); 1659 PetscCall(MatDestroy(&jac->schurp)); 1660 PetscCall(MatDestroy(&jac->schur_user)); 1661 PetscCall(KSPDestroy(&jac->kspschur)); 1662 PetscCall(KSPDestroy(&jac->kspupper)); 1663 PetscCall(MatDestroy(&jac->B)); 1664 PetscCall(MatDestroy(&jac->C)); 1665 PetscCall(MatDestroy(&jac->H)); 1666 PetscCall(VecDestroy(&jac->u)); 1667 PetscCall(VecDestroy(&jac->v)); 1668 PetscCall(VecDestroy(&jac->Hu)); 1669 PetscCall(VecDestroy(&jac->d)); 1670 PetscCall(PetscFree(jac->vecz)); 1671 PetscCall(PetscViewerDestroy(&jac->gkbviewer)); 1672 jac->isrestrict = PETSC_FALSE; 1673 PetscFunctionReturn(PETSC_SUCCESS); 1674 } 1675 1676 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1677 { 1678 PetscFunctionBegin; 1679 PetscCall(PCReset_FieldSplit(pc)); 1680 PetscCall(PetscFree(pc->data)); 1681 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL)); 1682 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL)); 1683 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL)); 1684 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL)); 1685 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL)); 1686 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL)); 1687 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL)); 1688 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 1689 1690 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 1691 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 1692 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 1693 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 1694 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 1695 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 1696 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 1697 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 1698 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 1699 PetscFunctionReturn(PETSC_SUCCESS); 1700 } 1701 1702 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems *PetscOptionsObject) 1703 { 1704 PetscInt bs; 1705 PetscBool flg; 1706 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1707 PCCompositeType ctype; 1708 1709 PetscFunctionBegin; 1710 PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options"); 1711 PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL)); 1712 PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg)); 1713 if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs)); 1714 jac->diag_use_amat = pc->useAmat; 1715 PetscCall(PetscOptionsBool("-pc_fieldsplit_diag_use_amat", "Use Amat (not Pmat) to extract diagonal fieldsplit blocks", "PCFieldSplitSetDiagUseAmat", jac->diag_use_amat, &jac->diag_use_amat, NULL)); 1716 jac->offdiag_use_amat = pc->useAmat; 1717 PetscCall(PetscOptionsBool("-pc_fieldsplit_off_diag_use_amat", "Use Amat (not Pmat) to extract off-diagonal fieldsplit blocks", "PCFieldSplitSetOffDiagUseAmat", jac->offdiag_use_amat, &jac->offdiag_use_amat, NULL)); 1718 PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL)); 1719 PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */ 1720 PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg)); 1721 if (flg) PetscCall(PCFieldSplitSetType(pc, ctype)); 1722 /* Only setup fields once */ 1723 if ((jac->bs > 0) && (jac->nsplits == 0)) { 1724 /* only allow user to set fields from command line if bs is already known. 1725 otherwise user can set them in PCFieldSplitSetDefaults() */ 1726 PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc)); 1727 if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n")); 1728 } 1729 if (jac->type == PC_COMPOSITE_SCHUR) { 1730 PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg)); 1731 if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n")); 1732 PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_fact_type", "Which off-diagonal parts of the block factorization to use", "PCFieldSplitSetSchurFactType", PCFieldSplitSchurFactTypes, (PetscEnum)jac->schurfactorization, (PetscEnum *)&jac->schurfactorization, NULL)); 1733 PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL)); 1734 PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL)); 1735 } else if (jac->type == PC_COMPOSITE_GKB) { 1736 PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitGKBTol", jac->gkbtol, &jac->gkbtol, NULL)); 1737 PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL)); 1738 PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitGKBNu", jac->gkbnu, &jac->gkbnu, NULL)); 1739 PetscCheck(jac->gkbnu >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nu cannot be less than 0: value %g", (double)jac->gkbnu); 1740 PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL)); 1741 PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL)); 1742 } 1743 /* 1744 In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet. 1745 But after the initial setup of ALL the layers of sub-solvers is completed we do want to call KSPSetFromOptions() on the sub-solvers every time it 1746 is called on the outer solver in case changes were made in the options database 1747 1748 But even after PCSetUp_FieldSplit() is called all the options inside the inner levels of sub-solvers may still not have been set thus we only call the KSPSetFromOptions() 1749 if we know that the entire stack of sub-solvers below this have been complete instantiated, we check this by seeing if any solver iterations are complete. 1750 Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types. 1751 1752 There could be a negative side effect of calling the KSPSetFromOptions() below. 1753 1754 If one captured the PetscObjectState of the options database one could skip these calls if the database has not changed from the previous call 1755 */ 1756 if (jac->issetup) { 1757 PC_FieldSplitLink ilink = jac->head; 1758 if (jac->type == PC_COMPOSITE_SCHUR) { 1759 if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper)); 1760 if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur)); 1761 } 1762 while (ilink) { 1763 if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp)); 1764 ilink = ilink->next; 1765 } 1766 } 1767 PetscOptionsHeadEnd(); 1768 PetscFunctionReturn(PETSC_SUCCESS); 1769 } 1770 1771 static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) 1772 { 1773 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1774 PC_FieldSplitLink ilink, next = jac->head; 1775 char prefix[128]; 1776 PetscInt i; 1777 1778 PetscFunctionBegin; 1779 if (jac->splitdefined) { 1780 PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 1781 PetscFunctionReturn(PETSC_SUCCESS); 1782 } 1783 for (i = 0; i < n; i++) { 1784 PetscCheck(fields[i] < jac->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", fields[i], jac->bs); 1785 PetscCheck(fields[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", fields[i]); 1786 } 1787 PetscCall(PetscNew(&ilink)); 1788 if (splitname) { 1789 PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 1790 } else { 1791 PetscCall(PetscMalloc1(3, &ilink->splitname)); 1792 PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits)); 1793 } 1794 ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */ 1795 PetscCall(PetscMalloc1(n, &ilink->fields)); 1796 PetscCall(PetscArraycpy(ilink->fields, fields, n)); 1797 PetscCall(PetscMalloc1(n, &ilink->fields_col)); 1798 PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n)); 1799 1800 ilink->nfields = n; 1801 ilink->next = NULL; 1802 PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 1803 PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 1804 PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 1805 PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 1806 PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 1807 1808 PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 1809 PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 1810 1811 if (!next) { 1812 jac->head = ilink; 1813 ilink->previous = NULL; 1814 } else { 1815 while (next->next) next = next->next; 1816 next->next = ilink; 1817 ilink->previous = next; 1818 } 1819 jac->nsplits++; 1820 PetscFunctionReturn(PETSC_SUCCESS); 1821 } 1822 1823 static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 1824 { 1825 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1826 1827 PetscFunctionBegin; 1828 *subksp = NULL; 1829 if (n) *n = 0; 1830 if (jac->type == PC_COMPOSITE_SCHUR) { 1831 PetscInt nn; 1832 1833 PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()"); 1834 PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits); 1835 nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0); 1836 PetscCall(PetscMalloc1(nn, subksp)); 1837 (*subksp)[0] = jac->head->ksp; 1838 (*subksp)[1] = jac->kspschur; 1839 if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper; 1840 if (n) *n = nn; 1841 } 1842 PetscFunctionReturn(PETSC_SUCCESS); 1843 } 1844 1845 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp) 1846 { 1847 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1848 1849 PetscFunctionBegin; 1850 PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()"); 1851 PetscCall(PetscMalloc1(jac->nsplits, subksp)); 1852 PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp)); 1853 1854 (*subksp)[1] = jac->kspschur; 1855 if (n) *n = jac->nsplits; 1856 PetscFunctionReturn(PETSC_SUCCESS); 1857 } 1858 1859 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 1860 { 1861 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1862 PetscInt cnt = 0; 1863 PC_FieldSplitLink ilink = jac->head; 1864 1865 PetscFunctionBegin; 1866 PetscCall(PetscMalloc1(jac->nsplits, subksp)); 1867 while (ilink) { 1868 (*subksp)[cnt++] = ilink->ksp; 1869 ilink = ilink->next; 1870 } 1871 PetscCheck(cnt == jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt PCFIELDSPLIT object: number of splits in linked list %" PetscInt_FMT " does not match number in object %" PetscInt_FMT, cnt, jac->nsplits); 1872 if (n) *n = jac->nsplits; 1873 PetscFunctionReturn(PETSC_SUCCESS); 1874 } 1875 1876 /*@C 1877 PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`. 1878 1879 Input Parameters: 1880 + pc - the preconditioner context 1881 - isy - the index set that defines the indices to which the fieldsplit is to be restricted 1882 1883 Level: advanced 1884 1885 Developer Notes: 1886 It seems the resulting `IS`s will not cover the entire space, so 1887 how can they define a convergent preconditioner? Needs explaining. 1888 1889 .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 1890 @*/ 1891 PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy) 1892 { 1893 PetscFunctionBegin; 1894 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1895 PetscValidHeaderSpecific(isy, IS_CLASSID, 2); 1896 PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy)); 1897 PetscFunctionReturn(PETSC_SUCCESS); 1898 } 1899 1900 static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) 1901 { 1902 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1903 PC_FieldSplitLink ilink = jac->head, next; 1904 PetscInt localsize, size, sizez, i; 1905 const PetscInt *ind, *indz; 1906 PetscInt *indc, *indcz; 1907 PetscBool flg; 1908 1909 PetscFunctionBegin; 1910 PetscCall(ISGetLocalSize(isy, &localsize)); 1911 PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy))); 1912 size -= localsize; 1913 while (ilink) { 1914 IS isrl, isr; 1915 PC subpc; 1916 PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl)); 1917 PetscCall(ISGetLocalSize(isrl, &localsize)); 1918 PetscCall(PetscMalloc1(localsize, &indc)); 1919 PetscCall(ISGetIndices(isrl, &ind)); 1920 PetscCall(PetscArraycpy(indc, ind, localsize)); 1921 PetscCall(ISRestoreIndices(isrl, &ind)); 1922 PetscCall(ISDestroy(&isrl)); 1923 for (i = 0; i < localsize; i++) *(indc + i) += size; 1924 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr)); 1925 PetscCall(PetscObjectReference((PetscObject)isr)); 1926 PetscCall(ISDestroy(&ilink->is)); 1927 ilink->is = isr; 1928 PetscCall(PetscObjectReference((PetscObject)isr)); 1929 PetscCall(ISDestroy(&ilink->is_col)); 1930 ilink->is_col = isr; 1931 PetscCall(ISDestroy(&isr)); 1932 PetscCall(KSPGetPC(ilink->ksp, &subpc)); 1933 PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg)); 1934 if (flg) { 1935 IS iszl, isz; 1936 MPI_Comm comm; 1937 PetscCall(ISGetLocalSize(ilink->is, &localsize)); 1938 comm = PetscObjectComm((PetscObject)ilink->is); 1939 PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl)); 1940 PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm)); 1941 sizez -= localsize; 1942 PetscCall(ISGetLocalSize(iszl, &localsize)); 1943 PetscCall(PetscMalloc1(localsize, &indcz)); 1944 PetscCall(ISGetIndices(iszl, &indz)); 1945 PetscCall(PetscArraycpy(indcz, indz, localsize)); 1946 PetscCall(ISRestoreIndices(iszl, &indz)); 1947 PetscCall(ISDestroy(&iszl)); 1948 for (i = 0; i < localsize; i++) *(indcz + i) += sizez; 1949 PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz)); 1950 PetscCall(PCFieldSplitRestrictIS(subpc, isz)); 1951 PetscCall(ISDestroy(&isz)); 1952 } 1953 next = ilink->next; 1954 ilink = next; 1955 } 1956 jac->isrestrict = PETSC_TRUE; 1957 PetscFunctionReturn(PETSC_SUCCESS); 1958 } 1959 1960 static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is) 1961 { 1962 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1963 PC_FieldSplitLink ilink, next = jac->head; 1964 char prefix[128]; 1965 1966 PetscFunctionBegin; 1967 if (jac->splitdefined) { 1968 PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 1969 PetscFunctionReturn(PETSC_SUCCESS); 1970 } 1971 PetscCall(PetscNew(&ilink)); 1972 if (splitname) { 1973 PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 1974 } else { 1975 PetscCall(PetscMalloc1(8, &ilink->splitname)); 1976 PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits)); 1977 } 1978 ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */ 1979 PetscCall(PetscObjectReference((PetscObject)is)); 1980 PetscCall(ISDestroy(&ilink->is)); 1981 ilink->is = is; 1982 PetscCall(PetscObjectReference((PetscObject)is)); 1983 PetscCall(ISDestroy(&ilink->is_col)); 1984 ilink->is_col = is; 1985 ilink->next = NULL; 1986 PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 1987 PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 1988 PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 1989 PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 1990 PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 1991 1992 PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 1993 PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 1994 1995 if (!next) { 1996 jac->head = ilink; 1997 ilink->previous = NULL; 1998 } else { 1999 while (next->next) next = next->next; 2000 next->next = ilink; 2001 ilink->previous = next; 2002 } 2003 jac->nsplits++; 2004 PetscFunctionReturn(PETSC_SUCCESS); 2005 } 2006 2007 /*@C 2008 PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT` 2009 2010 Logically Collective 2011 2012 Input Parameters: 2013 + pc - the preconditioner context 2014 . splitname - name of this split, if `NULL` the number of the split is used 2015 . n - the number of fields in this split 2016 . fields - the fields in this split 2017 - fields_col - generally the same as fields, if it does not match fields then the matrix block that is solved for this set of fields comes from an off-diagonal block 2018 of the matrix and fields_col provides the column indices for that block 2019 2020 Level: intermediate 2021 2022 Notes: 2023 Use `PCFieldSplitSetIS()` to set a general set of indices as a split. 2024 2025 `PCFieldSplitSetFields()` is for defining fields as strided blocks. For example, if the block 2026 size is three then one can define a split as 0, or 1 or 2 or 0,1 or 0,2 or 1,2 which mean 2027 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 2028 where the numbered entries indicate what is in the split. 2029 2030 This function is called once per split (it creates a new split each time). Solve options 2031 for this split will be available under the prefix `-fieldsplit_SPLITNAME_`. 2032 2033 `PCFieldSplitSetIS()` does not support having a fields_col different from fields 2034 2035 Developer Notes: 2036 This routine does not actually create the `IS` representing the split, that is delayed 2037 until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be 2038 available when this routine is called. 2039 2040 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()` 2041 @*/ 2042 PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) 2043 { 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2046 PetscAssertPointer(splitname, 2); 2047 PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname); 2048 PetscAssertPointer(fields, 4); 2049 PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col)); 2050 PetscFunctionReturn(PETSC_SUCCESS); 2051 } 2052 2053 /*@ 2054 PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2055 the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat)) was used to supply the operators. 2056 2057 Logically Collective 2058 2059 Input Parameters: 2060 + pc - the preconditioner object 2061 - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2062 2063 Options Database Key: 2064 . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks 2065 2066 Level: intermediate 2067 2068 .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT` 2069 @*/ 2070 PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg) 2071 { 2072 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2073 PetscBool isfs; 2074 2075 PetscFunctionBegin; 2076 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2077 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 2078 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2079 jac->diag_use_amat = flg; 2080 PetscFunctionReturn(PETSC_SUCCESS); 2081 } 2082 2083 /*@ 2084 PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2085 the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat)) was used to supply the operators. 2086 2087 Logically Collective 2088 2089 Input Parameter: 2090 . pc - the preconditioner object 2091 2092 Output Parameter: 2093 . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2094 2095 Level: intermediate 2096 2097 .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT` 2098 @*/ 2099 PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg) 2100 { 2101 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2102 PetscBool isfs; 2103 2104 PetscFunctionBegin; 2105 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2106 PetscAssertPointer(flg, 2); 2107 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 2108 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2109 *flg = jac->diag_use_amat; 2110 PetscFunctionReturn(PETSC_SUCCESS); 2111 } 2112 2113 /*@ 2114 PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2115 the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat)) was used to supply the operators. 2116 2117 Logically Collective 2118 2119 Input Parameters: 2120 + pc - the preconditioner object 2121 - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2122 2123 Options Database Key: 2124 . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks 2125 2126 Level: intermediate 2127 2128 .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT` 2129 @*/ 2130 PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg) 2131 { 2132 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2133 PetscBool isfs; 2134 2135 PetscFunctionBegin; 2136 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2137 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 2138 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2139 jac->offdiag_use_amat = flg; 2140 PetscFunctionReturn(PETSC_SUCCESS); 2141 } 2142 2143 /*@ 2144 PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2145 the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat)) was used to supply the operators. 2146 2147 Logically Collective 2148 2149 Input Parameter: 2150 . pc - the preconditioner object 2151 2152 Output Parameter: 2153 . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2154 2155 Level: intermediate 2156 2157 .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT` 2158 @*/ 2159 PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg) 2160 { 2161 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2162 PetscBool isfs; 2163 2164 PetscFunctionBegin; 2165 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2166 PetscAssertPointer(flg, 2); 2167 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 2168 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2169 *flg = jac->offdiag_use_amat; 2170 PetscFunctionReturn(PETSC_SUCCESS); 2171 } 2172 2173 /*@C 2174 PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT` 2175 2176 Logically Collective 2177 2178 Input Parameters: 2179 + pc - the preconditioner context 2180 . splitname - name of this split, if `NULL` the number of the split is used 2181 - is - the index set that defines the elements in this split 2182 2183 Level: intermediate 2184 2185 Notes: 2186 Use `PCFieldSplitSetFields()`, for splits defined by strided types. 2187 2188 This function is called once per split (it creates a new split each time). Solve options 2189 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 2190 2191 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()` 2192 @*/ 2193 PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is) 2194 { 2195 PetscFunctionBegin; 2196 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2197 if (splitname) PetscAssertPointer(splitname, 2); 2198 PetscValidHeaderSpecific(is, IS_CLASSID, 3); 2199 PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is)); 2200 PetscFunctionReturn(PETSC_SUCCESS); 2201 } 2202 2203 /*@C 2204 PCFieldSplitGetIS - Retrieves the elements for a split as an `IS` 2205 2206 Logically Collective 2207 2208 Input Parameters: 2209 + pc - the preconditioner context 2210 - splitname - name of this split 2211 2212 Output Parameter: 2213 . is - the index set that defines the elements in this split, or `NULL` if the split is not found 2214 2215 Level: intermediate 2216 2217 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()` 2218 @*/ 2219 PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is) 2220 { 2221 PetscFunctionBegin; 2222 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2223 PetscAssertPointer(splitname, 2); 2224 PetscAssertPointer(is, 3); 2225 { 2226 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2227 PC_FieldSplitLink ilink = jac->head; 2228 PetscBool found; 2229 2230 *is = NULL; 2231 while (ilink) { 2232 PetscCall(PetscStrcmp(ilink->splitname, splitname, &found)); 2233 if (found) { 2234 *is = ilink->is; 2235 break; 2236 } 2237 ilink = ilink->next; 2238 } 2239 } 2240 PetscFunctionReturn(PETSC_SUCCESS); 2241 } 2242 2243 /*@C 2244 PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS` 2245 2246 Logically Collective 2247 2248 Input Parameters: 2249 + pc - the preconditioner context 2250 - index - index of this split 2251 2252 Output Parameter: 2253 . is - the index set that defines the elements in this split 2254 2255 Level: intermediate 2256 2257 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()` 2258 @*/ 2259 PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is) 2260 { 2261 PetscFunctionBegin; 2262 PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index); 2263 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2264 PetscAssertPointer(is, 3); 2265 { 2266 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2267 PC_FieldSplitLink ilink = jac->head; 2268 PetscInt i = 0; 2269 PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits); 2270 2271 while (i < index) { 2272 ilink = ilink->next; 2273 ++i; 2274 } 2275 PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is)); 2276 } 2277 PetscFunctionReturn(PETSC_SUCCESS); 2278 } 2279 2280 /*@ 2281 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 2282 fieldsplit preconditioner when calling `PCFieldSplitSetIS()`. If not set the matrix block size is used. 2283 2284 Logically Collective 2285 2286 Input Parameters: 2287 + pc - the preconditioner context 2288 - bs - the block size 2289 2290 Level: intermediate 2291 2292 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 2293 @*/ 2294 PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs) 2295 { 2296 PetscFunctionBegin; 2297 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2298 PetscValidLogicalCollectiveInt(pc, bs, 2); 2299 PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs)); 2300 PetscFunctionReturn(PETSC_SUCCESS); 2301 } 2302 2303 /*@C 2304 PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits 2305 2306 Collective 2307 2308 Input Parameter: 2309 . pc - the preconditioner context 2310 2311 Output Parameters: 2312 + n - the number of splits 2313 - subksp - the array of `KSP` contexts 2314 2315 Level: advanced 2316 2317 Notes: 2318 After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2319 (not the `KSP`, just the array that contains them). 2320 2321 You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`. 2322 2323 If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the 2324 Schur complement and the `KSP` object used to iterate over the Schur complement. 2325 To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`. 2326 2327 If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the 2328 inner linear system defined by the matrix H in each loop. 2329 2330 Fortran Notes: 2331 You must pass in a `KSP` array that is large enough to contain all the `KSP`s. 2332 You can call `PCFieldSplitGetSubKSP`(pc,n,`PETSC_NULL_KSP`,ierr) to determine how large the 2333 `KSP` array must be. 2334 2335 Developer Notes: 2336 There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2337 2338 The Fortran interface should be modernized to return directly the array of values. 2339 2340 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()` 2341 @*/ 2342 PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2343 { 2344 PetscFunctionBegin; 2345 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2346 if (n) PetscAssertPointer(n, 2); 2347 PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 2348 PetscFunctionReturn(PETSC_SUCCESS); 2349 } 2350 2351 /*@C 2352 PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT` 2353 2354 Collective 2355 2356 Input Parameter: 2357 . pc - the preconditioner context 2358 2359 Output Parameters: 2360 + n - the number of splits 2361 - subksp - the array of `KSP` contexts 2362 2363 Level: advanced 2364 2365 Notes: 2366 After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2367 (not the `KSP` just the array that contains them). 2368 2369 You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`. 2370 2371 If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order) 2372 + 1 - the `KSP` used for the (1,1) block 2373 . 2 - the `KSP` used for the Schur complement (not the one used for the interior Schur solver) 2374 - 3 - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block). 2375 2376 It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`. 2377 2378 Fortran Notes: 2379 You must pass in a `KSP` array that is large enough to contain all the local `KSP`s. 2380 You can call `PCFieldSplitSchurGetSubKSP`(pc,n,`PETSC_NULL_KSP`,ierr) to determine how large the 2381 `KSP` array must be. 2382 2383 Developer Notes: 2384 There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2385 2386 Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged? 2387 2388 The Fortran interface should be modernized to return directly the array of values. 2389 2390 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()` 2391 @*/ 2392 PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2393 { 2394 PetscFunctionBegin; 2395 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2396 if (n) PetscAssertPointer(n, 2); 2397 PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 2398 PetscFunctionReturn(PETSC_SUCCESS); 2399 } 2400 2401 /*@ 2402 PCFieldSplitSetSchurPre - Indicates from what operator the preconditioner is constructucted for the Schur complement. 2403 The default is the A11 matrix. 2404 2405 Collective 2406 2407 Input Parameters: 2408 + pc - the preconditioner context 2409 . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default), 2410 `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`, 2411 `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL` 2412 - pre - matrix to use for preconditioning, or `NULL` 2413 2414 Options Database Keys: 2415 + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments 2416 - -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator 2417 2418 Level: intermediate 2419 2420 Notes: 2421 If ptype is 2422 + a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner 2423 matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix 2424 . self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix: 2425 The only preconditioner that currently works with this symbolic representation matrix object is the `PCLSC` 2426 preconditioner 2427 . user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument 2428 to this function). 2429 . selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation Sp = A11 - A10 inv(diag(A00)) A01 2430 This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be 2431 lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump` 2432 - full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation 2433 computed internally by `PCFIELDSPLIT` (this is expensive) 2434 useful mostly as a test that the Schur complement approach can work for your problem 2435 2436 When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense 2437 with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a ptype of self and 2438 `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement. 2439 2440 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, 2441 `MatSchurComplementSetAinvType()`, `PCLSC`, 2442 2443 @*/ 2444 PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2445 { 2446 PetscFunctionBegin; 2447 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2448 PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre)); 2449 PetscFunctionReturn(PETSC_SUCCESS); 2450 } 2451 2452 PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2453 { 2454 return PCFieldSplitSetSchurPre(pc, ptype, pre); 2455 } /* Deprecated name */ 2456 2457 /*@ 2458 PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be 2459 preconditioned. See `PCFieldSplitSetSchurPre()` for details. 2460 2461 Logically Collective 2462 2463 Input Parameter: 2464 . pc - the preconditioner context 2465 2466 Output Parameters: 2467 + ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER` 2468 - pre - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL` 2469 2470 Level: intermediate 2471 2472 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC` 2473 2474 @*/ 2475 PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2476 { 2477 PetscFunctionBegin; 2478 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2479 PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre)); 2480 PetscFunctionReturn(PETSC_SUCCESS); 2481 } 2482 2483 /*@ 2484 PCFieldSplitSchurGetS - extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately 2485 2486 Not Collective 2487 2488 Input Parameter: 2489 . pc - the preconditioner context 2490 2491 Output Parameter: 2492 . S - the Schur complement matrix 2493 2494 Level: advanced 2495 2496 Note: 2497 This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`. 2498 2499 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`, 2500 `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()` 2501 @*/ 2502 PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S) 2503 { 2504 const char *t; 2505 PetscBool isfs; 2506 PC_FieldSplit *jac; 2507 2508 PetscFunctionBegin; 2509 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2510 PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 2511 PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 2512 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 2513 jac = (PC_FieldSplit *)pc->data; 2514 PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 2515 if (S) *S = jac->schur; 2516 PetscFunctionReturn(PETSC_SUCCESS); 2517 } 2518 2519 /*@ 2520 PCFieldSplitSchurRestoreS - returns the `MATSCHURCOMPLEMENT` matrix used by this `PC` 2521 2522 Not Collective 2523 2524 Input Parameters: 2525 + pc - the preconditioner context 2526 - S - the Schur complement matrix 2527 2528 Level: advanced 2529 2530 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()` 2531 @*/ 2532 PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S) 2533 { 2534 const char *t; 2535 PetscBool isfs; 2536 PC_FieldSplit *jac; 2537 2538 PetscFunctionBegin; 2539 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2540 PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 2541 PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 2542 PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 2543 jac = (PC_FieldSplit *)pc->data; 2544 PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 2545 PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten"); 2546 PetscFunctionReturn(PETSC_SUCCESS); 2547 } 2548 2549 static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2550 { 2551 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2552 2553 PetscFunctionBegin; 2554 jac->schurpre = ptype; 2555 if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) { 2556 PetscCall(MatDestroy(&jac->schur_user)); 2557 jac->schur_user = pre; 2558 PetscCall(PetscObjectReference((PetscObject)jac->schur_user)); 2559 } 2560 PetscFunctionReturn(PETSC_SUCCESS); 2561 } 2562 2563 static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2564 { 2565 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2566 2567 PetscFunctionBegin; 2568 if (ptype) *ptype = jac->schurpre; 2569 if (pre) *pre = jac->schur_user; 2570 PetscFunctionReturn(PETSC_SUCCESS); 2571 } 2572 2573 /*@ 2574 PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner 2575 2576 Collective 2577 2578 Input Parameters: 2579 + pc - the preconditioner context 2580 - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default 2581 2582 Options Database Key: 2583 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full` 2584 2585 Level: intermediate 2586 2587 Notes: 2588 The FULL factorization is 2589 2590 .vb 2591 (A B) = (1 0) (A 0) (1 Ainv*B) = L D U 2592 (C E) (C*Ainv 1) (0 S) (0 1) 2593 .vb 2594 where S = E - C*Ainv*B. In practice, the full factorization is applied via block triangular solves with the grouping L*(D*U). UPPER uses D*U, LOWER uses L*D, 2595 and DIAG is the diagonal part with the sign of S flipped (because this makes the preconditioner positive definite for many formulations, thus allowing the use of `KSPMINRES)`. 2596 Sign flipping of S can be turned off with `PCFieldSplitSetSchurScale()`. 2597 2598 If A and S are solved exactly 2599 .vb 2600 *) FULL factorization is a direct solver. 2601 *) The preconditioned operator with LOWER or UPPER has all eigenvalues equal to 1 and minimal polynomial of degree 2, so `KSPGMRES` converges in 2 iterations. 2602 *) With DIAG, the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so `KSPGMRES` converges in at most 4 iterations. 2603 .ve 2604 2605 If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner 2606 application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. 2607 2608 For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with `KSPMINRES`. 2609 2610 A flexible method like `KSPFGMRES` or `KSPGCR` must be used if the fieldsplit preconditioner is nonlinear (e.g. a few iterations of a Krylov method is used to solve with A or S). 2611 2612 References: 2613 + * - Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000). 2614 - * - Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001). 2615 2616 .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()` 2617 @*/ 2618 PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype) 2619 { 2620 PetscFunctionBegin; 2621 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2622 PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype)); 2623 PetscFunctionReturn(PETSC_SUCCESS); 2624 } 2625 2626 static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype) 2627 { 2628 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2629 2630 PetscFunctionBegin; 2631 jac->schurfactorization = ftype; 2632 PetscFunctionReturn(PETSC_SUCCESS); 2633 } 2634 2635 /*@ 2636 PCFieldSplitSetSchurScale - Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`. 2637 2638 Collective 2639 2640 Input Parameters: 2641 + pc - the preconditioner context 2642 - scale - scaling factor for the Schur complement 2643 2644 Options Database Key: 2645 . -pc_fieldsplit_schur_scale - default is -1.0 2646 2647 Level: intermediate 2648 2649 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()` 2650 @*/ 2651 PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale) 2652 { 2653 PetscFunctionBegin; 2654 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2655 PetscValidLogicalCollectiveScalar(pc, scale, 2); 2656 PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale)); 2657 PetscFunctionReturn(PETSC_SUCCESS); 2658 } 2659 2660 static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale) 2661 { 2662 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2663 2664 PetscFunctionBegin; 2665 jac->schurscale = scale; 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@C 2670 PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 2671 2672 Collective 2673 2674 Input Parameter: 2675 . pc - the preconditioner context 2676 2677 Output Parameters: 2678 + A00 - the (0,0) block 2679 . A01 - the (0,1) block 2680 . A10 - the (1,0) block 2681 - A11 - the (1,1) block 2682 2683 Level: advanced 2684 2685 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()` 2686 @*/ 2687 PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11) 2688 { 2689 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2690 2691 PetscFunctionBegin; 2692 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2693 PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 2694 if (A00) *A00 = jac->pmat[0]; 2695 if (A01) *A01 = jac->B; 2696 if (A10) *A10 = jac->C; 2697 if (A11) *A11 = jac->pmat[1]; 2698 PetscFunctionReturn(PETSC_SUCCESS); 2699 } 2700 2701 /*@ 2702 PCFieldSplitSetGKBTol - Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner in `PCFIELDSPLIT` 2703 2704 Collective 2705 2706 Input Parameters: 2707 + pc - the preconditioner context 2708 - tolerance - the solver tolerance 2709 2710 Options Database Key: 2711 . -pc_fieldsplit_gkb_tol - default is 1e-5 2712 2713 Level: intermediate 2714 2715 Note: 2716 The generalized GKB algorithm uses a lower bound estimate of the error in energy norm as stopping criterion. 2717 It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than 2718 this estimate, the stopping criterion is satisfactory in practical cases [A13]. 2719 2720 References: 2721 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2722 2723 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()` 2724 @*/ 2725 PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance) 2726 { 2727 PetscFunctionBegin; 2728 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2729 PetscValidLogicalCollectiveReal(pc, tolerance, 2); 2730 PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance)); 2731 PetscFunctionReturn(PETSC_SUCCESS); 2732 } 2733 2734 static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance) 2735 { 2736 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2737 2738 PetscFunctionBegin; 2739 jac->gkbtol = tolerance; 2740 PetscFunctionReturn(PETSC_SUCCESS); 2741 } 2742 2743 /*@ 2744 PCFieldSplitSetGKBMaxit - Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner in `PCFIELDSPLIT` 2745 2746 Collective 2747 2748 Input Parameters: 2749 + pc - the preconditioner context 2750 - maxit - the maximum number of iterations 2751 2752 Options Database Key: 2753 . -pc_fieldsplit_gkb_maxit - default is 100 2754 2755 Level: intermediate 2756 2757 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()` 2758 @*/ 2759 PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit) 2760 { 2761 PetscFunctionBegin; 2762 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2763 PetscValidLogicalCollectiveInt(pc, maxit, 2); 2764 PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit)); 2765 PetscFunctionReturn(PETSC_SUCCESS); 2766 } 2767 2768 static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit) 2769 { 2770 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2771 2772 PetscFunctionBegin; 2773 jac->gkbmaxit = maxit; 2774 PetscFunctionReturn(PETSC_SUCCESS); 2775 } 2776 2777 /*@ 2778 PCFieldSplitSetGKBDelay - Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization in `PCFIELDSPLIT` 2779 preconditioner. 2780 2781 Collective 2782 2783 Input Parameters: 2784 + pc - the preconditioner context 2785 - delay - the delay window in the lower bound estimate 2786 2787 Options Database Key: 2788 . -pc_fieldsplit_gkb_delay - default is 5 2789 2790 Level: intermediate 2791 2792 Note: 2793 The algorithm uses a lower bound estimate of the error in energy norm as stopping criterion. The lower bound of the error ||u-u^k||_H 2794 is expressed as a truncated sum. The error at iteration k can only be measured at iteration (k + delay), and thus the algorithm needs 2795 at least (delay + 1) iterations to stop. For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to 2796 2797 References: 2798 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2799 2800 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 2801 @*/ 2802 PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay) 2803 { 2804 PetscFunctionBegin; 2805 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2806 PetscValidLogicalCollectiveInt(pc, delay, 2); 2807 PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay)); 2808 PetscFunctionReturn(PETSC_SUCCESS); 2809 } 2810 2811 static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay) 2812 { 2813 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2814 2815 PetscFunctionBegin; 2816 jac->gkbdelay = delay; 2817 PetscFunctionReturn(PETSC_SUCCESS); 2818 } 2819 2820 /*@ 2821 PCFieldSplitSetGKBNu - Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the Golub-Kahan bidiagonalization preconditioner 2822 in `PCFIELDSPLIT` 2823 2824 Collective 2825 2826 Input Parameters: 2827 + pc - the preconditioner context 2828 - nu - the shift parameter 2829 2830 Options Database Key: 2831 . -pc_fieldsplit_gkb_nu - default is 1 2832 2833 Level: intermediate 2834 2835 Notes: 2836 This shift is in general done to obtain better convergence properties for the outer loop of the algorithm. This is often achieved by choosing nu sufficiently big. However, 2837 if nu is chosen too big, the matrix H might be badly conditioned and the solution of the linear system Hx = b in the inner loop becomes difficult. It is therefore 2838 necessary to find a good balance in between the convergence of the inner and outer loop. 2839 2840 For nu = 0, no shift is done. In this case A00 has to be positive definite. The matrix N in [Ar13] is then chosen as identity. 2841 2842 References: 2843 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2844 2845 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 2846 @*/ 2847 PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu) 2848 { 2849 PetscFunctionBegin; 2850 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2851 PetscValidLogicalCollectiveReal(pc, nu, 2); 2852 PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu)); 2853 PetscFunctionReturn(PETSC_SUCCESS); 2854 } 2855 2856 static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu) 2857 { 2858 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2859 2860 PetscFunctionBegin; 2861 jac->gkbnu = nu; 2862 PetscFunctionReturn(PETSC_SUCCESS); 2863 } 2864 2865 static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type) 2866 { 2867 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2868 2869 PetscFunctionBegin; 2870 jac->type = type; 2871 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 2872 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 2873 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 2874 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 2875 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 2876 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 2877 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 2878 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 2879 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 2880 2881 if (type == PC_COMPOSITE_SCHUR) { 2882 pc->ops->apply = PCApply_FieldSplit_Schur; 2883 pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur; 2884 pc->ops->view = PCView_FieldSplit_Schur; 2885 2886 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur)); 2887 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit)); 2888 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit)); 2889 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit)); 2890 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit)); 2891 } else if (type == PC_COMPOSITE_GKB) { 2892 pc->ops->apply = PCApply_FieldSplit_GKB; 2893 pc->ops->view = PCView_FieldSplit_GKB; 2894 2895 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 2896 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit)); 2897 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit)); 2898 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit)); 2899 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit)); 2900 } else { 2901 pc->ops->apply = PCApply_FieldSplit; 2902 pc->ops->view = PCView_FieldSplit; 2903 2904 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 2905 } 2906 PetscFunctionReturn(PETSC_SUCCESS); 2907 } 2908 2909 static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs) 2910 { 2911 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2912 2913 PetscFunctionBegin; 2914 PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs); 2915 PetscCheck(jac->bs <= 0 || jac->bs == bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change fieldsplit blocksize from %" PetscInt_FMT " to %" PetscInt_FMT " after it has been set", jac->bs, bs); 2916 jac->bs = bs; 2917 PetscFunctionReturn(PETSC_SUCCESS); 2918 } 2919 2920 static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[]) 2921 { 2922 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2923 PC_FieldSplitLink ilink_current = jac->head; 2924 IS is_owned; 2925 2926 PetscFunctionBegin; 2927 jac->coordinates_set = PETSC_TRUE; // Internal flag 2928 PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL)); 2929 2930 while (ilink_current) { 2931 // For each IS, embed it to get local coords indces 2932 IS is_coords; 2933 PetscInt ndofs_block; 2934 const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block 2935 2936 // Setting drop to true for safety. It should make no difference. 2937 PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords)); 2938 PetscCall(ISGetLocalSize(is_coords, &ndofs_block)); 2939 PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration)); 2940 2941 // Allocate coordinates vector and set it directly 2942 PetscCall(PetscMalloc1(ndofs_block * dim, &(ilink_current->coords))); 2943 for (PetscInt dof = 0; dof < ndofs_block; ++dof) { 2944 for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d]; 2945 } 2946 ilink_current->dim = dim; 2947 ilink_current->ndofs = ndofs_block; 2948 PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration)); 2949 PetscCall(ISDestroy(&is_coords)); 2950 ilink_current = ilink_current->next; 2951 } 2952 PetscCall(ISDestroy(&is_owned)); 2953 PetscFunctionReturn(PETSC_SUCCESS); 2954 } 2955 2956 /*@ 2957 PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 2958 2959 Collective 2960 2961 Input Parameters: 2962 + pc - the preconditioner context 2963 - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 2964 2965 Options Database Key: 2966 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 2967 2968 Level: intermediate 2969 2970 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 2971 `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 2972 @*/ 2973 PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type) 2974 { 2975 PetscFunctionBegin; 2976 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2977 PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type)); 2978 PetscFunctionReturn(PETSC_SUCCESS); 2979 } 2980 2981 /*@ 2982 PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 2983 2984 Not collective 2985 2986 Input Parameter: 2987 . pc - the preconditioner context 2988 2989 Output Parameter: 2990 . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 2991 2992 Level: intermediate 2993 2994 .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 2995 `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 2996 @*/ 2997 PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 2998 { 2999 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3000 3001 PetscFunctionBegin; 3002 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3003 PetscAssertPointer(type, 2); 3004 *type = jac->type; 3005 PetscFunctionReturn(PETSC_SUCCESS); 3006 } 3007 3008 /*@ 3009 PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 3010 3011 Logically Collective 3012 3013 Input Parameters: 3014 + pc - the preconditioner context 3015 - flg - boolean indicating whether to use field splits defined by the `DM` 3016 3017 Options Database Key: 3018 . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM` 3019 3020 Level: intermediate 3021 3022 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `PCFieldSplitSetFields()`, `PCFieldsplitSetIS()` 3023 @*/ 3024 PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg) 3025 { 3026 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3027 PetscBool isfs; 3028 3029 PetscFunctionBegin; 3030 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3031 PetscValidLogicalCollectiveBool(pc, flg, 2); 3032 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 3033 if (isfs) jac->dm_splits = flg; 3034 PetscFunctionReturn(PETSC_SUCCESS); 3035 } 3036 3037 /*@ 3038 PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 3039 3040 Logically Collective 3041 3042 Input Parameter: 3043 . pc - the preconditioner context 3044 3045 Output Parameter: 3046 . flg - boolean indicating whether to use field splits defined by the `DM` 3047 3048 Level: intermediate 3049 3050 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `PCFieldSplitSetFields()`, `PCFieldsplitSetIS()` 3051 @*/ 3052 PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg) 3053 { 3054 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3055 PetscBool isfs; 3056 3057 PetscFunctionBegin; 3058 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3059 PetscAssertPointer(flg, 2); 3060 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 3061 if (isfs) { 3062 if (flg) *flg = jac->dm_splits; 3063 } 3064 PetscFunctionReturn(PETSC_SUCCESS); 3065 } 3066 3067 /*@ 3068 PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 3069 3070 Logically Collective 3071 3072 Input Parameter: 3073 . pc - the preconditioner context 3074 3075 Output Parameter: 3076 . flg - boolean indicating whether to detect fields or not 3077 3078 Level: intermediate 3079 3080 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()` 3081 @*/ 3082 PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg) 3083 { 3084 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3085 3086 PetscFunctionBegin; 3087 *flg = jac->detect; 3088 PetscFunctionReturn(PETSC_SUCCESS); 3089 } 3090 3091 /*@ 3092 PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 3093 3094 Logically Collective 3095 3096 Input Parameter: 3097 . pc - the preconditioner context 3098 3099 Output Parameter: 3100 . flg - boolean indicating whether to detect fields or not 3101 3102 Options Database Key: 3103 . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point 3104 3105 Level: intermediate 3106 3107 Note: 3108 Also sets the split type to `PC_COMPOSITE_SCHUR` (see `PCFieldSplitSetType()`) and the Schur preconditioner type to `PC_FIELDSPLIT_SCHUR_PRE_SELF` (see `PCFieldSplitSetSchurPre()`). 3109 3110 .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF` 3111 @*/ 3112 PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg) 3113 { 3114 PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3115 3116 PetscFunctionBegin; 3117 jac->detect = flg; 3118 if (jac->detect) { 3119 PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR)); 3120 PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL)); 3121 } 3122 PetscFunctionReturn(PETSC_SUCCESS); 3123 } 3124 3125 /*MC 3126 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 3127 collections of variables (that may overlap) called splits. See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details. 3128 3129 Options Database Keys: 3130 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split 3131 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 3132 been supplied explicitly by `-pc_fieldsplit_%d_fields` 3133 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 3134 . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting 3135 . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`; see `PCFieldSplitSetSchurPre()` 3136 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using `-pc_fieldsplit_type schur`; see `PCFieldSplitSetSchurFactType()` 3137 - -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver 3138 3139 Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` . 3140 The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_` 3141 For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields. 3142 3143 To set options on the solvers for each block append `-fieldsplit_` to all the `PC` 3144 options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1` 3145 3146 To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()` 3147 and set the options directly on the resulting `KSP` object 3148 3149 Level: intermediate 3150 3151 Notes: 3152 Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries and `PCFieldSplitSetIS()` 3153 to define a split by an arbitrary collection of entries. 3154 3155 If no splits are set the default is used. The splits are defined by entries strided by bs, 3156 beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`, 3157 if this is not called the block size defaults to the blocksize of the second matrix passed 3158 to `KSPSetOperators()`/`PCSetOperators()`. 3159 3160 For the Schur complement preconditioner if 3161 3162 ```{math} 3163 J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right] 3164 ``` 3165 3166 the preconditioner using `full` factorization is logically 3167 ```{math} 3168 \left[\begin{array}{cc} I & -\text{ksp}(A_{00}) \\ 0 & I \end{array}\right] \left[\begin{array}{cc} \text{inv}(A_{00}) & 0 \\ 0 & \text{ksp}(S) \end{array}\right] \left[\begin{array}{cc} I & 0 \\ -A_{10} \text{ksp}(A_{00}) & I \end{array}\right] 3169 ``` 3170 where the action of $\text{inv}(A_{00})$ is applied using the KSP solver with prefix `-fieldsplit_0_`. $S$ is the Schur complement 3171 ```{math} 3172 S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01} 3173 ``` 3174 which is usually dense and not stored explicitly. The action of $\text{ksp}(S)$ is computed using the KSP solver with prefix `-fieldsplit_splitname_` (where `splitname` was given 3175 in providing the SECOND split or 1 if not given). For `PCFieldSplitGetSubKSP()` when field number is 0, 3176 it returns the KSP associated with `-fieldsplit_0_` while field number 1 gives `-fieldsplit_1_` KSP. By default 3177 $A_{11}$ is used to construct a preconditioner for $S$, use `PCFieldSplitSetSchurPre()` for all the possible ways to construct the preconditioner for $S$. 3178 3179 The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above, 3180 `diag` gives 3181 ```{math} 3182 \left[\begin{array}{cc} \text{inv}(A_{00}) & 0 \\ 0 & -\text{ksp}(S) \end{array}\right] 3183 ``` 3184 Note that, slightly counter intuitively, there is a negative in front of the $\text{ksp}(S)$ so that the preconditioner is positive definite. For SPD matrices $J$, the sign flip 3185 can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of 3186 ```{math} 3187 \left[\begin{array}{cc} A_{00} & 0 \\ A_{10} & S \end{array}\right] 3188 ``` 3189 where the inverses of A_{00} and S are applied using KSPs. The upper factorization is the inverse of 3190 ```{math} 3191 \left[\begin{array}{cc} A_{00} & A_{01} \\ 0 & S \end{array}\right] 3192 ``` 3193 where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s. 3194 3195 If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS` 3196 is used automatically for a second block. 3197 3198 The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1. 3199 Generally it should be used with the `MATAIJ` format. 3200 3201 The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see, 3202 for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`. 3203 One can also use `PCFIELDSPLIT` 3204 inside a smoother resulting in "Distributive Smoothers". 3205 3206 See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`. 3207 3208 The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the 3209 residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables. 3210 3211 The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape 3212 ```{math} 3213 \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right] 3214 ``` 3215 with $A_{00}$ positive semi-definite. The implementation follows {cite}`arioli2013`. Therein, we choose $N := 1/\nu * I$ and the $(1,1)$-block of the matrix is modified to $H = _{A00} + \nu*A_{01}*A_{01}'$. 3216 A linear system $Hx = b$ has to be solved in each iteration of the GKB algorithm. This solver is chosen with the option prefix `-fieldsplit_0_`. 3217 3218 Developer Note: 3219 The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their 3220 user API. 3221 3222 .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`, 3223 `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`, 3224 `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`, 3225 `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()` 3226 M*/ 3227 3228 PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) 3229 { 3230 PC_FieldSplit *jac; 3231 3232 PetscFunctionBegin; 3233 PetscCall(PetscNew(&jac)); 3234 3235 jac->bs = -1; 3236 jac->nsplits = 0; 3237 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 3238 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 3239 jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 3240 jac->schurscale = -1.0; 3241 jac->dm_splits = PETSC_TRUE; 3242 jac->detect = PETSC_FALSE; 3243 jac->gkbtol = 1e-5; 3244 jac->gkbdelay = 5; 3245 jac->gkbnu = 1; 3246 jac->gkbmaxit = 100; 3247 jac->gkbmonitor = PETSC_FALSE; 3248 jac->coordinates_set = PETSC_FALSE; 3249 3250 pc->data = (void *)jac; 3251 3252 pc->ops->apply = PCApply_FieldSplit; 3253 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 3254 pc->ops->setup = PCSetUp_FieldSplit; 3255 pc->ops->reset = PCReset_FieldSplit; 3256 pc->ops->destroy = PCDestroy_FieldSplit; 3257 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 3258 pc->ops->view = PCView_FieldSplit; 3259 pc->ops->applyrichardson = NULL; 3260 3261 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit)); 3262 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 3263 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit)); 3264 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit)); 3265 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit)); 3266 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit)); 3267 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit)); 3268 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit)); 3269 PetscFunctionReturn(PETSC_SUCCESS); 3270 } 3271