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