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