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