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