1af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
2a80b646eSBarry Smith #include <petsc/private/kspimpl.h> /* This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/
3d484b384SBoris Martin #include <petsc/private/matimpl.h> /* MatScatterDense_Private() for PCMatApply() */
41e25c274SJed Brown #include <petscdm.h>
5f7cbcdf3SPierre Jolivet #include <petscdevice.h>
6f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA)
7f7cbcdf3SPierre Jolivet #include <petscdevice_cuda.h>
8f7cbcdf3SPierre Jolivet #endif
9f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP)
10f7cbcdf3SPierre Jolivet #include <petscdevice_hip.h>
11f7cbcdf3SPierre Jolivet #endif
120971522cSBarry Smith
130a545947SLisandro Dalcin const char *const PCFieldSplitSchurPreTypes[] = {"SELF", "SELFP", "A11", "USER", "FULL", "PCFieldSplitSchurPreType", "PC_FIELDSPLIT_SCHUR_PRE_", NULL};
140a545947SLisandro Dalcin const char *const PCFieldSplitSchurFactTypes[] = {"DIAG", "LOWER", "UPPER", "FULL", "PCFieldSplitSchurFactType", "PC_FIELDSPLIT_SCHUR_FACT_", NULL};
15c5d2311dSJed Brown
169df09d43SBarry Smith 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;
179df09d43SBarry Smith
180971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
190971522cSBarry Smith struct _PC_FieldSplitLink {
2069a612a9SBarry Smith KSP ksp;
21443836d0SMatthew G Knepley Vec x, y, z;
22f5b94327SPierre Jolivet Mat X, Y, Z;
23db4c96c1SJed Brown char *splitname;
240971522cSBarry Smith PetscInt nfields;
255d4c12cdSJungho Lee PetscInt *fields, *fields_col;
261b9fc7fcSBarry Smith VecScatter sctx;
27f5f0d762SBarry Smith IS is, is_col;
2851f519a2SBarry Smith PC_FieldSplitLink next, previous;
299df09d43SBarry Smith PetscLogEvent event;
305ddf11f8SNicolas Barnafi
315ddf11f8SNicolas Barnafi /* Used only when setting coordinates with PCSetCoordinates */
325ddf11f8SNicolas Barnafi PetscInt dim;
335ddf11f8SNicolas Barnafi PetscInt ndofs;
345ddf11f8SNicolas Barnafi PetscReal *coords;
350971522cSBarry Smith };
360971522cSBarry Smith
370971522cSBarry Smith typedef struct {
3868dd23aaSBarry Smith PCCompositeType type;
39ace3abfcSBarry Smith PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
40ace3abfcSBarry Smith PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
4130ad9308SMatthew Knepley PetscInt bs; /* Block size for IS and Mat structures */
4230ad9308SMatthew Knepley PetscInt nsplits; /* Number of field divisions defined */
4379416396SBarry Smith Vec *x, *y, w1, w2;
44519d70e2SJed Brown Mat *mat; /* The diagonal block for each split */
45519d70e2SJed Brown Mat *pmat; /* The preconditioning diagonal block for each split */
4630ad9308SMatthew Knepley Mat *Afield; /* The rows of the matrix associated with each split */
47ace3abfcSBarry Smith PetscBool issetup;
482fa5cd67SKarl Rupp
4930ad9308SMatthew Knepley /* Only used when Schur complement preconditioning is used */
5030ad9308SMatthew Knepley Mat B; /* The (0,1) block */
5130ad9308SMatthew Knepley Mat C; /* The (1,0) block */
52443836d0SMatthew G Knepley Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */
537addb90fSBarry Smith Mat schurp; /* Assembled approximation to S built by MatSchurComplement to be used as a matrix for constructing the preconditioner when solving with S */
547addb90fSBarry Smith Mat schur_user; /* User-provided matrix for constructing the preconditioner for the Schur complement */
557addb90fSBarry Smith PCFieldSplitSchurPreType schurpre; /* Determines which matrix is used for the Schur complement */
56c9c6ffaaSJed Brown PCFieldSplitSchurFactType schurfactorization;
5730ad9308SMatthew Knepley KSP kspschur; /* The solver for S */
58443836d0SMatthew G Knepley KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */
59c096484dSStefano Zampini PetscScalar schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */
60c096484dSStefano Zampini
61a51937d4SCarola Kruse /* Only used when Golub-Kahan bidiagonalization preconditioning is used */
62a51937d4SCarola Kruse Mat H; /* The modified matrix H = A00 + nu*A01*A01' */
63a51937d4SCarola Kruse PetscReal gkbtol; /* Stopping tolerance for lower bound estimate */
64a51937d4SCarola Kruse PetscInt gkbdelay; /* The delay window for the stopping criterion */
65a51937d4SCarola Kruse PetscReal gkbnu; /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */
66a51937d4SCarola Kruse PetscInt gkbmaxit; /* Maximum number of iterations for outer loop */
67de482cd7SCarola Kruse PetscBool gkbmonitor; /* Monitor for gkb iterations and the lower bound error */
68de482cd7SCarola Kruse PetscViewer gkbviewer; /* Viewer context for gkbmonitor */
69e071a0a4SCarola Kruse Vec u, v, d, Hu; /* Work vectors for the GKB algorithm */
70e071a0a4SCarola Kruse PetscScalar *vecz; /* Contains intermediate values, eg for lower bound */
71a51937d4SCarola Kruse
7297bbdb24SBarry Smith PC_FieldSplitLink head;
736dbb499eSCian Wilson PetscBool isrestrict; /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */
74c1570756SJed Brown PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
754ab8060aSDmitry Karpeev PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */
76c84da90fSDmitry Karpeev PetscBool diag_use_amat; /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
77c84da90fSDmitry Karpeev PetscBool offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
787b752e3dSPatrick Sanan PetscBool detect; /* Whether to form 2-way split by finding zero diagonal entries */
795ddf11f8SNicolas Barnafi PetscBool coordinates_set; /* Whether PCSetCoordinates has been called */
800971522cSBarry Smith } PC_FieldSplit;
810971522cSBarry Smith
8216913363SBarry Smith /*
83f1580f4eSBarry Smith Note:
8495452b02SPatrick Sanan there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
8516913363SBarry Smith inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
8616913363SBarry Smith PC you could change this.
8716913363SBarry Smith */
88084e4875SJed Brown
897addb90fSBarry Smith /* This helper is so that setting a user-provided matrix is orthogonal to choosing to use it. This way the
90084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
FieldSplitSchurPre(PC_FieldSplit * jac)91d71ae5a4SJacob Faibussowitsch static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
92d71ae5a4SJacob Faibussowitsch {
93084e4875SJed Brown switch (jac->schurpre) {
94d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_SELF:
95d71ae5a4SJacob Faibussowitsch return jac->schur;
96d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
97d71ae5a4SJacob Faibussowitsch return jac->schurp;
98d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_A11:
99d71ae5a4SJacob Faibussowitsch return jac->pmat[1];
100e74569cdSMatthew G. Knepley case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */
101084e4875SJed Brown case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
102d71ae5a4SJacob Faibussowitsch default:
103d71ae5a4SJacob Faibussowitsch return jac->schur_user ? jac->schur_user : jac->pmat[1];
104084e4875SJed Brown }
105084e4875SJed Brown }
106084e4875SJed Brown
1079804daf3SBarry Smith #include <petscdraw.h>
PCView_FieldSplit(PC pc,PetscViewer viewer)108d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit(PC pc, PetscViewer viewer)
109d71ae5a4SJacob Faibussowitsch {
1100971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1119f196a02SMartin Diehl PetscBool isascii, isdraw;
1120971522cSBarry Smith PetscInt i, j;
1135a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head;
1140971522cSBarry Smith
1150971522cSBarry Smith PetscFunctionBegin;
1169f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1179566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1189f196a02SMartin Diehl if (isascii) {
1192c9966d7SBarry Smith if (jac->bs > 0) {
12063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
1212c9966d7SBarry Smith } else {
12263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
1232c9966d7SBarry Smith }
12448a46eb9SPierre Jolivet if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n"));
12548a46eb9SPierre Jolivet if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for diagonal blocks\n"));
12648a46eb9SPierre Jolivet if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for off-diagonal blocks\n"));
1279566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Solver info for each split is in the following KSP objects:\n"));
1280971522cSBarry Smith for (i = 0; i < jac->nsplits; i++) {
1291ab39975SBarry Smith if (ilink->fields) {
13063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
1319566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1325a9f2f41SSatish Balay for (j = 0; j < ilink->nfields; j++) {
13348a46eb9SPierre Jolivet if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
13463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
1350971522cSBarry Smith }
1369566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1379566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1381ab39975SBarry Smith } else {
13963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
1401ab39975SBarry Smith }
1419566063dSJacob Faibussowitsch PetscCall(KSPView(ilink->ksp, viewer));
1425a9f2f41SSatish Balay ilink = ilink->next;
1430971522cSBarry Smith }
1442fa5cd67SKarl Rupp }
1452fa5cd67SKarl Rupp
1462fa5cd67SKarl Rupp if (isdraw) {
147d9884438SBarry Smith PetscDraw draw;
148d9884438SBarry Smith PetscReal x, y, w, wd;
149d9884438SBarry Smith
1509566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1519566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
152d9884438SBarry Smith w = 2 * PetscMin(1.0 - x, x);
153d9884438SBarry Smith wd = w / (jac->nsplits + 1);
154d9884438SBarry Smith x = x - wd * (jac->nsplits - 1) / 2.0;
155d9884438SBarry Smith for (i = 0; i < jac->nsplits; i++) {
1569566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
1579566063dSJacob Faibussowitsch PetscCall(KSPView(ilink->ksp, viewer));
1589566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
159d9884438SBarry Smith x += wd;
160d9884438SBarry Smith ilink = ilink->next;
161d9884438SBarry Smith }
1620971522cSBarry Smith }
1633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1640971522cSBarry Smith }
1650971522cSBarry Smith
PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)166d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit_Schur(PC pc, PetscViewer viewer)
167d71ae5a4SJacob Faibussowitsch {
1683b224e63SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1699f196a02SMartin Diehl PetscBool isascii, isdraw;
1703b224e63SBarry Smith PetscInt i, j;
1713b224e63SBarry Smith PC_FieldSplitLink ilink = jac->head;
172a9908d51SBarry Smith MatSchurComplementAinvType atype;
1733b224e63SBarry Smith
1743b224e63SBarry Smith PetscFunctionBegin;
1759f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1769566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1779f196a02SMartin Diehl if (isascii) {
1782c9966d7SBarry Smith if (jac->bs > 0) {
17963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with Schur preconditioner, blocksize = %" PetscInt_FMT ", factorization %s\n", jac->bs, PCFieldSplitSchurFactTypes[jac->schurfactorization]));
1802c9966d7SBarry Smith } else {
1819566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with Schur preconditioner, factorization %s\n", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
1822c9966d7SBarry Smith }
18348a46eb9SPierre Jolivet if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n"));
1843e8b8b31SMatthew G Knepley switch (jac->schurpre) {
185d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_SELF:
186d71ae5a4SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from S itself\n"));
187d71ae5a4SJacob Faibussowitsch break;
188a7476a74SDmitry Karpeev case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
1897cf5f706SPierre Jolivet if (jac->schur) {
1909566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetAinvType(jac->schur, &atype));
1919371c9d4SSatish Balay 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 "))));
1927cf5f706SPierre Jolivet }
193a9908d51SBarry Smith break;
194d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_A11:
195d71ae5a4SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from A11\n"));
196d71ae5a4SJacob Faibussowitsch break;
197d71ae5a4SJacob Faibussowitsch case PC_FIELDSPLIT_SCHUR_PRE_FULL:
198d71ae5a4SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from the exact Schur complement\n"));
199d71ae5a4SJacob Faibussowitsch break;
2003e8b8b31SMatthew G Knepley case PC_FIELDSPLIT_SCHUR_PRE_USER:
2013e8b8b31SMatthew G Knepley if (jac->schur_user) {
2029566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from user provided matrix\n"));
2033e8b8b31SMatthew G Knepley } else {
2049566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioner for the Schur complement formed from A11\n"));
2053e8b8b31SMatthew G Knepley }
2063e8b8b31SMatthew G Knepley break;
207d71ae5a4SJacob Faibussowitsch default:
208d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre);
2093e8b8b31SMatthew G Knepley }
2109566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Split info:\n"));
2119566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
2123b224e63SBarry Smith for (i = 0; i < jac->nsplits; i++) {
2133b224e63SBarry Smith if (ilink->fields) {
21463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
2159566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
2163b224e63SBarry Smith for (j = 0; j < ilink->nfields; j++) {
21748a46eb9SPierre Jolivet if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
21863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
2193b224e63SBarry Smith }
2209566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2219566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
2223b224e63SBarry Smith } else {
22363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
2243b224e63SBarry Smith }
2253b224e63SBarry Smith ilink = ilink->next;
2263b224e63SBarry Smith }
2279566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for A00 block\n"));
2289566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
229ac530a7eSPierre Jolivet if (jac->head) PetscCall(KSPView(jac->head->ksp, viewer));
230ac530a7eSPierre Jolivet else PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n"));
2319566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
23206de4afeSJed Brown if (jac->head && jac->kspupper != jac->head->ksp) {
2339566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for upper A00 in upper triangular factor\n"));
2349566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
2359566063dSJacob Faibussowitsch if (jac->kspupper) PetscCall(KSPView(jac->kspupper, viewer));
2369566063dSJacob Faibussowitsch else PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n"));
2379566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
238443836d0SMatthew G Knepley }
2399566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for S = A11 - A10 inv(A00) A01\n"));
2409566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
24112cae6f2SJed Brown if (jac->kspschur) {
2429566063dSJacob Faibussowitsch PetscCall(KSPView(jac->kspschur, viewer));
24312cae6f2SJed Brown } else {
2449566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " not yet available\n"));
24512cae6f2SJed Brown }
2469566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
2479566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
24806de4afeSJed Brown } else if (isdraw && jac->head) {
2494996c5bdSBarry Smith PetscDraw draw;
2504996c5bdSBarry Smith PetscReal x, y, w, wd, h;
2514996c5bdSBarry Smith PetscInt cnt = 2;
2524996c5bdSBarry Smith char str[32];
2534996c5bdSBarry Smith
2549566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2559566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
256c74581afSBarry Smith if (jac->kspupper != jac->head->ksp) cnt++;
257c74581afSBarry Smith w = 2 * PetscMin(1.0 - x, x);
258c74581afSBarry Smith wd = w / (cnt + 1);
259c74581afSBarry Smith
2609566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(str, 32, "Schur fact. %s", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
2619566063dSJacob Faibussowitsch PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
2624996c5bdSBarry Smith y -= h;
2634996c5bdSBarry Smith if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) {
2649566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]));
2653b224e63SBarry Smith } else {
2669566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[jac->schurpre]));
2674996c5bdSBarry Smith }
2689566063dSJacob Faibussowitsch PetscCall(PetscDrawStringBoxed(draw, x + wd * (cnt - 1) / 2.0, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
2694996c5bdSBarry Smith y -= h;
2704996c5bdSBarry Smith x = x - wd * (cnt - 1) / 2.0;
2714996c5bdSBarry Smith
2729566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2739566063dSJacob Faibussowitsch PetscCall(KSPView(jac->head->ksp, viewer));
2749566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
2754996c5bdSBarry Smith if (jac->kspupper != jac->head->ksp) {
2764996c5bdSBarry Smith x += wd;
2779566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2789566063dSJacob Faibussowitsch PetscCall(KSPView(jac->kspupper, viewer));
2799566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
2804996c5bdSBarry Smith }
2814996c5bdSBarry Smith x += wd;
2829566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2839566063dSJacob Faibussowitsch PetscCall(KSPView(jac->kspschur, viewer));
2849566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
2853b224e63SBarry Smith }
2863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2873b224e63SBarry Smith }
2883b224e63SBarry Smith
PCView_FieldSplit_GKB(PC pc,PetscViewer viewer)289d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit_GKB(PC pc, PetscViewer viewer)
290d71ae5a4SJacob Faibussowitsch {
291a51937d4SCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2929f196a02SMartin Diehl PetscBool isascii, isdraw;
293a51937d4SCarola Kruse PetscInt i, j;
294a51937d4SCarola Kruse PC_FieldSplitLink ilink = jac->head;
295a51937d4SCarola Kruse
296a51937d4SCarola Kruse PetscFunctionBegin;
2979f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2989566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
2999f196a02SMartin Diehl if (isascii) {
300a51937d4SCarola Kruse if (jac->bs > 0) {
30163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
302a51937d4SCarola Kruse } else {
30363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
304a51937d4SCarola Kruse }
30548a46eb9SPierre Jolivet if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for blocks\n"));
30648a46eb9SPierre Jolivet if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for diagonal blocks\n"));
30748a46eb9SPierre Jolivet if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, " using Amat (not Pmat) as operator for off-diagonal blocks\n"));
308a51937d4SCarola Kruse
30963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Stopping tolerance=%.1e, delay in error estimate=%" PetscInt_FMT ", maximum iterations=%" PetscInt_FMT "\n", (double)jac->gkbtol, jac->gkbdelay, jac->gkbmaxit));
3109566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Solver info for H = A00 + nu*A01*A01' matrix:\n"));
3119566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer));
312a51937d4SCarola Kruse
313a51937d4SCarola Kruse if (ilink->fields) {
31463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Fields "));
3159566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
316a51937d4SCarola Kruse for (j = 0; j < ilink->nfields; j++) {
31748a46eb9SPierre Jolivet if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
31863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
319a51937d4SCarola Kruse }
3209566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
3219566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
322a51937d4SCarola Kruse } else {
32363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Defined by IS\n"));
324a51937d4SCarola Kruse }
3259566063dSJacob Faibussowitsch PetscCall(KSPView(ilink->ksp, viewer));
326a51937d4SCarola Kruse
3279566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer));
328a51937d4SCarola Kruse }
329a51937d4SCarola Kruse
330a51937d4SCarola Kruse if (isdraw) {
331a51937d4SCarola Kruse PetscDraw draw;
332a51937d4SCarola Kruse PetscReal x, y, w, wd;
333a51937d4SCarola Kruse
3349566063dSJacob Faibussowitsch PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3359566063dSJacob Faibussowitsch PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
336a51937d4SCarola Kruse w = 2 * PetscMin(1.0 - x, x);
337a51937d4SCarola Kruse wd = w / (jac->nsplits + 1);
338a51937d4SCarola Kruse x = x - wd * (jac->nsplits - 1) / 2.0;
339a51937d4SCarola Kruse for (i = 0; i < jac->nsplits; i++) {
3409566063dSJacob Faibussowitsch PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
3419566063dSJacob Faibussowitsch PetscCall(KSPView(ilink->ksp, viewer));
3429566063dSJacob Faibussowitsch PetscCall(PetscDrawPopCurrentPoint(draw));
343a51937d4SCarola Kruse x += wd;
344a51937d4SCarola Kruse ilink = ilink->next;
345a51937d4SCarola Kruse }
346a51937d4SCarola Kruse }
3473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
348a51937d4SCarola Kruse }
349a51937d4SCarola Kruse
35080670ca5SBarry Smith /* Precondition: jac->bs is set to a meaningful value or MATNEST */
PCFieldSplitSetRuntimeSplits_Private(PC pc)351d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
352d71ae5a4SJacob Faibussowitsch {
3536c924f48SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35480670ca5SBarry Smith PetscInt bs, i, nfields, *ifields, nfields_col, *ifields_col;
35580670ca5SBarry Smith PetscBool flg, flg_col, mnest;
3565d4c12cdSJungho Lee char optionname[128], splitname[8], optionname_col[128];
3576c924f48SJed Brown
3586c924f48SJed Brown PetscFunctionBegin;
35980670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &mnest));
36080670ca5SBarry Smith if (mnest) {
36180670ca5SBarry Smith PetscCall(MatNestGetSize(pc->pmat, &bs, NULL));
36280670ca5SBarry Smith } else {
36380670ca5SBarry Smith bs = jac->bs;
36480670ca5SBarry Smith }
36580670ca5SBarry Smith PetscCall(PetscMalloc2(bs, &ifields, bs, &ifields_col));
3666c924f48SJed Brown for (i = 0, flg = PETSC_TRUE;; i++) {
36763a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
36863a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
36963a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(optionname_col, sizeof(optionname_col), "-pc_fieldsplit_%" PetscInt_FMT "_fields_col", i));
37080670ca5SBarry Smith nfields = bs;
37180670ca5SBarry Smith nfields_col = bs;
3729566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
3739566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname_col, ifields_col, &nfields_col, &flg_col));
3746c924f48SJed Brown if (!flg) break;
3755d4c12cdSJungho Lee else if (flg && !flg_col) {
37628b400f6SJacob Faibussowitsch PetscCheck(nfields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
3779566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields));
3782fa5cd67SKarl Rupp } else {
3797827d75bSBarry Smith PetscCheck(nfields && nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
38008401ef6SPierre Jolivet PetscCheck(nfields == nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Number of row and column fields must match");
3819566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields_col));
3825d4c12cdSJungho Lee }
3836c924f48SJed Brown }
3846c924f48SJed Brown if (i > 0) {
3856c924f48SJed Brown /* Makes command-line setting of splits take precedence over setting them in code.
3866c924f48SJed Brown Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
3876c924f48SJed Brown create new splits, which would probably not be what the user wanted. */
3886c924f48SJed Brown jac->splitdefined = PETSC_TRUE;
3896c924f48SJed Brown }
39080670ca5SBarry Smith PetscCall(PetscFree2(ifields, ifields_col));
3913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3926c924f48SJed Brown }
3936c924f48SJed Brown
PCFieldSplitSetDefaults(PC pc)394d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
395d71ae5a4SJacob Faibussowitsch {
3960971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3975a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head;
3987b752e3dSPatrick Sanan PetscBool fieldsplit_default = PETSC_FALSE, coupling = PETSC_FALSE;
3996c924f48SJed Brown PetscInt i;
4000971522cSBarry Smith
4010971522cSBarry Smith PetscFunctionBegin;
4027287d2a3SDmitry Karpeev /*
403f5f0d762SBarry Smith Kinda messy, but at least this now uses DMCreateFieldDecomposition().
4047287d2a3SDmitry Karpeev Should probably be rewritten.
4057287d2a3SDmitry Karpeev */
406f5f0d762SBarry Smith if (!ilink) {
4079566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_detect_coupling", &coupling, NULL));
4087b752e3dSPatrick Sanan if (pc->dm && jac->dm_splits && !jac->detect && !coupling) {
409bafc1b83SMatthew G Knepley PetscInt numFields, f, i, j;
4100784a22cSJed Brown char **fieldNames;
4117b62db95SJungho Lee IS *fields;
412e7c4fc90SDmitry Karpeev DM *dms;
413bafc1b83SMatthew G Knepley DM subdm[128];
414bafc1b83SMatthew G Knepley PetscBool flg;
415bafc1b83SMatthew G Knepley
4169566063dSJacob Faibussowitsch PetscCall(DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms));
417bafc1b83SMatthew G Knepley /* Allow the user to prescribe the splits */
418bafc1b83SMatthew G Knepley for (i = 0, flg = PETSC_TRUE;; i++) {
419bafc1b83SMatthew G Knepley PetscInt ifields[128];
420bafc1b83SMatthew G Knepley IS compField;
421bafc1b83SMatthew G Knepley char optionname[128], splitname[8];
422bafc1b83SMatthew G Knepley PetscInt nfields = numFields;
423bafc1b83SMatthew G Knepley
42463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
4259566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
426bafc1b83SMatthew G Knepley if (!flg) break;
42763a3b9bcSJacob Faibussowitsch PetscCheck(numFields <= 128, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot currently support %" PetscInt_FMT " > 128 fields", numFields);
4289566063dSJacob Faibussowitsch PetscCall(DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]));
429bafc1b83SMatthew G Knepley if (nfields == 1) {
4309566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField));
431bafc1b83SMatthew G Knepley } else {
43263a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
4339566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, splitname, compField));
4347287d2a3SDmitry Karpeev }
4359566063dSJacob Faibussowitsch PetscCall(ISDestroy(&compField));
436bafc1b83SMatthew G Knepley for (j = 0; j < nfields; ++j) {
437bafc1b83SMatthew G Knepley f = ifields[j];
4389566063dSJacob Faibussowitsch PetscCall(PetscFree(fieldNames[f]));
4399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fields[f]));
4407b62db95SJungho Lee }
441bafc1b83SMatthew G Knepley }
442bafc1b83SMatthew G Knepley if (i == 0) {
443bafc1b83SMatthew G Knepley for (f = 0; f < numFields; ++f) {
4449566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, fieldNames[f], fields[f]));
4459566063dSJacob Faibussowitsch PetscCall(PetscFree(fieldNames[f]));
4469566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fields[f]));
447bafc1b83SMatthew G Knepley }
448bafc1b83SMatthew G Knepley } else {
44948a46eb9SPierre Jolivet for (j = 0; j < numFields; j++) PetscCall(DMDestroy(dms + j));
4509566063dSJacob Faibussowitsch PetscCall(PetscFree(dms));
4519566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(i, &dms));
4522fa5cd67SKarl Rupp for (j = 0; j < i; ++j) dms[j] = subdm[j];
453bafc1b83SMatthew G Knepley }
4549566063dSJacob Faibussowitsch PetscCall(PetscFree(fieldNames));
4559566063dSJacob Faibussowitsch PetscCall(PetscFree(fields));
456e7c4fc90SDmitry Karpeev if (dms) {
4579566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n"));
458bafc1b83SMatthew G Knepley for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) {
4597287d2a3SDmitry Karpeev const char *prefix;
460f4f49eeaSPierre Jolivet PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ilink->ksp, &prefix));
461f4f49eeaSPierre Jolivet PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dms[i], prefix));
4629566063dSJacob Faibussowitsch PetscCall(KSPSetDM(ilink->ksp, dms[i]));
463*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(ilink->ksp, KSP_DMACTIVE_ALL, PETSC_FALSE));
4649566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)dms[i], (PetscObject)ilink->ksp, 0));
4659566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dms[i]));
4662fa5ba8aSJed Brown }
4679566063dSJacob Faibussowitsch PetscCall(PetscFree(dms));
4688b8307b2SJed Brown }
46966ffff09SJed Brown } else {
470521d7252SBarry Smith if (jac->bs <= 0) {
471ac530a7eSPierre Jolivet if (pc->pmat) PetscCall(MatGetBlockSize(pc->pmat, &jac->bs));
472ac530a7eSPierre Jolivet else jac->bs = 1;
473521d7252SBarry Smith }
474d32f9abdSBarry Smith
4757b752e3dSPatrick Sanan if (jac->detect) {
4766ce1633cSBarry Smith IS zerodiags, rest;
4776ce1633cSBarry Smith PetscInt nmin, nmax;
4786ce1633cSBarry Smith
4799566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
4807199da05SBarry Smith if (jac->diag_use_amat) {
4819566063dSJacob Faibussowitsch PetscCall(MatFindZeroDiagonals(pc->mat, &zerodiags));
4827199da05SBarry Smith } else {
4839566063dSJacob Faibussowitsch PetscCall(MatFindZeroDiagonals(pc->pmat, &zerodiags));
4847199da05SBarry Smith }
4859566063dSJacob Faibussowitsch PetscCall(ISComplement(zerodiags, nmin, nmax, &rest));
4869566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, "0", rest));
4879566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, "1", zerodiags));
4889566063dSJacob Faibussowitsch PetscCall(ISDestroy(&zerodiags));
4899566063dSJacob Faibussowitsch PetscCall(ISDestroy(&rest));
4903a062f41SBarry Smith } else if (coupling) {
4913a062f41SBarry Smith IS coupling, rest;
4923a062f41SBarry Smith PetscInt nmin, nmax;
4933a062f41SBarry Smith
4949566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
4957199da05SBarry Smith if (jac->offdiag_use_amat) {
4969566063dSJacob Faibussowitsch PetscCall(MatFindOffBlockDiagonalEntries(pc->mat, &coupling));
4977199da05SBarry Smith } else {
4989566063dSJacob Faibussowitsch PetscCall(MatFindOffBlockDiagonalEntries(pc->pmat, &coupling));
4997199da05SBarry Smith }
5009566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc->mat), nmax - nmin, nmin, 1, &rest));
5019566063dSJacob Faibussowitsch PetscCall(ISSetIdentity(rest));
5029566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, "0", rest));
5039566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, "1", coupling));
5049566063dSJacob Faibussowitsch PetscCall(ISDestroy(&coupling));
5059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&rest));
5066ce1633cSBarry Smith } else {
5079566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_default", &fieldsplit_default, NULL));
5087287d2a3SDmitry Karpeev if (!fieldsplit_default) {
509d32f9abdSBarry Smith /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit()
510d32f9abdSBarry Smith then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
5119566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
5129566063dSJacob Faibussowitsch if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
513d32f9abdSBarry Smith }
5146dbb499eSCian Wilson if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) {
5159f001fe8SStefano Zampini Mat M = pc->pmat;
516f3b928b9SStefano Zampini PetscBool isnest;
51780670ca5SBarry Smith PetscInt nf;
518f3b928b9SStefano Zampini
5199566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Using default splitting of fields\n"));
5209566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &isnest));
521f3b928b9SStefano Zampini if (!isnest) {
5229f001fe8SStefano Zampini M = pc->mat;
5239566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &isnest));
524f3b928b9SStefano Zampini }
52580670ca5SBarry Smith if (!isnest) nf = jac->bs;
52680670ca5SBarry Smith else PetscCall(MatNestGetSize(M, &nf, NULL));
52780670ca5SBarry Smith for (i = 0; i < nf; i++) {
5286c924f48SJed Brown char splitname[8];
52980670ca5SBarry Smith
53063a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
5319566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetFields(pc, splitname, 1, &i, &i));
53279416396SBarry Smith }
5335d4c12cdSJungho Lee jac->defaultsplit = PETSC_TRUE;
534521d7252SBarry Smith }
53566ffff09SJed Brown }
5366ce1633cSBarry Smith }
537edf189efSBarry Smith } else if (jac->nsplits == 1) {
538edf189efSBarry Smith IS is2;
539edf189efSBarry Smith PetscInt nmin, nmax;
540edf189efSBarry Smith
5410fdf79fbSJacob Faibussowitsch PetscCheck(ilink->is, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Must provide at least two sets of fields to PCFieldSplit()");
5429566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
5439566063dSJacob Faibussowitsch PetscCall(ISComplement(ilink->is, nmin, nmax, &is2));
5449566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetIS(pc, "1", is2));
5459566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is2));
546edf189efSBarry Smith }
547d0af7cd3SBarry Smith
54863a3b9bcSJacob Faibussowitsch PetscCheck(jac->nsplits >= 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unhandled case, must have at least two fields, not %" PetscInt_FMT, jac->nsplits);
5493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
55069a612a9SBarry Smith }
55169a612a9SBarry Smith
MatGolubKahanComputeExplicitOperator(Mat A,Mat B,Mat C,Mat * H,PetscReal gkbnu)552d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGolubKahanComputeExplicitOperator(Mat A, Mat B, Mat C, Mat *H, PetscReal gkbnu)
553d71ae5a4SJacob Faibussowitsch {
554a51937d4SCarola Kruse Mat BT, T;
555de482cd7SCarola Kruse PetscReal nrmT, nrmB;
556a51937d4SCarola Kruse
557a51937d4SCarola Kruse PetscFunctionBegin;
5589566063dSJacob Faibussowitsch PetscCall(MatHermitianTranspose(C, MAT_INITIAL_MATRIX, &T)); /* Test if augmented matrix is symmetric */
5599566063dSJacob Faibussowitsch PetscCall(MatAXPY(T, -1.0, B, DIFFERENT_NONZERO_PATTERN));
5609566063dSJacob Faibussowitsch PetscCall(MatNorm(T, NORM_1, &nrmT));
5619566063dSJacob Faibussowitsch PetscCall(MatNorm(B, NORM_1, &nrmB));
562b0c98d1dSPierre Jolivet PetscCheck(nrmB <= 0 || nrmT / nrmB < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix is not symmetric/Hermitian, GKB is not applicable.");
563049d1499SBarry Smith
564a51937d4SCarola Kruse /* Compute augmented Lagrangian matrix H = A00 + nu*A01*A01'. This corresponds to */
565a51937d4SCarola Kruse /* setting N := 1/nu*I in [Ar13]. */
5669566063dSJacob Faibussowitsch PetscCall(MatHermitianTranspose(B, MAT_INITIAL_MATRIX, &BT));
567fb842aefSJose E. Roman PetscCall(MatMatMult(B, BT, MAT_INITIAL_MATRIX, PETSC_CURRENT, H)); /* H = A01*A01' */
5689566063dSJacob Faibussowitsch PetscCall(MatAYPX(*H, gkbnu, A, DIFFERENT_NONZERO_PATTERN)); /* H = A00 + nu*A01*A01' */
569a51937d4SCarola Kruse
5709566063dSJacob Faibussowitsch PetscCall(MatDestroy(&BT));
5719566063dSJacob Faibussowitsch PetscCall(MatDestroy(&T));
5723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
573a51937d4SCarola Kruse }
574a51937d4SCarola Kruse
57554a546c1SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);
576514bf10dSMatthew G Knepley
PCSetUp_FieldSplit(PC pc)577d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_FieldSplit(PC pc)
578d71ae5a4SJacob Faibussowitsch {
57969a612a9SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
5805a9f2f41SSatish Balay PC_FieldSplitLink ilink;
5812c9966d7SBarry Smith PetscInt i, nsplit;
5822033cbf1SStefano Zampini PetscBool matnest = PETSC_FALSE;
58369a612a9SBarry Smith
58469a612a9SBarry Smith PetscFunctionBegin;
5855da88fe4STristan Konolige pc->failedreason = PC_NOERROR;
5869566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetDefaults(pc));
58797bbdb24SBarry Smith nsplit = jac->nsplits;
5885a9f2f41SSatish Balay ilink = jac->head;
58980670ca5SBarry Smith if (pc->pmat) PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
59097bbdb24SBarry Smith
59197bbdb24SBarry Smith /* get the matrices for each split */
592704ba839SBarry Smith if (!jac->issetup) {
5931b9fc7fcSBarry Smith PetscInt rstart, rend, nslots, bs;
59497bbdb24SBarry Smith
595704ba839SBarry Smith jac->issetup = PETSC_TRUE;
596704ba839SBarry Smith
5975d4c12cdSJungho Lee /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
5982c9966d7SBarry Smith if (jac->defaultsplit || !ilink->is) {
5992c9966d7SBarry Smith if (jac->bs <= 0) jac->bs = nsplit;
6002c9966d7SBarry Smith }
6014db63379SBarry Smith
6024db63379SBarry Smith /* MatCreateSubMatrix() for [S]BAIJ matrices can only work if the indices include entire blocks of the matrix */
6034db63379SBarry Smith PetscCall(MatGetBlockSize(pc->pmat, &bs));
6044db63379SBarry Smith if (bs > 1 && (jac->bs <= bs || jac->bs % bs)) {
6054db63379SBarry Smith PetscBool blk;
6064db63379SBarry Smith
6074db63379SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)pc->pmat, &blk, MATBAIJ, MATSBAIJ, MATSEQBAIJ, MATSEQSBAIJ, MATMPIBAIJ, MATMPISBAIJ, NULL));
6084db63379SBarry Smith PetscCheck(!blk, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Cannot use MATBAIJ with PCFIELDSPLIT and currently set matrix and PC blocksizes");
6094db63379SBarry Smith }
6104db63379SBarry Smith
61180670ca5SBarry Smith if (!matnest) { /* use the matrix blocksize and stride IS to determine the index sets that define the submatrices */
61251f519a2SBarry Smith bs = jac->bs;
6139566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(pc->pmat, &rstart, &rend));
6141b9fc7fcSBarry Smith nslots = (rend - rstart) / bs;
6151b9fc7fcSBarry Smith for (i = 0; i < nsplit; i++) {
6161b9fc7fcSBarry Smith if (jac->defaultsplit) {
6179566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + i, nsplit, &ilink->is));
6182033cbf1SStefano Zampini PetscCall(PetscObjectReference((PetscObject)ilink->is));
6192033cbf1SStefano Zampini ilink->is_col = ilink->is;
620704ba839SBarry Smith } else if (!ilink->is) {
6212033cbf1SStefano Zampini PetscBool same_fields = PETSC_TRUE;
6222033cbf1SStefano Zampini
6232033cbf1SStefano Zampini for (PetscInt k = 0; k < ilink->nfields; k++) {
6242033cbf1SStefano Zampini if (ilink->fields[k] != ilink->fields_col[k]) same_fields = PETSC_FALSE;
6252033cbf1SStefano Zampini }
6262033cbf1SStefano Zampini
627ccb205f8SBarry Smith if (ilink->nfields > 1) {
6285f4ab4e1SJungho Lee PetscInt *ii, *jj, j, k, nfields = ilink->nfields, *fields = ilink->fields, *fields_col = ilink->fields_col;
62980670ca5SBarry Smith
6309566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ilink->nfields * nslots, &ii));
6312033cbf1SStefano Zampini if (!same_fields) PetscCall(PetscMalloc1(ilink->nfields * nslots, &jj));
6321b9fc7fcSBarry Smith for (j = 0; j < nslots; j++) {
6331b9fc7fcSBarry Smith for (k = 0; k < nfields; k++) {
6341b9fc7fcSBarry Smith ii[nfields * j + k] = rstart + bs * j + fields[k];
6352033cbf1SStefano Zampini if (!same_fields) jj[nfields * j + k] = rstart + bs * j + fields_col[k];
63697bbdb24SBarry Smith }
63797bbdb24SBarry Smith }
6389566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, ii, PETSC_OWN_POINTER, &ilink->is));
6392033cbf1SStefano Zampini if (!same_fields) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, jj, PETSC_OWN_POINTER, &ilink->is_col));
6402033cbf1SStefano Zampini else {
6412033cbf1SStefano Zampini PetscCall(PetscObjectReference((PetscObject)ilink->is));
6422033cbf1SStefano Zampini ilink->is_col = ilink->is;
6432033cbf1SStefano Zampini }
6449566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(ilink->is, nfields));
6459566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(ilink->is_col, nfields));
646ccb205f8SBarry Smith } else {
6479566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields[0], bs, &ilink->is));
6482033cbf1SStefano Zampini if (!same_fields) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields_col[0], bs, &ilink->is_col));
6492033cbf1SStefano Zampini else {
6502033cbf1SStefano Zampini PetscCall(PetscObjectReference((PetscObject)ilink->is));
6512033cbf1SStefano Zampini ilink->is_col = ilink->is;
652ccb205f8SBarry Smith }
6533e197d65SBarry Smith }
6542033cbf1SStefano Zampini }
655704ba839SBarry Smith ilink = ilink->next;
6561b9fc7fcSBarry Smith }
65780670ca5SBarry Smith } else { /* use the IS that define the MATNEST to determine the index sets that define the submatrices */
65880670ca5SBarry Smith IS *rowis, *colis, *ises = NULL;
65980670ca5SBarry Smith PetscInt mis, nis;
66080670ca5SBarry Smith
66180670ca5SBarry Smith PetscCall(MatNestGetSize(pc->pmat, &mis, &nis));
66280670ca5SBarry Smith PetscCall(PetscMalloc2(mis, &rowis, nis, &colis));
66380670ca5SBarry Smith PetscCall(MatNestGetISs(pc->pmat, rowis, colis));
66480670ca5SBarry Smith if (!jac->defaultsplit) PetscCall(PetscMalloc1(mis, &ises));
66580670ca5SBarry Smith
66680670ca5SBarry Smith for (i = 0; i < nsplit; i++) {
66780670ca5SBarry Smith if (jac->defaultsplit) {
66880670ca5SBarry Smith PetscCall(ISDuplicate(rowis[i], &ilink->is));
6692033cbf1SStefano Zampini PetscCall(PetscObjectReference((PetscObject)ilink->is));
6702033cbf1SStefano Zampini ilink->is_col = ilink->is;
67180670ca5SBarry Smith } else if (!ilink->is) {
67280670ca5SBarry Smith if (ilink->nfields > 1) {
67380670ca5SBarry Smith for (PetscInt j = 0; j < ilink->nfields; j++) ises[j] = rowis[ilink->fields[j]];
67480670ca5SBarry Smith PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), ilink->nfields, ises, &ilink->is));
67580670ca5SBarry Smith } else {
67680670ca5SBarry Smith PetscCall(ISDuplicate(rowis[ilink->fields[0]], &ilink->is));
67780670ca5SBarry Smith }
6782033cbf1SStefano Zampini PetscCall(PetscObjectReference((PetscObject)ilink->is));
6792033cbf1SStefano Zampini ilink->is_col = ilink->is;
68080670ca5SBarry Smith }
68180670ca5SBarry Smith ilink = ilink->next;
68280670ca5SBarry Smith }
68380670ca5SBarry Smith PetscCall(PetscFree2(rowis, colis));
68480670ca5SBarry Smith PetscCall(PetscFree(ises));
68580670ca5SBarry Smith }
6861b9fc7fcSBarry Smith }
6871b9fc7fcSBarry Smith
688704ba839SBarry Smith ilink = jac->head;
68997bbdb24SBarry Smith if (!jac->pmat) {
690bdddcaaaSMatthew G Knepley Vec xtmp;
691bdddcaaaSMatthew G Knepley
6929566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(pc->pmat, &xtmp, NULL));
6939566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nsplit, &jac->pmat));
6949566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nsplit, &jac->x, nsplit, &jac->y));
695cf502942SBarry Smith for (i = 0; i < nsplit; i++) {
696bdddcaaaSMatthew G Knepley MatNullSpace sp;
697bdddcaaaSMatthew G Knepley
6987addb90fSBarry Smith /* Check for matrix attached to IS */
6999566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&jac->pmat[i]));
700a3df900dSMatthew G Knepley if (jac->pmat[i]) {
7019566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->pmat[i]));
702a3df900dSMatthew G Knepley if (jac->type == PC_COMPOSITE_SCHUR) {
703a3df900dSMatthew G Knepley jac->schur_user = jac->pmat[i];
7042fa5cd67SKarl Rupp
7059566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
706a3df900dSMatthew G Knepley }
707a3df900dSMatthew G Knepley } else {
7083a062f41SBarry Smith const char *prefix;
7099566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->pmat[i]));
7102f427464SPierre Jolivet PetscCall(MatGetOptionsPrefix(jac->pmat[i], &prefix));
7112f427464SPierre Jolivet if (!prefix) {
7129566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(ilink->ksp, &prefix));
7139566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(jac->pmat[i], prefix));
7142f427464SPierre Jolivet }
71545881c45SPierre Jolivet PetscCall(MatSetFromOptions(jac->pmat[i]));
7169566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(jac->pmat[i], NULL, "-mat_view"));
717a3df900dSMatthew G Knepley }
718bdddcaaaSMatthew G Knepley /* create work vectors for each split */
7199566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(jac->pmat[i], &jac->x[i], &jac->y[i]));
7209371c9d4SSatish Balay ilink->x = jac->x[i];
7219371c9d4SSatish Balay ilink->y = jac->y[i];
7229371c9d4SSatish Balay ilink->z = NULL;
723bdddcaaaSMatthew G Knepley /* compute scatter contexts needed by multiplicative versions and non-default splits */
7249566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(xtmp, ilink->is, jac->x[i], NULL, &ilink->sctx));
7259566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nearnullspace", (PetscObject *)&sp));
72648a46eb9SPierre Jolivet if (sp) PetscCall(MatSetNearNullSpace(jac->pmat[i], sp));
727704ba839SBarry Smith ilink = ilink->next;
728cf502942SBarry Smith }
7299566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xtmp));
73097bbdb24SBarry Smith } else {
731ef7efd37SHong Zhang MatReuse scall;
7324849c82aSBarry Smith MatNullSpace *nullsp = NULL;
7334849c82aSBarry Smith
734ef7efd37SHong Zhang if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
7354849c82aSBarry Smith PetscCall(MatGetNullSpaces(nsplit, jac->pmat, &nullsp));
73648a46eb9SPierre Jolivet for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->pmat[i]));
737ef7efd37SHong Zhang scall = MAT_INITIAL_MATRIX;
738ef7efd37SHong Zhang } else scall = MAT_REUSE_MATRIX;
739ef7efd37SHong Zhang
740cf502942SBarry Smith for (i = 0; i < nsplit; i++) {
741a3df900dSMatthew G Knepley Mat pmat;
742a3df900dSMatthew G Knepley
7437addb90fSBarry Smith /* Check for matrix attached to IS */
7449566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&pmat));
74548a46eb9SPierre Jolivet if (!pmat) PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, scall, &jac->pmat[i]));
746704ba839SBarry Smith ilink = ilink->next;
747cf502942SBarry Smith }
7484849c82aSBarry Smith if (nullsp) PetscCall(MatRestoreNullSpaces(nsplit, jac->pmat, &nullsp));
74997bbdb24SBarry Smith }
7504e39094bSDmitry Karpeev if (jac->diag_use_amat) {
751519d70e2SJed Brown ilink = jac->head;
752519d70e2SJed Brown if (!jac->mat) {
7539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nsplit, &jac->mat));
754519d70e2SJed Brown for (i = 0; i < nsplit; i++) {
7559566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->mat[i]));
756519d70e2SJed Brown ilink = ilink->next;
757519d70e2SJed Brown }
758519d70e2SJed Brown } else {
759ef7efd37SHong Zhang MatReuse scall;
7604849c82aSBarry Smith MatNullSpace *nullsp = NULL;
7614849c82aSBarry Smith
762ef7efd37SHong Zhang if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
7634849c82aSBarry Smith PetscCall(MatGetNullSpaces(nsplit, jac->mat, &nullsp));
76448a46eb9SPierre Jolivet for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->mat[i]));
765ef7efd37SHong Zhang scall = MAT_INITIAL_MATRIX;
766ef7efd37SHong Zhang } else scall = MAT_REUSE_MATRIX;
767ef7efd37SHong Zhang
768ef7efd37SHong Zhang for (i = 0; i < nsplit; i++) {
7699566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, scall, &jac->mat[i]));
770519d70e2SJed Brown ilink = ilink->next;
771519d70e2SJed Brown }
7724849c82aSBarry Smith if (nullsp) PetscCall(MatRestoreNullSpaces(nsplit, jac->mat, &nullsp));
773519d70e2SJed Brown }
774519d70e2SJed Brown } else {
775519d70e2SJed Brown jac->mat = jac->pmat;
776519d70e2SJed Brown }
77797bbdb24SBarry Smith
77853935eafSBarry Smith /* Check for null space attached to IS */
77953935eafSBarry Smith ilink = jac->head;
78053935eafSBarry Smith for (i = 0; i < nsplit; i++) {
78153935eafSBarry Smith MatNullSpace sp;
78253935eafSBarry Smith
7839566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nullspace", (PetscObject *)&sp));
78448a46eb9SPierre Jolivet if (sp) PetscCall(MatSetNullSpace(jac->mat[i], sp));
78553935eafSBarry Smith ilink = ilink->next;
78653935eafSBarry Smith }
78753935eafSBarry Smith
788a51937d4SCarola Kruse if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR && jac->type != PC_COMPOSITE_GKB) {
78968dd23aaSBarry Smith /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
7904e39094bSDmitry Karpeev /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */
79168dd23aaSBarry Smith ilink = jac->head;
792e52d2c62SBarry Smith if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) {
793e52d2c62SBarry Smith /* 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 */
794e52d2c62SBarry Smith if (!jac->Afield) {
7959566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nsplit, &jac->Afield));
79680c96bb1SFande Kong if (jac->offdiag_use_amat) {
7979566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
798e52d2c62SBarry Smith } else {
7999566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
80080c96bb1SFande Kong }
80180c96bb1SFande Kong } else {
802ef7efd37SHong Zhang MatReuse scall;
803e9422dd5SStefano Zampini
804ef7efd37SHong Zhang if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
8059566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->Afield[1]));
806ef7efd37SHong Zhang scall = MAT_INITIAL_MATRIX;
807ef7efd37SHong Zhang } else scall = MAT_REUSE_MATRIX;
808ef7efd37SHong Zhang
80980c96bb1SFande Kong if (jac->offdiag_use_amat) {
8109566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
81180c96bb1SFande Kong } else {
8129566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
81380c96bb1SFande Kong }
814e52d2c62SBarry Smith }
815e52d2c62SBarry Smith } else {
81668dd23aaSBarry Smith if (!jac->Afield) {
8179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nsplit, &jac->Afield));
81868dd23aaSBarry Smith for (i = 0; i < nsplit; i++) {
81980c96bb1SFande Kong if (jac->offdiag_use_amat) {
8209566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
82180c96bb1SFande Kong } else {
8229566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
82380c96bb1SFande Kong }
82468dd23aaSBarry Smith ilink = ilink->next;
82568dd23aaSBarry Smith }
82668dd23aaSBarry Smith } else {
827ef7efd37SHong Zhang MatReuse scall;
828ef7efd37SHong Zhang if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
82948a46eb9SPierre Jolivet for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->Afield[i]));
830ef7efd37SHong Zhang scall = MAT_INITIAL_MATRIX;
831ef7efd37SHong Zhang } else scall = MAT_REUSE_MATRIX;
832ef7efd37SHong Zhang
83368dd23aaSBarry Smith for (i = 0; i < nsplit; i++) {
83480c96bb1SFande Kong if (jac->offdiag_use_amat) {
8359566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, scall, &jac->Afield[i]));
83680c96bb1SFande Kong } else {
8379566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, scall, &jac->Afield[i]));
83880c96bb1SFande Kong }
83968dd23aaSBarry Smith ilink = ilink->next;
84068dd23aaSBarry Smith }
84168dd23aaSBarry Smith }
84268dd23aaSBarry Smith }
843e52d2c62SBarry Smith }
84468dd23aaSBarry Smith
8453b224e63SBarry Smith if (jac->type == PC_COMPOSITE_SCHUR) {
84618f54938SStefano Zampini PetscBool isset, isspd = PETSC_FALSE, issym = PETSC_FALSE, flg;
847093c86ffSJed Brown char lscname[256];
848093c86ffSJed Brown PetscObject LSC_L;
849ce94432eSBarry Smith
85008401ef6SPierre Jolivet PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use Schur complement preconditioner you must have exactly 2 fields");
85168dd23aaSBarry Smith
852c096484dSStefano Zampini /* If pc->mat is SPD, don't scale by -1 the Schur complement */
853b94d7dedSBarry Smith PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
85418f54938SStefano Zampini if (jac->schurscale == (PetscScalar)-1.0) jac->schurscale = (isset && isspd) ? 1.0 : -1.0;
85518f54938SStefano Zampini PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
856c096484dSStefano Zampini
857558f3fe8SPierre Jolivet PetscCall(PetscObjectTypeCompareAny(jac->offdiag_use_amat ? (PetscObject)pc->mat : (PetscObject)pc->pmat, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
858e6cab6aaSJed Brown
8593b224e63SBarry Smith if (jac->schur) {
8600298fd71SBarry Smith KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper;
861e9422dd5SStefano Zampini MatReuse scall;
862e9422dd5SStefano Zampini
863e9422dd5SStefano Zampini if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
864e9422dd5SStefano Zampini scall = MAT_INITIAL_MATRIX;
8659566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->B));
8669566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->C));
867e9422dd5SStefano Zampini } else scall = MAT_REUSE_MATRIX;
868443836d0SMatthew G Knepley
8699566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
8703b224e63SBarry Smith ilink = jac->head;
871ad881d7cSPierre Jolivet PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, scall, &jac->B));
872ad881d7cSPierre Jolivet if (!flg) PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, scall, &jac->C));
873ad881d7cSPierre Jolivet else {
87418f54938SStefano Zampini PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &isset, &flg));
87518f54938SStefano Zampini if (isset && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C));
876558f3fe8SPierre Jolivet else PetscCall(MatCreateTranspose(jac->B, &jac->C));
877558f3fe8SPierre Jolivet }
878ad881d7cSPierre Jolivet ilink = ilink->next;
8799566063dSJacob Faibussowitsch PetscCall(MatSchurComplementUpdateSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
880a7476a74SDmitry Karpeev if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) {
8819566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schurp));
8829566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
8835becce15SPierre Jolivet } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL && jac->kspupper != jac->head->ksp) {
884d9eadc85SPierre Jolivet PetscCall(MatDestroy(&jac->schur_user));
885d9eadc85SPierre Jolivet PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
886a7476a74SDmitry Karpeev }
88748a46eb9SPierre Jolivet if (kspA != kspInner) PetscCall(KSPSetOperators(kspA, jac->mat[0], jac->pmat[0]));
88848a46eb9SPierre Jolivet if (kspUpper != kspA) PetscCall(KSPSetOperators(kspUpper, jac->mat[0], jac->pmat[0]));
8899566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
8903b224e63SBarry Smith } else {
891bafc1b83SMatthew G Knepley const char *Dprefix;
892470b340bSDmitry Karpeev char schurprefix[256], schurmatprefix[256];
893514bf10dSMatthew G Knepley char schurtestoption[256];
894bdddcaaaSMatthew G Knepley MatNullSpace sp;
895686bed4dSStefano Zampini KSP kspt;
8963b224e63SBarry Smith
897a04f6461SBarry Smith /* extract the A01 and A10 matrices */
8983b224e63SBarry Smith ilink = jac->head;
899ad881d7cSPierre Jolivet PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, MAT_INITIAL_MATRIX, &jac->B));
900ad881d7cSPierre Jolivet if (!flg) PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->C));
901ad881d7cSPierre Jolivet else {
90218f54938SStefano Zampini PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &isset, &flg));
90318f54938SStefano Zampini if (isset && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C));
904558f3fe8SPierre Jolivet else PetscCall(MatCreateTranspose(jac->B, &jac->C));
905558f3fe8SPierre Jolivet }
906ad881d7cSPierre Jolivet ilink = ilink->next;
907f5236f50SJed Brown /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */
9089566063dSJacob Faibussowitsch PetscCall(MatCreate(((PetscObject)jac->mat[0])->comm, &jac->schur));
9099566063dSJacob Faibussowitsch PetscCall(MatSetType(jac->schur, MATSCHURCOMPLEMENT));
9109566063dSJacob Faibussowitsch PetscCall(MatSchurComplementSetSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
9119566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
9129566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(jac->schur, schurmatprefix));
9139566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, &kspt));
9149566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(kspt, schurmatprefix));
915686bed4dSStefano Zampini
916686bed4dSStefano Zampini /* Note: this is not true in general */
9179566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(jac->mat[1], &sp));
9181baa6e33SBarry Smith if (sp) PetscCall(MatSetNullSpace(jac->schur, sp));
91920252d06SBarry Smith
9209566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname));
92154a546c1SMatthew G. Knepley PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, NULL, &flg));
922514bf10dSMatthew G Knepley if (flg) {
923514bf10dSMatthew G Knepley DM dmInner;
92421635b76SJed Brown KSP kspInner;
925686bed4dSStefano Zampini PC pcInner;
92621635b76SJed Brown
9279566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
9289566063dSJacob Faibussowitsch PetscCall(KSPReset(kspInner));
9299566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(kspInner, jac->mat[0], jac->pmat[0]));
9309566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
93121635b76SJed Brown /* Indent this deeper to emphasize the "inner" nature of this solver. */
9329566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject)pc, 2));
9339566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner->pc, (PetscObject)pc, 2));
9349566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(kspInner, schurprefix));
935514bf10dSMatthew G Knepley
936514bf10dSMatthew G Knepley /* Set DM for new solver */
9379566063dSJacob Faibussowitsch PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
9389566063dSJacob Faibussowitsch PetscCall(KSPSetDM(kspInner, dmInner));
939*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(kspInner, KSP_DMACTIVE_ALL, PETSC_FALSE));
940686bed4dSStefano Zampini
941686bed4dSStefano Zampini /* Defaults to PCKSP as preconditioner */
9429566063dSJacob Faibussowitsch PetscCall(KSPGetPC(kspInner, &pcInner));
9439566063dSJacob Faibussowitsch PetscCall(PCSetType(pcInner, PCKSP));
9449566063dSJacob Faibussowitsch PetscCall(PCKSPSetKSP(pcInner, jac->head->ksp));
945514bf10dSMatthew G Knepley } else {
94621635b76SJed Brown /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or
94721635b76SJed Brown * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact,
94821635b76SJed Brown * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for
94921635b76SJed Brown * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make
95021635b76SJed Brown * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used
95121635b76SJed Brown * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */
9529566063dSJacob Faibussowitsch PetscCall(KSPSetType(jac->head->ksp, KSPGMRES));
9539566063dSJacob Faibussowitsch PetscCall(MatSchurComplementSetKSP(jac->schur, jac->head->ksp));
954bafc1b83SMatthew G Knepley }
9559566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(jac->head->ksp, jac->mat[0], jac->pmat[0]));
9569566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(jac->head->ksp));
9579566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(jac->schur));
9583b224e63SBarry Smith
9599566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)jac->schur, MATSCHURCOMPLEMENT, &flg));
960686bed4dSStefano Zampini if (flg) { /* Need to do this otherwise PCSetUp_KSP will overwrite the amat of jac->head->ksp */
961686bed4dSStefano Zampini KSP kspInner;
962686bed4dSStefano Zampini PC pcInner;
963686bed4dSStefano Zampini
9649566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
9659566063dSJacob Faibussowitsch PetscCall(KSPGetPC(kspInner, &pcInner));
9669566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pcInner, PCKSP, &flg));
967686bed4dSStefano Zampini if (flg) {
968686bed4dSStefano Zampini KSP ksp;
969686bed4dSStefano Zampini
9709566063dSJacob Faibussowitsch PetscCall(PCKSPGetKSP(pcInner, &ksp));
97148a46eb9SPierre Jolivet if (ksp == jac->head->ksp) PetscCall(PCSetUseAmat(pcInner, PETSC_TRUE));
972686bed4dSStefano Zampini }
973686bed4dSStefano Zampini }
9749566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname));
97554a546c1SMatthew G. Knepley PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, NULL, &flg));
976443836d0SMatthew G Knepley if (flg) {
977443836d0SMatthew G Knepley DM dmInner;
978443836d0SMatthew G Knepley
9799566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
9809566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper));
9813821be0aSBarry Smith PetscCall(KSPSetNestLevel(jac->kspupper, pc->kspnestlevel));
9829566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(jac->kspupper, pc->erroriffailure));
9839566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(jac->kspupper, schurprefix));
9849566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper, (PetscObject)pc, 1));
9859566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper->pc, (PetscObject)pc, 1));
9869566063dSJacob Faibussowitsch PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
9879566063dSJacob Faibussowitsch PetscCall(KSPSetDM(jac->kspupper, dmInner));
988*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(jac->kspupper, KSP_DMACTIVE_ALL, PETSC_FALSE));
9899566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(jac->kspupper));
9909566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(jac->kspupper, jac->mat[0], jac->pmat[0]));
9919566063dSJacob Faibussowitsch PetscCall(VecDuplicate(jac->head->x, &jac->head->z));
992443836d0SMatthew G Knepley } else {
993443836d0SMatthew G Knepley jac->kspupper = jac->head->ksp;
9949566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->head->ksp));
995443836d0SMatthew G Knepley }
996443836d0SMatthew G Knepley
99748a46eb9SPierre Jolivet if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
9989566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspschur));
9993821be0aSBarry Smith PetscCall(KSPSetNestLevel(jac->kspschur, pc->kspnestlevel));
10009566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(jac->kspschur, pc->erroriffailure));
10019566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspschur, (PetscObject)pc, 1));
1002084e4875SJed Brown if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
10037233a360SDmitry Karpeev PC pcschur;
10049566063dSJacob Faibussowitsch PetscCall(KSPGetPC(jac->kspschur, &pcschur));
10059566063dSJacob Faibussowitsch PetscCall(PCSetType(pcschur, PCNONE));
1006084e4875SJed Brown /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
1007e74569cdSMatthew G. Knepley } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) {
10085becce15SPierre Jolivet if (jac->schurfactorization != PC_FIELDSPLIT_SCHUR_FACT_FULL || jac->kspupper != jac->head->ksp) PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1009e69d4d44SBarry Smith }
10109566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
10119566063dSJacob Faibussowitsch PetscCall(KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix));
10129566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(jac->kspschur, Dprefix));
1013c096484dSStefano Zampini /* propagate DM */
1014b20b4189SMatthew G. Knepley {
1015b20b4189SMatthew G. Knepley DM sdm;
10169566063dSJacob Faibussowitsch PetscCall(KSPGetDM(jac->head->next->ksp, &sdm));
1017b20b4189SMatthew G. Knepley if (sdm) {
10189566063dSJacob Faibussowitsch PetscCall(KSPSetDM(jac->kspschur, sdm));
1019*bf0c7fc2SBarry Smith PetscCall(KSPSetDMActive(jac->kspschur, KSP_DMACTIVE_ALL, PETSC_FALSE));
1020b20b4189SMatthew G. Knepley }
1021b20b4189SMatthew G. Knepley }
10223b224e63SBarry Smith /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
102320b26d62SBarry Smith /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
10249566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(jac->kspschur));
10253b224e63SBarry Smith }
10269566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(jac->schur, MAT_FINAL_ASSEMBLY));
10279566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(jac->schur, MAT_FINAL_ASSEMBLY));
102818f54938SStefano Zampini if (issym) PetscCall(MatSetOption(jac->schur, MAT_SYMMETRIC, PETSC_TRUE));
102918f54938SStefano Zampini if (isspd) PetscCall(MatSetOption(jac->schur, MAT_SPD, PETSC_TRUE));
1030093c86ffSJed Brown
1031093c86ffSJed Brown /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */
10329566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_L", ilink->splitname));
1033835f2295SStefano Zampini PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, &LSC_L));
1034835f2295SStefano Zampini if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, &LSC_L));
1035835f2295SStefano Zampini if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_L", LSC_L));
10369566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_Lp", ilink->splitname));
1037835f2295SStefano Zampini PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, &LSC_L));
1038835f2295SStefano Zampini if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, &LSC_L));
1039835f2295SStefano Zampini if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_Lp", LSC_L));
1040a51937d4SCarola Kruse } else if (jac->type == PC_COMPOSITE_GKB) {
104108401ef6SPierre Jolivet PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use GKB preconditioner you must have exactly 2 fields");
1042a51937d4SCarola Kruse ilink = jac->head;
1043ad881d7cSPierre Jolivet PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, MAT_INITIAL_MATRIX, &jac->B));
1044e071a0a4SCarola Kruse /* Create work vectors for GKB algorithm */
10459566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->u));
10469566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->Hu));
10479566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->w2));
1048ad881d7cSPierre Jolivet PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->C));
1049a51937d4SCarola Kruse ilink = ilink->next;
1050e071a0a4SCarola Kruse /* Create work vectors for GKB algorithm */
10519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->v));
10529566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->d));
10539566063dSJacob Faibussowitsch PetscCall(VecDuplicate(ilink->x, &jac->w1));
10549566063dSJacob Faibussowitsch PetscCall(MatGolubKahanComputeExplicitOperator(jac->mat[0], jac->B, jac->C, &jac->H, jac->gkbnu));
10559566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(jac->gkbdelay, &jac->vecz));
1056e071a0a4SCarola Kruse
1057a51937d4SCarola Kruse ilink = jac->head;
10589566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ilink->ksp, jac->H, jac->H));
10599566063dSJacob Faibussowitsch if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
1060e071a0a4SCarola Kruse /* Create gkb_monitor context */
1061de482cd7SCarola Kruse if (jac->gkbmonitor) {
1062de482cd7SCarola Kruse PetscInt tablevel;
10639566063dSJacob Faibussowitsch PetscCall(PetscViewerCreate(PETSC_COMM_WORLD, &jac->gkbviewer));
10649566063dSJacob Faibussowitsch PetscCall(PetscViewerSetType(jac->gkbviewer, PETSCVIEWERASCII));
10659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetTabLevel((PetscObject)ilink->ksp, &tablevel));
10669566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIISetTab(jac->gkbviewer, tablevel));
10679566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)ilink->ksp, 1));
1068de482cd7SCarola Kruse }
10693b224e63SBarry Smith } else {
107068bd789dSDmitry Karpeev /* set up the individual splits' PCs */
107197bbdb24SBarry Smith i = 0;
10725a9f2f41SSatish Balay ilink = jac->head;
10735a9f2f41SSatish Balay while (ilink) {
10749566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(ilink->ksp, jac->mat[i], jac->pmat[i]));
10753b224e63SBarry Smith /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
10769566063dSJacob Faibussowitsch if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
107797bbdb24SBarry Smith i++;
10785a9f2f41SSatish Balay ilink = ilink->next;
10790971522cSBarry Smith }
10803b224e63SBarry Smith }
10813b224e63SBarry Smith
10825ddf11f8SNicolas Barnafi /* Set coordinates to the sub PC objects whenever these are set */
10835ddf11f8SNicolas Barnafi if (jac->coordinates_set) {
10845ddf11f8SNicolas Barnafi PC pc_coords;
10855ddf11f8SNicolas Barnafi if (jac->type == PC_COMPOSITE_SCHUR) {
10865ddf11f8SNicolas Barnafi // Head is first block.
10879566063dSJacob Faibussowitsch PetscCall(KSPGetPC(jac->head->ksp, &pc_coords));
10889566063dSJacob Faibussowitsch PetscCall(PCSetCoordinates(pc_coords, jac->head->dim, jac->head->ndofs, jac->head->coords));
10895ddf11f8SNicolas Barnafi // Second one is Schur block, but its KSP object is in kspschur.
10909566063dSJacob Faibussowitsch PetscCall(KSPGetPC(jac->kspschur, &pc_coords));
10919566063dSJacob Faibussowitsch PetscCall(PCSetCoordinates(pc_coords, jac->head->next->dim, jac->head->next->ndofs, jac->head->next->coords));
10925ddf11f8SNicolas Barnafi } else if (jac->type == PC_COMPOSITE_GKB) {
10939d3446b2SPierre Jolivet PetscCall(PetscInfo(pc, "Warning: Setting coordinates does nothing for the GKB Fieldpslit preconditioner\n"));
10945ddf11f8SNicolas Barnafi } else {
10955ddf11f8SNicolas Barnafi ilink = jac->head;
10965ddf11f8SNicolas Barnafi while (ilink) {
10979566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ilink->ksp, &pc_coords));
10989566063dSJacob Faibussowitsch PetscCall(PCSetCoordinates(pc_coords, ilink->dim, ilink->ndofs, ilink->coords));
10995ddf11f8SNicolas Barnafi ilink = ilink->next;
11005ddf11f8SNicolas Barnafi }
11015ddf11f8SNicolas Barnafi }
11025ddf11f8SNicolas Barnafi }
11035ddf11f8SNicolas Barnafi
1104c1570756SJed Brown jac->suboptionsset = PETSC_TRUE;
11053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
11060971522cSBarry Smith }
11070971522cSBarry Smith
PCSetUpOnBlocks_FieldSplit_Schur(PC pc)110873716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_Schur(PC pc)
110973716367SStefano Zampini {
111073716367SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
111173716367SStefano Zampini PC_FieldSplitLink ilinkA = jac->head;
111273716367SStefano Zampini KSP kspA = ilinkA->ksp, kspUpper = jac->kspupper;
111373716367SStefano Zampini
111473716367SStefano Zampini PetscFunctionBegin;
111573716367SStefano Zampini if (jac->schurfactorization == PC_FIELDSPLIT_SCHUR_FACT_FULL && kspUpper != kspA) {
111673716367SStefano Zampini PetscCall(KSPSetUp(kspUpper));
111773716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(kspUpper));
111873716367SStefano Zampini }
111973716367SStefano Zampini PetscCall(KSPSetUp(kspA));
112073716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(kspA));
112173716367SStefano Zampini if (jac->schurpre != PC_FIELDSPLIT_SCHUR_PRE_FULL) {
112273716367SStefano Zampini PetscCall(KSPSetUp(jac->kspschur));
112373716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(jac->kspschur));
1124c9d0a0b7SPierre Jolivet } else if (kspUpper == kspA && jac->schurfactorization == PC_FIELDSPLIT_SCHUR_FACT_FULL) {
11255becce15SPierre Jolivet Mat A;
1126ab1f0642SPierre Jolivet PetscInt m, M, N;
1127ab1f0642SPierre Jolivet VecType vtype;
1128ab1f0642SPierre Jolivet PetscMemType mtype;
1129ab1f0642SPierre Jolivet PetscScalar *array;
1130ab1f0642SPierre Jolivet
1131ab1f0642SPierre Jolivet PetscCall(MatGetSize(jac->B, &M, &N));
1132ab1f0642SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1133ab1f0642SPierre Jolivet PetscCall(MatGetVecType(jac->B, &vtype));
1134ab1f0642SPierre Jolivet PetscCall(VecGetArrayAndMemType(ilinkA->x, &array, &mtype));
1135ab1f0642SPierre Jolivet PetscCall(VecRestoreArrayAndMemType(ilinkA->x, &array));
1136c9d0a0b7SPierre Jolivet PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&A));
1137cb03e585SPierre Jolivet if (A) {
1138cb03e585SPierre Jolivet PetscInt P;
1139cb03e585SPierre Jolivet
1140cb03e585SPierre Jolivet PetscCall(MatGetSize(A, NULL, &P));
1141cb03e585SPierre Jolivet if (P < N + 1) { // need to recreate AinvB, otherwise, the Schur complement won't be updated
1142cb03e585SPierre Jolivet PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
1143cb03e585SPierre Jolivet A = NULL;
1144cb03e585SPierre Jolivet }
1145cb03e585SPierre Jolivet }
1146c9d0a0b7SPierre Jolivet if (!A) {
1147ab1f0642SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(PetscMalloc1(m * (N + 1), &array));
1148ab1f0642SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1149ab1f0642SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1150ab1f0642SPierre Jolivet #endif
1151ab1f0642SPierre Jolivet #if PetscDefined(HAVE_HIP)
1152ab1f0642SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1153ab1f0642SPierre Jolivet #endif
1154ab1f0642SPierre Jolivet PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)jac->schur), vtype, m, PETSC_DECIDE, M, N + 1, -1, array, &A)); // number of columns of the Schur complement plus one
11555becce15SPierre Jolivet PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", (PetscObject)A));
11565becce15SPierre Jolivet PetscCall(MatDestroy(&A));
115773716367SStefano Zampini }
1158c9d0a0b7SPierre Jolivet }
115973716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS);
116073716367SStefano Zampini }
116173716367SStefano Zampini
PCSetUpOnBlocks_FieldSplit(PC pc)116273716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit(PC pc)
116373716367SStefano Zampini {
116473716367SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
116573716367SStefano Zampini PC_FieldSplitLink ilink = jac->head;
116673716367SStefano Zampini
116773716367SStefano Zampini PetscFunctionBegin;
116873716367SStefano Zampini while (ilink) {
116973716367SStefano Zampini PetscCall(KSPSetUp(ilink->ksp));
117073716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(ilink->ksp));
117173716367SStefano Zampini ilink = ilink->next;
117273716367SStefano Zampini }
117373716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS);
117473716367SStefano Zampini }
117573716367SStefano Zampini
PCSetUpOnBlocks_FieldSplit_GKB(PC pc)117673716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_GKB(PC pc)
117773716367SStefano Zampini {
117873716367SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
117973716367SStefano Zampini PC_FieldSplitLink ilinkA = jac->head;
118073716367SStefano Zampini KSP ksp = ilinkA->ksp;
118173716367SStefano Zampini
118273716367SStefano Zampini PetscFunctionBegin;
118373716367SStefano Zampini PetscCall(KSPSetUp(ksp));
118473716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(ksp));
118573716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS);
118673716367SStefano Zampini }
118773716367SStefano Zampini
PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)1188d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y)
1189d71ae5a4SJacob Faibussowitsch {
11903b224e63SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
11913b224e63SBarry Smith PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1192443836d0SMatthew G Knepley KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1193d9eadc85SPierre Jolivet Mat AinvB = NULL;
1194ab1f0642SPierre Jolivet PetscInt N, P;
11953b224e63SBarry Smith
11963b224e63SBarry Smith PetscFunctionBegin;
1197c5d2311dSJed Brown switch (jac->schurfactorization) {
1198c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1199a04f6461SBarry Smith /* [A00 0; 0 -S], positive definite, suitable for MINRES */
12009566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12019566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12029566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12039566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12049566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12059566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12069566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12079566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12089566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12099566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1210e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12119566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
12129566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1213e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12149566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12159566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->y, jac->schurscale));
12169566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12179566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12189566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1219c5d2311dSJed Brown break;
1220c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1221a04f6461SBarry Smith /* [A00 0; A10 S], suitable for left preconditioning */
12229566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12239566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12259566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12269566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12279566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12289566063dSJacob Faibussowitsch PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
12299566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, -1.));
12309566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12319566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12329566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12339566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1234e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12359566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1236e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12379566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12389566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12399566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12409566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12419566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1242c5d2311dSJed Brown break;
1243c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1244a04f6461SBarry Smith /* [A00 A01; 0 S], suitable for right preconditioning */
12459566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12469566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12479566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1248e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12499566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1250e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12519566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12529371c9d4SSatish Balay PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12539371c9d4SSatish Balay PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
12549566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkA->x, -1.));
12559566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12569566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12579566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12589566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12599566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12609566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12619566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12629566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12639566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12649566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1265c5d2311dSJed Brown break;
1266c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1267c238f8cdSStefano Zampini /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1268ab1f0642SPierre Jolivet PetscCall(MatGetSize(jac->B, NULL, &P));
1269ab1f0642SPierre Jolivet N = P;
12709566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12719566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12729566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
1273d9eadc85SPierre Jolivet if (kspUpper == kspA) {
1274d9eadc85SPierre Jolivet PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1275d9eadc85SPierre Jolivet if (AinvB) {
1276d9eadc85SPierre Jolivet PetscCall(MatGetSize(AinvB, NULL, &N));
1277ab1f0642SPierre Jolivet if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1278f7cbcdf3SPierre Jolivet PetscMemType mtype;
1279ab1f0642SPierre Jolivet Vec c = NULL;
1280f7cbcdf3SPierre Jolivet PetscScalar *array;
1281ab1f0642SPierre Jolivet PetscInt m, M;
1282d9eadc85SPierre Jolivet
1283ab1f0642SPierre Jolivet PetscCall(MatGetSize(jac->B, &M, NULL));
1284d9eadc85SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1285ab1f0642SPierre Jolivet PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1286ab1f0642SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1287f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1288ab1f0642SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCall(VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1289f7cbcdf3SPierre Jolivet #endif
1290f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP)
1291ab1f0642SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCall(VecCreateMPIHIPWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1292f7cbcdf3SPierre Jolivet #endif
1293ab1f0642SPierre Jolivet PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1294ab1f0642SPierre Jolivet PetscCall(VecCopy(ilinkA->x, c));
1295d9eadc85SPierre Jolivet PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1296d9eadc85SPierre Jolivet PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1297f7cbcdf3SPierre Jolivet PetscCall(VecCopy(c, ilinkA->y)); // retrieve the solution as the last column of the composed Mat
1298f7cbcdf3SPierre Jolivet PetscCall(VecDestroy(&c));
1299d9eadc85SPierre Jolivet }
1300d9eadc85SPierre Jolivet }
1301d9eadc85SPierre Jolivet }
1302ab1f0642SPierre Jolivet if (N == P) PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y));
13039566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y));
13049566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
13059566063dSJacob Faibussowitsch PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
13069566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, -1.0));
13079566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
13089566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
13093b224e63SBarry Smith
13109566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1311e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
13129566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1313e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
13149566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
13159566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
13169566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13173b224e63SBarry Smith
1318443836d0SMatthew G Knepley if (kspUpper == kspA) {
1319d9eadc85SPierre Jolivet if (!AinvB) {
13209566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y));
13219566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
13229566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13239566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13249566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13259566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1326d9eadc85SPierre Jolivet } else PetscCall(MatMultAdd(AinvB, ilinkD->y, ilinkA->y, ilinkA->y));
1327443836d0SMatthew G Knepley } else {
13289566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13299566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13309566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13319566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
13329566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13339566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z));
13349566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z));
13359566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13369566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
1337443836d0SMatthew G Knepley }
13389566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13399566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
13409566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1341c5d2311dSJed Brown }
13423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
13433b224e63SBarry Smith }
13443b224e63SBarry Smith
1345d484b384SBoris Martin /*
1346d484b384SBoris Martin PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS
1347d484b384SBoris Martin
1348d484b384SBoris Martin Input Parameters:
1349d484b384SBoris Martin + pc - the PC context
1350d484b384SBoris Martin - X - matrix to copy column-layout from
1351d484b384SBoris Martin
1352d484b384SBoris Martin Notes:
1353d484b384SBoris Martin If matrices already exist with correct column count, they are reused.
1354d484b384SBoris Martin If column count changed, old matrices are destroyed and new ones created.
1355d484b384SBoris Martin */
PCFieldSplitCreateWorkMats_Private(PC pc,Mat X)1356d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X)
1357d484b384SBoris Martin {
1358d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1359d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head;
1360d484b384SBoris Martin PetscInt mx, Mx, my, My, N;
1361d484b384SBoris Martin
1362d484b384SBoris Martin PetscFunctionBegin;
1363d484b384SBoris Martin while (ilink) {
1364d484b384SBoris Martin /* check if reallocation needed (previous allocation with wrong column count) */
1365d484b384SBoris Martin if (ilink->X) {
1366d484b384SBoris Martin PetscCall(MatGetSize(ilink->X, NULL, &N));
1367d484b384SBoris Martin if (N != X->cmap->N) {
1368d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X));
1369d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y));
1370f5b94327SPierre Jolivet PetscCall(MatDestroy(&ilink->Z));
1371d484b384SBoris Martin }
1372d484b384SBoris Martin }
1373d484b384SBoris Martin /* create if needed */
1374d484b384SBoris Martin if (!ilink->X) {
1375d484b384SBoris Martin VecType xtype, ytype;
1376d484b384SBoris Martin
1377d484b384SBoris Martin PetscCall(VecGetType(ilink->x, &xtype));
1378d484b384SBoris Martin PetscCall(VecGetType(ilink->y, &ytype));
1379d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->x, &mx));
1380d484b384SBoris Martin PetscCall(VecGetSize(ilink->x, &Mx));
1381d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->y, &my));
1382d484b384SBoris Martin PetscCall(VecGetSize(ilink->y, &My));
1383d484b384SBoris Martin /* use default lda */
1384d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X));
1385d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y));
1386d484b384SBoris Martin }
1387d484b384SBoris Martin ilink = ilink->next;
1388d484b384SBoris Martin }
1389d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS);
1390d484b384SBoris Martin }
1391d484b384SBoris Martin
PCMatApply_FieldSplit_Schur(PC pc,Mat X,Mat Y)1392f5b94327SPierre Jolivet static PetscErrorCode PCMatApply_FieldSplit_Schur(PC pc, Mat X, Mat Y)
1393f5b94327SPierre Jolivet {
1394f5b94327SPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1395f5b94327SPierre Jolivet PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1396f5b94327SPierre Jolivet KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1397f5b94327SPierre Jolivet Mat AinvB = NULL;
1398f5b94327SPierre Jolivet PetscInt N, P;
1399f5b94327SPierre Jolivet
1400f5b94327SPierre Jolivet PetscFunctionBegin;
1401f5b94327SPierre Jolivet /* create working matrices with the correct number of columns */
1402f5b94327SPierre Jolivet PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1403f5b94327SPierre Jolivet switch (jac->schurfactorization) {
1404f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1405f5b94327SPierre Jolivet /* [A00 0; 0 -S], positive definite, suitable for MINRES */
1406f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1407f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1408f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1409f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1410f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1411f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1412f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1413f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1414f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1415f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1416f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1417f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->Y, jac->schurscale));
1418f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1419f5b94327SPierre Jolivet break;
1420f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1421f5b94327SPierre Jolivet /* [A00 0; A10 S], suitable for left preconditioning */
1422f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1423f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1424f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1425f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1426f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1427f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->X, -1.0));
1428f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1429f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1430f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1431f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1432f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1433f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1434f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1435f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1436f5b94327SPierre Jolivet break;
1437f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1438f5b94327SPierre Jolivet /* [A00 A01; 0 S], suitable for right preconditioning */
1439f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1440f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1441f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1442f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1443f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1444f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1445f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1446f5b94327SPierre Jolivet PetscCall(MatScale(ilinkA->X, -1.0));
1447f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, ADD_VALUES, SCATTER_FORWARD));
1448f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1449f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1450f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1451f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1452f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1453f5b94327SPierre Jolivet break;
1454f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1455f5b94327SPierre Jolivet /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1456f5b94327SPierre Jolivet PetscCall(MatGetSize(jac->B, NULL, &P));
1457f5b94327SPierre Jolivet N = P;
1458f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1459f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1460f5b94327SPierre Jolivet if (kspUpper == kspA) {
1461f5b94327SPierre Jolivet PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1462f5b94327SPierre Jolivet if (AinvB) {
1463f5b94327SPierre Jolivet PetscCall(MatGetSize(AinvB, NULL, &N));
1464f5b94327SPierre Jolivet if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1465f5b94327SPierre Jolivet PetscMemType mtype;
1466f5b94327SPierre Jolivet Mat C = NULL;
1467f5b94327SPierre Jolivet PetscScalar *array;
1468f5b94327SPierre Jolivet PetscInt m, M, q, Q, p;
1469f5b94327SPierre Jolivet
1470f5b94327SPierre Jolivet PetscCall(MatGetSize(jac->B, &M, NULL));
1471f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1472f5b94327SPierre Jolivet PetscCall(MatGetSize(X, NULL, &Q));
1473f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(X, NULL, &q));
1474f5b94327SPierre Jolivet PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1475f5b94327SPierre Jolivet if (N != P + Q) {
1476f5b94327SPierre Jolivet Mat replace;
1477f5b94327SPierre Jolivet
1478f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, NULL, &p));
1479f5b94327SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) {
1480f5b94327SPierre Jolivet PetscCall(PetscFree(array));
1481f5b94327SPierre Jolivet PetscCall(PetscMalloc1(m * (P + Q), &array));
1482f5b94327SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1483f5b94327SPierre Jolivet }
1484f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1485f5b94327SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) {
1486f5b94327SPierre Jolivet PetscCallCUDA(cudaFree(array));
1487f5b94327SPierre Jolivet PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1488f5b94327SPierre Jolivet PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1489f5b94327SPierre Jolivet }
1490f5b94327SPierre Jolivet #endif
1491f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1492f5b94327SPierre Jolivet else if (PetscMemTypeHIP(mtype)) {
1493f5b94327SPierre Jolivet PetscCallHIP(hipFree(array));
1494f5b94327SPierre Jolivet PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1495f5b94327SPierre Jolivet PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1496f5b94327SPierre Jolivet }
1497f5b94327SPierre Jolivet #endif
1498f5b94327SPierre Jolivet PetscCall(MatHeaderReplace(AinvB, &replace));
1499f5b94327SPierre Jolivet }
1500f5b94327SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1501f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1502f5b94327SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1503f5b94327SPierre Jolivet #endif
1504f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1505f5b94327SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1506f5b94327SPierre Jolivet #endif
1507f5b94327SPierre Jolivet PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1508f5b94327SPierre Jolivet PetscCall(MatCopy(ilinkA->X, C, SAME_NONZERO_PATTERN));
1509f5b94327SPierre Jolivet PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1510f5b94327SPierre Jolivet PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1511f5b94327SPierre Jolivet PetscCall(MatCopy(C, ilinkA->Y, SAME_NONZERO_PATTERN)); // retrieve solutions as last columns of the composed Mat
1512f5b94327SPierre Jolivet PetscCall(MatDestroy(&C));
1513f5b94327SPierre Jolivet }
1514f5b94327SPierre Jolivet }
1515f5b94327SPierre Jolivet }
1516f5b94327SPierre Jolivet if (N == P) PetscCall(KSPMatSolve(kspLower, ilinkA->X, ilinkA->Y));
1517f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1518f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1519f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->X, -1.0));
1520f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1521f5b94327SPierre Jolivet
1522f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1523f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1524f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1525f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1526f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1527f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1528f5b94327SPierre Jolivet
1529f5b94327SPierre Jolivet if (kspUpper == kspA) {
1530f5b94327SPierre Jolivet if (!AinvB) {
1531f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->Y));
1532f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->X, -1.0, ilinkA->Y, SAME_NONZERO_PATTERN));
1533f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1534f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1535f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1536f5b94327SPierre Jolivet } else {
1537f5b94327SPierre Jolivet PetscCall(MatMatMult(AinvB, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1538f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->Y, 1.0, ilinkA->X, SAME_NONZERO_PATTERN));
1539f5b94327SPierre Jolivet }
1540f5b94327SPierre Jolivet } else {
1541f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1542f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1543f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1544f5b94327SPierre Jolivet if (!ilinkA->Z) PetscCall(MatDuplicate(ilinkA->X, MAT_DO_NOT_COPY_VALUES, &ilinkA->Z));
1545f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1546f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspUpper, ilinkA->X, ilinkA->Z));
1547f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1548f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->Y, -1.0, ilinkA->Z, SAME_NONZERO_PATTERN));
1549f5b94327SPierre Jolivet }
1550f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1551f5b94327SPierre Jolivet }
1552f5b94327SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS);
1553f5b94327SPierre Jolivet }
1554f5b94327SPierre Jolivet
PCApplyTranspose_FieldSplit_Schur(PC pc,Vec x,Vec y)15557b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y)
15567b665727SPierre Jolivet {
15577b665727SPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
15587b665727SPierre Jolivet PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
15597b665727SPierre Jolivet KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
15607b665727SPierre Jolivet
15617b665727SPierre Jolivet PetscFunctionBegin;
15627b665727SPierre Jolivet switch (jac->schurfactorization) {
15637b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
15647b665727SPierre Jolivet /* [A00 0; 0 -S], positive definite, suitable for MINRES */
15657b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15667b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15677b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15687b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15697b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15707b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15717b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15727b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15737b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15747b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1575e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15767b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1577e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
15787b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
15797b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
15807b665727SPierre Jolivet PetscCall(VecScale(ilinkD->y, jac->schurscale));
15817b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15827b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15837b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15847b665727SPierre Jolivet break;
15857b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
15867b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15877b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15887b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15897b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15907b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15917b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15927b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
15937b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.));
15947b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15957b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15967b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15977b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1598e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15997b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1600e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16017b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16027b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16037b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16047b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16057b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16067b665727SPierre Jolivet break;
16077b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
16087b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16097b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16107b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1611e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16127b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1613e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16147b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16157b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16167b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16177b665727SPierre Jolivet PetscCall(VecScale(ilinkA->x, -1.));
16187b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16197b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16207b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16217b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16227b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16237b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16247b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16257b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16267b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16277b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16287b665727SPierre Jolivet break;
16297b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_FULL:
16307b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16317b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16327b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16337b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y));
16347b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y));
16357b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16367b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
16377b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.0));
16387b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16397b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16407b665727SPierre Jolivet
16417b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1642e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16437b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1644e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16457b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16467b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16477b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16487b665727SPierre Jolivet
16497b665727SPierre Jolivet if (kspLower == kspA) {
16507b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y));
16517b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
16527b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16537b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16547b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16557b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16567b665727SPierre Jolivet } else {
16577b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16587b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16597b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16607b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16617b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16627b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z));
16637b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z));
16647b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16657b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
16667b665727SPierre Jolivet }
16677b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16687b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16697b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16707b665727SPierre Jolivet }
16717b665727SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS);
16727b665727SPierre Jolivet }
16737b665727SPierre Jolivet
16745becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \
16755becce15SPierre Jolivet ((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) || \
16765becce15SPierre Jolivet 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) || \
16775becce15SPierre Jolivet VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE)))
16785becce15SPierre Jolivet
PCApply_FieldSplit(PC pc,Vec x,Vec y)1679d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y)
1680d71ae5a4SJacob Faibussowitsch {
16810971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
16825a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head;
1683939b8a20SBarry Smith PetscInt cnt, bs;
16840971522cSBarry Smith
16850971522cSBarry Smith PetscFunctionBegin;
168679416396SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) {
168780670ca5SBarry Smith PetscBool matnest;
168880670ca5SBarry Smith
168980670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
169080670ca5SBarry Smith if (jac->defaultsplit && !matnest) {
16919566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs));
16922472a847SBarry Smith 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);
16939566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs));
16942472a847SBarry Smith 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);
16959566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
16965a9f2f41SSatish Balay while (ilink) {
16979566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
16989566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
16999566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17009566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17015a9f2f41SSatish Balay ilink = ilink->next;
17020971522cSBarry Smith }
17039566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
17041b9fc7fcSBarry Smith } else {
17059566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0));
17065a9f2f41SSatish Balay while (ilink) {
17079566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
17085a9f2f41SSatish Balay ilink = ilink->next;
17091b9fc7fcSBarry Smith }
17101b9fc7fcSBarry Smith }
1711e52d2c62SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
17129566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0));
1713e52d2c62SBarry Smith /* solve on first block for first block variables */
17149566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17159566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17169566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17179566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17189566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17199566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17209566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17219566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1722e52d2c62SBarry Smith
1723e52d2c62SBarry Smith /* compute the residual only onto second block variables using first block variables */
17249566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x));
1725e52d2c62SBarry Smith ilink = ilink->next;
17269566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0));
17279566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17289566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1729e52d2c62SBarry Smith
1730e52d2c62SBarry Smith /* solve on second block variables */
17319566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17329566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17339566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17349566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17359566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17369566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
173716913363SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
173879416396SBarry Smith if (!jac->w1) {
17399566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1));
17409566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2));
174179416396SBarry Smith }
17429566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0));
17439566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
17443e197d65SBarry Smith cnt = 1;
17455a9f2f41SSatish Balay while (ilink->next) {
17465a9f2f41SSatish Balay ilink = ilink->next;
17473e197d65SBarry Smith /* compute the residual only over the part of the vector needed */
17489566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x));
17499566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0));
17509566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17519566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17529566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17539566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17549566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17559566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17569566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17579566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17583e197d65SBarry Smith }
175951f519a2SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
176011755939SBarry Smith cnt -= 2;
176151f519a2SBarry Smith while (ilink->previous) {
176251f519a2SBarry Smith ilink = ilink->previous;
176311755939SBarry Smith /* compute the residual only over the part of the vector needed */
17649566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x));
17659566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0));
17669566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17679566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17689566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17699566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17709566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17719566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17729566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17739566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
177451f519a2SBarry Smith }
177511755939SBarry Smith }
177663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type);
17773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
17780971522cSBarry Smith }
17790971522cSBarry Smith
PCMatApply_FieldSplit(PC pc,Mat X,Mat Y)1780d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y)
1781d484b384SBoris Martin {
1782d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1783d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head;
1784d484b384SBoris Martin PetscInt cnt;
1785d484b384SBoris Martin
1786d484b384SBoris Martin PetscFunctionBegin;
1787d484b384SBoris Martin /* create working matrices with the correct number of columns */
1788d484b384SBoris Martin PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1789d484b384SBoris Martin if (jac->type == PC_COMPOSITE_ADDITIVE) {
1790d484b384SBoris Martin PetscCall(MatZeroEntries(Y));
1791d484b384SBoris Martin while (ilink) {
1792d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1793d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1794d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1795d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1796d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1797d484b384SBoris Martin ilink = ilink->next;
1798d484b384SBoris Martin }
1799d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
1800d484b384SBoris Martin PetscCall(MatZeroEntries(Y));
1801d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1802d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1803d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1804d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1805d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1806d484b384SBoris Martin
1807d484b384SBoris Martin /* compute the residual only onto second block variables using first block variables */
1808d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X));
1809d484b384SBoris Martin ilink = ilink->next;
1810d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0));
1811d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1812d484b384SBoris Martin
1813d484b384SBoris Martin /* solve on second block variables */
1814d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1815d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1816d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1817d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1818d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1819d484b384SBoris Martin /* general multiplicative with any number of splits */
1820d484b384SBoris Martin PetscCall(MatZeroEntries(Y));
1821d484b384SBoris Martin /* first split */
1822d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1823d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1824d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1825d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1826d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1827d484b384SBoris Martin cnt = 1;
1828d484b384SBoris Martin /* forward sweep */
1829d484b384SBoris Martin while (ilink->next) {
1830d484b384SBoris Martin ilink = ilink->next;
1831d484b384SBoris Martin /* compute the residual only over the part of the vector needed */
1832d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1833d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0));
1834d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1835d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1836d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1837d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1838d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1839d484b384SBoris Martin }
1840d484b384SBoris Martin /* backward sweep for symmetric multiplicative */
1841d484b384SBoris Martin if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1842d484b384SBoris Martin cnt -= 2;
1843d484b384SBoris Martin while (ilink->previous) {
1844d484b384SBoris Martin ilink = ilink->previous;
1845d484b384SBoris Martin /* compute the residual only over the part of the vector needed */
1846d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1847d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0));
1848d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1849d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1850d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1851d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1852d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1853d484b384SBoris Martin }
1854d484b384SBoris Martin }
1855d484b384SBoris Martin } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type");
1856d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS);
1857d484b384SBoris Martin }
1858d484b384SBoris Martin
PCApply_FieldSplit_GKB(PC pc,Vec x,Vec y)1859d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y)
1860d71ae5a4SJacob Faibussowitsch {
1861a51937d4SCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1862a51937d4SCarola Kruse PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1863a51937d4SCarola Kruse KSP ksp = ilinkA->ksp;
1864de482cd7SCarola Kruse Vec u, v, Hu, d, work1, work2;
1865e071a0a4SCarola Kruse PetscScalar alpha, z, nrmz2, *vecz;
1866e071a0a4SCarola Kruse PetscReal lowbnd, nu, beta;
1867a51937d4SCarola Kruse PetscInt j, iterGKB;
1868a51937d4SCarola Kruse
1869a51937d4SCarola Kruse PetscFunctionBegin;
18709566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18719566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
18729566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18739566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1874e071a0a4SCarola Kruse
1875e071a0a4SCarola Kruse u = jac->u;
1876e071a0a4SCarola Kruse v = jac->v;
1877e071a0a4SCarola Kruse Hu = jac->Hu;
1878e071a0a4SCarola Kruse d = jac->d;
1879e071a0a4SCarola Kruse work1 = jac->w1;
1880e071a0a4SCarola Kruse work2 = jac->w2;
1881e071a0a4SCarola Kruse vecz = jac->vecz;
1882a51937d4SCarola Kruse
1883a51937d4SCarola Kruse /* Change RHS to comply with matrix regularization H = A + nu*B*B' */
1884a51937d4SCarola Kruse /* Add q = q + nu*B*b */
1885a51937d4SCarola Kruse if (jac->gkbnu) {
1886a51937d4SCarola Kruse nu = jac->gkbnu;
18879566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, jac->gkbnu));
18889566063dSJacob Faibussowitsch PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */
1889a51937d4SCarola Kruse } else {
1890a51937d4SCarola Kruse /* Situation when no augmented Lagrangian is used. Then we set inner */
1891a51937d4SCarola Kruse /* matrix N = I in [Ar13], and thus nu = 1. */
1892a51937d4SCarola Kruse nu = 1;
1893a51937d4SCarola Kruse }
1894a51937d4SCarola Kruse
1895a51937d4SCarola Kruse /* Transform rhs from [q,tilde{b}] to [0,b] */
18969566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
18979566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y));
18989566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y));
18999566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
19009566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1));
19019566063dSJacob Faibussowitsch PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x */
1902a51937d4SCarola Kruse
1903a51937d4SCarola Kruse /* First step of algorithm */
19049566063dSJacob Faibussowitsch PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/
1905e071a0a4SCarola Kruse KSPCheckDot(ksp, beta);
1906addd1e01SJunchao Zhang beta = PetscSqrtReal(nu) * beta;
19079566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c */
19089566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u = H^{-1}*B*v */
19099566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19109566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u));
19119566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u));
19129566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19139566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */
19149566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha));
1915e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha);
191608401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1917addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19189566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha));
19199566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c */
1920de482cd7SCarola Kruse
1921a51937d4SCarola Kruse z = beta / alpha;
1922a51937d4SCarola Kruse vecz[1] = z;
1923a51937d4SCarola Kruse
1924de482cd7SCarola Kruse /* Computation of first iterate x(1) and p(1) */
19259566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u));
19269566063dSJacob Faibussowitsch PetscCall(VecCopy(d, ilinkD->y));
19279566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->y, -z));
1928a51937d4SCarola Kruse
19299371c9d4SSatish Balay iterGKB = 1;
19309371c9d4SSatish Balay lowbnd = 2 * jac->gkbtol;
193148a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1932de482cd7SCarola Kruse
1933a51937d4SCarola Kruse while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) {
1934a51937d4SCarola Kruse iterGKB += 1;
19359566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */
19369566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu, -alpha, work1));
19379566063dSJacob Faibussowitsch PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v */
1938addd1e01SJunchao Zhang beta = beta / PetscSqrtReal(nu);
19399566063dSJacob Faibussowitsch PetscCall(VecScale(v, 1.0 / beta));
19409566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */
19419566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu));
19429566063dSJacob Faibussowitsch PetscCall(VecAXPY(work2, -beta, Hu));
19439566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19449566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u));
19459566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u));
19469566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19479566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */
19489566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha));
1949e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha);
195008401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1951addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19529566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha));
1953a51937d4SCarola Kruse
1954e071a0a4SCarola Kruse z = -beta / alpha * z; /* z <- beta/alpha*z */
1955a51937d4SCarola Kruse vecz[0] = z;
1956a51937d4SCarola Kruse
1957a51937d4SCarola Kruse /* Computation of new iterate x(i+1) and p(i+1) */
19589566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */
19599566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u)); /* r = r + z*u */
19609566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkD->y, -z, d)); /* p = p - z*d */
19619566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, ilinkA->y, Hu)); /* ||u||_H = u'*H*u */
19629566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, ilinkA->y, &nrmz2));
1963a51937d4SCarola Kruse
1964a51937d4SCarola Kruse /* Compute Lower Bound estimate */
1965a51937d4SCarola Kruse if (iterGKB > jac->gkbdelay) {
1966a51937d4SCarola Kruse lowbnd = 0.0;
1967ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]);
1968addd1e01SJunchao Zhang lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2));
1969a51937d4SCarola Kruse }
1970a51937d4SCarola Kruse
1971ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2];
197248a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1973a51937d4SCarola Kruse }
1974a51937d4SCarola Kruse
19759566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19769566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19779566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19789566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
1980a51937d4SCarola Kruse }
1981a51937d4SCarola Kruse
1982421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \
19833ba16761SJacob Faibussowitsch ((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) || \
19849371c9d4SSatish Balay 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) || \
19853ba16761SJacob Faibussowitsch VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE)))
1986421e10b8SBarry Smith
PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)1987d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y)
1988d71ae5a4SJacob Faibussowitsch {
1989421e10b8SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1990421e10b8SBarry Smith PC_FieldSplitLink ilink = jac->head;
1991939b8a20SBarry Smith PetscInt bs;
1992421e10b8SBarry Smith
1993421e10b8SBarry Smith PetscFunctionBegin;
1994421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) {
199580670ca5SBarry Smith PetscBool matnest;
199680670ca5SBarry Smith
199780670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
199880670ca5SBarry Smith if (jac->defaultsplit && !matnest) {
19999566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs));
20002472a847SBarry Smith 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);
20019566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs));
20022472a847SBarry Smith 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);
20039566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
2004421e10b8SBarry Smith while (ilink) {
20059566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
20069566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y));
20079566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
20089566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
2009421e10b8SBarry Smith ilink = ilink->next;
2010421e10b8SBarry Smith }
20119566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
2012421e10b8SBarry Smith } else {
20139566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0));
2014421e10b8SBarry Smith while (ilink) {
20159566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2016421e10b8SBarry Smith ilink = ilink->next;
2017421e10b8SBarry Smith }
2018421e10b8SBarry Smith }
2019421e10b8SBarry Smith } else {
2020421e10b8SBarry Smith if (!jac->w1) {
20219566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1));
20229566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2));
2023421e10b8SBarry Smith }
20249566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0));
2025421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
20269566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2027421e10b8SBarry Smith while (ilink->next) {
2028421e10b8SBarry Smith ilink = ilink->next;
20299566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20309566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20319566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2032421e10b8SBarry Smith }
2033421e10b8SBarry Smith while (ilink->previous) {
2034421e10b8SBarry Smith ilink = ilink->previous;
20359566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20369566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20379566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2038421e10b8SBarry Smith }
2039421e10b8SBarry Smith } else {
2040421e10b8SBarry Smith while (ilink->next) { /* get to last entry in linked list */
2041421e10b8SBarry Smith ilink = ilink->next;
2042421e10b8SBarry Smith }
20439566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2044421e10b8SBarry Smith while (ilink->previous) {
2045421e10b8SBarry Smith ilink = ilink->previous;
20469566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20479566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20489566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2049421e10b8SBarry Smith }
2050421e10b8SBarry Smith }
2051421e10b8SBarry Smith }
20523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2053421e10b8SBarry Smith }
2054421e10b8SBarry Smith
PCReset_FieldSplit(PC pc)2055d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc)
2056d71ae5a4SJacob Faibussowitsch {
20570971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
20585a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head, next;
20590971522cSBarry Smith
20600971522cSBarry Smith PetscFunctionBegin;
20615a9f2f41SSatish Balay while (ilink) {
20629566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&ilink->ksp));
20639566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->x));
20649566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->y));
20659566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->z));
2066d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X));
2067d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y));
2068f5b94327SPierre Jolivet PetscCall(MatDestroy(&ilink->Z));
20699566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&ilink->sctx));
20709566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is));
20719566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col));
20729566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->splitname));
20739566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields));
20749566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields_col));
20755a9f2f41SSatish Balay next = ilink->next;
20769566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink));
20775a9f2f41SSatish Balay ilink = next;
20780971522cSBarry Smith }
2079f5f0d762SBarry Smith jac->head = NULL;
20809566063dSJacob Faibussowitsch PetscCall(PetscFree2(jac->x, jac->y));
2081574deadeSBarry Smith if (jac->mat && jac->mat != jac->pmat) {
20829566063dSJacob Faibussowitsch PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat));
2083574deadeSBarry Smith } else if (jac->mat) {
20840298fd71SBarry Smith jac->mat = NULL;
2085574deadeSBarry Smith }
20869566063dSJacob Faibussowitsch if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat));
20879566063dSJacob Faibussowitsch if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield));
2088f5f0d762SBarry Smith jac->nsplits = 0;
20899566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w1));
20909566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w2));
209173716367SStefano Zampini if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
20929566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur));
20939566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schurp));
20949566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user));
20959566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspschur));
20969566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspupper));
20979566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->B));
20989566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->C));
20999566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->H));
21009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->u));
21019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->v));
21029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->Hu));
21039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->d));
21049566063dSJacob Faibussowitsch PetscCall(PetscFree(jac->vecz));
21059566063dSJacob Faibussowitsch PetscCall(PetscViewerDestroy(&jac->gkbviewer));
21066dbb499eSCian Wilson jac->isrestrict = PETSC_FALSE;
21073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2108574deadeSBarry Smith }
2109574deadeSBarry Smith
PCDestroy_FieldSplit(PC pc)2110d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc)
2111d71ae5a4SJacob Faibussowitsch {
2112574deadeSBarry Smith PetscFunctionBegin;
21139566063dSJacob Faibussowitsch PetscCall(PCReset_FieldSplit(pc));
21149566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data));
21152e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
21169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL));
21179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL));
21189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL));
21199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL));
21202e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL));
21212e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL));
21222e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
21232e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
21242e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
21252e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
21262e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
21279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
21289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
21299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
21302e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
21313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
21320971522cSBarry Smith }
21330971522cSBarry Smith
PCSetFromOptions_FieldSplit(PC pc,PetscOptionItems PetscOptionsObject)2134ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject)
2135d71ae5a4SJacob Faibussowitsch {
21366c924f48SJed Brown PetscInt bs;
21377b752e3dSPatrick Sanan PetscBool flg;
21389dcbbd2bSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
21393b224e63SBarry Smith PCCompositeType ctype;
21401b9fc7fcSBarry Smith
21410971522cSBarry Smith PetscFunctionBegin;
2142d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options");
21439566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL));
21449566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg));
21451baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs));
21462686e3e9SMatthew G. Knepley jac->diag_use_amat = pc->useAmat;
21479566063dSJacob Faibussowitsch 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));
21482686e3e9SMatthew G. Knepley jac->offdiag_use_amat = pc->useAmat;
21499566063dSJacob Faibussowitsch 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));
21509566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL));
21519566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */
21529566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg));
21531baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetType(pc, ctype));
2154c30613efSMatthew Knepley /* Only setup fields once */
2155b6555650SPierre Jolivet if (jac->bs > 0 && jac->nsplits == 0) {
215680670ca5SBarry Smith /* only allow user to set fields from command line.
2157d32f9abdSBarry Smith otherwise user can set them in PCFieldSplitSetDefaults() */
21589566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
21599566063dSJacob Faibussowitsch if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
2160d32f9abdSBarry Smith }
2161c5d2311dSJed Brown if (jac->type == PC_COMPOSITE_SCHUR) {
21629566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg));
21639566063dSJacob Faibussowitsch if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n"));
21649566063dSJacob Faibussowitsch 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));
21659566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL));
21669566063dSJacob Faibussowitsch PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL));
2167a51937d4SCarola Kruse } else if (jac->type == PC_COMPOSITE_GKB) {
2168a077d33dSBarry Smith PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL));
2169a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL));
2170a077d33dSBarry Smith PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0));
2171a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL));
21729566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL));
2173c5d2311dSJed Brown }
217434603f55SBarry Smith /*
217534603f55SBarry Smith In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet.
217634603f55SBarry Smith 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
217734603f55SBarry Smith is called on the outer solver in case changes were made in the options database
217834603f55SBarry Smith
217934603f55SBarry Smith 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()
218034603f55SBarry Smith 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.
218134603f55SBarry Smith Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types.
218234603f55SBarry Smith
218334603f55SBarry Smith There could be a negative side effect of calling the KSPSetFromOptions() below.
218434603f55SBarry Smith
218534603f55SBarry Smith If one captured the PetscObjectState of the options database one could skip these calls if the database has not changed from the previous call
218634603f55SBarry Smith */
218734603f55SBarry Smith if (jac->issetup) {
218834603f55SBarry Smith PC_FieldSplitLink ilink = jac->head;
218934603f55SBarry Smith if (jac->type == PC_COMPOSITE_SCHUR) {
219034603f55SBarry Smith if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper));
219134603f55SBarry Smith if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur));
219234603f55SBarry Smith }
219334603f55SBarry Smith while (ilink) {
219434603f55SBarry Smith if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp));
219534603f55SBarry Smith ilink = ilink->next;
219634603f55SBarry Smith }
219734603f55SBarry Smith }
2198d0609cedSBarry Smith PetscOptionsHeadEnd();
21993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
22000971522cSBarry Smith }
22010971522cSBarry Smith
PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt * fields,const PetscInt * fields_col)2202d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col)
2203d71ae5a4SJacob Faibussowitsch {
220497bbdb24SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
22055a9f2f41SSatish Balay PC_FieldSplitLink ilink, next = jac->head;
220669a612a9SBarry Smith char prefix[128];
22075d4c12cdSJungho Lee PetscInt i;
2208835f2295SStefano Zampini PetscLogEvent nse;
22090971522cSBarry Smith
22100971522cSBarry Smith PetscFunctionBegin;
22116c924f48SJed Brown if (jac->splitdefined) {
22129566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
22133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
22146c924f48SJed Brown }
2215ac530a7eSPierre Jolivet for (i = 0; i < n; i++) PetscCheck(fields[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", fields[i]);
22169566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink));
2217a04f6461SBarry Smith if (splitname) {
22189566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2219a04f6461SBarry Smith } else {
22209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3, &ilink->splitname));
222163a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits));
2222a04f6461SBarry Smith }
2223835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2224835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
22259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields));
22269566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields, fields, n));
22279566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields_col));
22289566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n));
22292fa5cd67SKarl Rupp
22305a9f2f41SSatish Balay ilink->nfields = n;
22310298fd71SBarry Smith ilink->next = NULL;
22329566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
22333821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
22349566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
22359566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
22369566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
223769a612a9SBarry Smith
22389566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
22399566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
22400971522cSBarry Smith
22410971522cSBarry Smith if (!next) {
22425a9f2f41SSatish Balay jac->head = ilink;
22430298fd71SBarry Smith ilink->previous = NULL;
22440971522cSBarry Smith } else {
2245ad540459SPierre Jolivet while (next->next) next = next->next;
22465a9f2f41SSatish Balay next->next = ilink;
224751f519a2SBarry Smith ilink->previous = next;
22480971522cSBarry Smith }
22490971522cSBarry Smith jac->nsplits++;
22503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
22510971522cSBarry Smith }
22520971522cSBarry Smith
PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc,PetscInt * n,KSP ** subksp)2253d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2254d71ae5a4SJacob Faibussowitsch {
2255285fb4e2SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2256285fb4e2SStefano Zampini
2257285fb4e2SStefano Zampini PetscFunctionBegin;
2258285fb4e2SStefano Zampini *subksp = NULL;
2259285fb4e2SStefano Zampini if (n) *n = 0;
2260285fb4e2SStefano Zampini if (jac->type == PC_COMPOSITE_SCHUR) {
2261285fb4e2SStefano Zampini PetscInt nn;
2262285fb4e2SStefano Zampini
226328b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()");
226463a3b9bcSJacob Faibussowitsch PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits);
2265285fb4e2SStefano Zampini nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0);
22669566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nn, subksp));
2267285fb4e2SStefano Zampini (*subksp)[0] = jac->head->ksp;
2268285fb4e2SStefano Zampini (*subksp)[1] = jac->kspschur;
2269285fb4e2SStefano Zampini if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper;
2270285fb4e2SStefano Zampini if (n) *n = nn;
2271285fb4e2SStefano Zampini }
22723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2273285fb4e2SStefano Zampini }
2274285fb4e2SStefano Zampini
PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt * n,KSP ** subksp)2275d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp)
2276d71ae5a4SJacob Faibussowitsch {
2277e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2278e69d4d44SBarry Smith
2279e69d4d44SBarry Smith PetscFunctionBegin;
228028b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()");
22819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp));
22829566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp));
22832fa5cd67SKarl Rupp
2284e69d4d44SBarry Smith (*subksp)[1] = jac->kspschur;
228513e0d083SBarry Smith if (n) *n = jac->nsplits;
22863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2287e69d4d44SBarry Smith }
22880971522cSBarry Smith
PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt * n,KSP ** subksp)2289d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2290d71ae5a4SJacob Faibussowitsch {
22910971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
22920971522cSBarry Smith PetscInt cnt = 0;
22935a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head;
22940971522cSBarry Smith
22950971522cSBarry Smith PetscFunctionBegin;
22969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp));
22975a9f2f41SSatish Balay while (ilink) {
22985a9f2f41SSatish Balay (*subksp)[cnt++] = ilink->ksp;
22995a9f2f41SSatish Balay ilink = ilink->next;
23000971522cSBarry Smith }
230163a3b9bcSJacob Faibussowitsch 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);
230213e0d083SBarry Smith if (n) *n = jac->nsplits;
23033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
23040971522cSBarry Smith }
23050971522cSBarry Smith
2306cc4c1da9SBarry Smith /*@
2307f1580f4eSBarry Smith PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`.
23086dbb499eSCian Wilson
23096dbb499eSCian Wilson Input Parameters:
23106dbb499eSCian Wilson + pc - the preconditioner context
2311feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted
23126dbb499eSCian Wilson
23136dbb499eSCian Wilson Level: advanced
23146dbb499eSCian Wilson
2315feefa0e1SJacob Faibussowitsch Developer Notes:
2316f1580f4eSBarry Smith It seems the resulting `IS`s will not cover the entire space, so
2317f1580f4eSBarry Smith how can they define a convergent preconditioner? Needs explaining.
2318f1580f4eSBarry Smith
231960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
23206dbb499eSCian Wilson @*/
PCFieldSplitRestrictIS(PC pc,IS isy)2321d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy)
2322d71ae5a4SJacob Faibussowitsch {
23236dbb499eSCian Wilson PetscFunctionBegin;
23246dbb499eSCian Wilson PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23256dbb499eSCian Wilson PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
2326cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy));
23273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
23286dbb499eSCian Wilson }
23296dbb499eSCian Wilson
PCFieldSplitRestrictIS_FieldSplit(PC pc,IS isy)2330d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy)
2331d71ae5a4SJacob Faibussowitsch {
23326dbb499eSCian Wilson PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
23336dbb499eSCian Wilson PC_FieldSplitLink ilink = jac->head, next;
23346dbb499eSCian Wilson PetscInt localsize, size, sizez, i;
23356dbb499eSCian Wilson const PetscInt *ind, *indz;
23366dbb499eSCian Wilson PetscInt *indc, *indcz;
23376dbb499eSCian Wilson PetscBool flg;
23386dbb499eSCian Wilson
23396dbb499eSCian Wilson PetscFunctionBegin;
23409566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isy, &localsize));
23419566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy)));
23426dbb499eSCian Wilson size -= localsize;
23436dbb499eSCian Wilson while (ilink) {
23446dbb499eSCian Wilson IS isrl, isr;
23451c7cfba8SBarry Smith PC subpc;
23469566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl));
23479566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isrl, &localsize));
23489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indc));
23499566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isrl, &ind));
23509566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indc, ind, localsize));
23519566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isrl, &ind));
23529566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isrl));
23536dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indc + i) += size;
23549566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr));
23559566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr));
23569566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is));
23576dbb499eSCian Wilson ilink->is = isr;
23589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr));
23599566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col));
23606dbb499eSCian Wilson ilink->is_col = isr;
23619566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isr));
23629566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ilink->ksp, &subpc));
23639566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg));
23646dbb499eSCian Wilson if (flg) {
23656dbb499eSCian Wilson IS iszl, isz;
23666dbb499eSCian Wilson MPI_Comm comm;
23679566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(ilink->is, &localsize));
23686dbb499eSCian Wilson comm = PetscObjectComm((PetscObject)ilink->is);
23699566063dSJacob Faibussowitsch PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl));
23709566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm));
23716dbb499eSCian Wilson sizez -= localsize;
23729566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(iszl, &localsize));
23739566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indcz));
23749566063dSJacob Faibussowitsch PetscCall(ISGetIndices(iszl, &indz));
23759566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indcz, indz, localsize));
23769566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(iszl, &indz));
23779566063dSJacob Faibussowitsch PetscCall(ISDestroy(&iszl));
23786dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indcz + i) += sizez;
23799566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz));
23809566063dSJacob Faibussowitsch PetscCall(PCFieldSplitRestrictIS(subpc, isz));
23819566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isz));
23826dbb499eSCian Wilson }
23836dbb499eSCian Wilson next = ilink->next;
23846dbb499eSCian Wilson ilink = next;
23856dbb499eSCian Wilson }
23866dbb499eSCian Wilson jac->isrestrict = PETSC_TRUE;
23873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
23886dbb499eSCian Wilson }
23896dbb499eSCian Wilson
PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)2390d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is)
2391d71ae5a4SJacob Faibussowitsch {
2392704ba839SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2393704ba839SBarry Smith PC_FieldSplitLink ilink, next = jac->head;
2394704ba839SBarry Smith char prefix[128];
2395835f2295SStefano Zampini PetscLogEvent nse;
2396704ba839SBarry Smith
2397704ba839SBarry Smith PetscFunctionBegin;
23986c924f48SJed Brown if (jac->splitdefined) {
23999566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
24003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
24016c924f48SJed Brown }
24029566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink));
2403a04f6461SBarry Smith if (splitname) {
24049566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2405a04f6461SBarry Smith } else {
24069566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(8, &ilink->splitname));
240763a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits));
2408a04f6461SBarry Smith }
2409835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2410835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
24119566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is));
24129566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is));
2413b5787286SJed Brown ilink->is = is;
24149566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is));
24159566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col));
2416b5787286SJed Brown ilink->is_col = is;
24170298fd71SBarry Smith ilink->next = NULL;
24189566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
24193821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
24209566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
24219566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
24229566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
2423704ba839SBarry Smith
24249566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
24259566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
2426704ba839SBarry Smith
2427704ba839SBarry Smith if (!next) {
2428704ba839SBarry Smith jac->head = ilink;
24290298fd71SBarry Smith ilink->previous = NULL;
2430704ba839SBarry Smith } else {
2431ad540459SPierre Jolivet while (next->next) next = next->next;
2432704ba839SBarry Smith next->next = ilink;
2433704ba839SBarry Smith ilink->previous = next;
2434704ba839SBarry Smith }
2435704ba839SBarry Smith jac->nsplits++;
24363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2437704ba839SBarry Smith }
2438704ba839SBarry Smith
24395d83a8b1SBarry Smith /*@
244060f59c3bSBarry Smith PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT`
24410971522cSBarry Smith
2442c3339decSBarry Smith Logically Collective
24430971522cSBarry Smith
24440971522cSBarry Smith Input Parameters:
24450971522cSBarry Smith + pc - the preconditioner context
244660f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used
24470971522cSBarry Smith . n - the number of fields in this split
24483b374dbdSBarry Smith . fields - the fields in this split
244980670ca5SBarry Smith - fields_col - generally the same as `fields`, if it does not match `fields` then the submatrix that is solved for this set of fields comes from an off-diagonal block
245080670ca5SBarry Smith of the matrix and `fields_col` provides the column indices for that block
245180670ca5SBarry Smith
245280670ca5SBarry Smith Options Database Key:
245380670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
24540971522cSBarry Smith
24550971522cSBarry Smith Level: intermediate
24560971522cSBarry Smith
245795452b02SPatrick Sanan Notes:
2458f1580f4eSBarry Smith Use `PCFieldSplitSetIS()` to set a general set of indices as a split.
2459d32f9abdSBarry Smith
246080670ca5SBarry Smith If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`.
246180670ca5SBarry Smith
246280670ca5SBarry Smith If the matrix used to construct the preconditioner is not `MATNEST` then
246354c05997SPierre Jolivet `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or
246480670ca5SBarry Smith to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block
2465f1580f4eSBarry Smith 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
246614c74629SNuno Nobre 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x....
2467f1580f4eSBarry Smith where the numbered entries indicate what is in the split.
2468d32f9abdSBarry Smith
2469db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options
247060f59c3bSBarry Smith for this split will be available under the prefix `-fieldsplit_SPLITNAME_`.
2471db4c96c1SJed Brown
247280670ca5SBarry Smith `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields`
24733b374dbdSBarry Smith
2474feefa0e1SJacob Faibussowitsch Developer Notes:
2475f1580f4eSBarry Smith This routine does not actually create the `IS` representing the split, that is delayed
2476f1580f4eSBarry Smith until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be
24775d4c12cdSJungho Lee available when this routine is called.
24785d4c12cdSJungho Lee
247980670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`,
248054c05997SPierre Jolivet `MatSetBlockSize()`, `MatCreateNest()`
24810971522cSBarry Smith @*/
PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt fields[],const PetscInt fields_col[])2482cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[])
2483d71ae5a4SJacob Faibussowitsch {
24840971522cSBarry Smith PetscFunctionBegin;
24850700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24864f572ea9SToby Isaac PetscAssertPointer(splitname, 2);
248763a3b9bcSJacob Faibussowitsch PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname);
24884f572ea9SToby Isaac PetscAssertPointer(fields, 4);
2489cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col));
24903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
24910971522cSBarry Smith }
24920971522cSBarry Smith
2493c84da90fSDmitry Karpeev /*@
2494f1580f4eSBarry Smith PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2495c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2496c84da90fSDmitry Karpeev
2497c3339decSBarry Smith Logically Collective
2498c84da90fSDmitry Karpeev
2499c84da90fSDmitry Karpeev Input Parameters:
2500c84da90fSDmitry Karpeev + pc - the preconditioner object
2501c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2502c84da90fSDmitry Karpeev
250320f4b53cSBarry Smith Options Database Key:
2504147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks
2505c84da90fSDmitry Karpeev
2506c84da90fSDmitry Karpeev Level: intermediate
2507c84da90fSDmitry Karpeev
250860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT`
2509c84da90fSDmitry Karpeev @*/
PCFieldSplitSetDiagUseAmat(PC pc,PetscBool flg)2510d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg)
2511d71ae5a4SJacob Faibussowitsch {
2512c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2513c84da90fSDmitry Karpeev PetscBool isfs;
2514c84da90fSDmitry Karpeev
2515c84da90fSDmitry Karpeev PetscFunctionBegin;
2516c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25179566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
251828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2519c84da90fSDmitry Karpeev jac->diag_use_amat = flg;
25203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2521c84da90fSDmitry Karpeev }
2522c84da90fSDmitry Karpeev
2523c84da90fSDmitry Karpeev /*@
2524f1580f4eSBarry Smith PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2525c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2526c84da90fSDmitry Karpeev
2527c3339decSBarry Smith Logically Collective
2528c84da90fSDmitry Karpeev
252920f4b53cSBarry Smith Input Parameter:
2530c84da90fSDmitry Karpeev . pc - the preconditioner object
2531c84da90fSDmitry Karpeev
253220f4b53cSBarry Smith Output Parameter:
2533c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2534c84da90fSDmitry Karpeev
2535c84da90fSDmitry Karpeev Level: intermediate
2536c84da90fSDmitry Karpeev
253760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT`
2538c84da90fSDmitry Karpeev @*/
PCFieldSplitGetDiagUseAmat(PC pc,PetscBool * flg)2539d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg)
2540d71ae5a4SJacob Faibussowitsch {
2541c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2542c84da90fSDmitry Karpeev PetscBool isfs;
2543c84da90fSDmitry Karpeev
2544c84da90fSDmitry Karpeev PetscFunctionBegin;
2545c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25464f572ea9SToby Isaac PetscAssertPointer(flg, 2);
25479566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
254828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2549c84da90fSDmitry Karpeev *flg = jac->diag_use_amat;
25503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2551c84da90fSDmitry Karpeev }
2552c84da90fSDmitry Karpeev
2553c84da90fSDmitry Karpeev /*@
2554f1580f4eSBarry Smith PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2555c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2556c84da90fSDmitry Karpeev
2557c3339decSBarry Smith Logically Collective
2558c84da90fSDmitry Karpeev
2559c84da90fSDmitry Karpeev Input Parameters:
2560c84da90fSDmitry Karpeev + pc - the preconditioner object
2561c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2562c84da90fSDmitry Karpeev
256320f4b53cSBarry Smith Options Database Key:
2564147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks
2565c84da90fSDmitry Karpeev
2566c84da90fSDmitry Karpeev Level: intermediate
2567c84da90fSDmitry Karpeev
256860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT`
2569c84da90fSDmitry Karpeev @*/
PCFieldSplitSetOffDiagUseAmat(PC pc,PetscBool flg)2570d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg)
2571d71ae5a4SJacob Faibussowitsch {
2572c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2573c84da90fSDmitry Karpeev PetscBool isfs;
2574c84da90fSDmitry Karpeev
2575c84da90fSDmitry Karpeev PetscFunctionBegin;
2576c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25779566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
257828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2579c84da90fSDmitry Karpeev jac->offdiag_use_amat = flg;
25803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2581c84da90fSDmitry Karpeev }
2582c84da90fSDmitry Karpeev
2583c84da90fSDmitry Karpeev /*@
2584f1580f4eSBarry Smith PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2585c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2586c84da90fSDmitry Karpeev
2587c3339decSBarry Smith Logically Collective
2588c84da90fSDmitry Karpeev
258920f4b53cSBarry Smith Input Parameter:
2590c84da90fSDmitry Karpeev . pc - the preconditioner object
2591c84da90fSDmitry Karpeev
259220f4b53cSBarry Smith Output Parameter:
2593c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2594c84da90fSDmitry Karpeev
2595c84da90fSDmitry Karpeev Level: intermediate
2596c84da90fSDmitry Karpeev
259760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT`
2598c84da90fSDmitry Karpeev @*/
PCFieldSplitGetOffDiagUseAmat(PC pc,PetscBool * flg)2599d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg)
2600d71ae5a4SJacob Faibussowitsch {
2601c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2602c84da90fSDmitry Karpeev PetscBool isfs;
2603c84da90fSDmitry Karpeev
2604c84da90fSDmitry Karpeev PetscFunctionBegin;
2605c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26064f572ea9SToby Isaac PetscAssertPointer(flg, 2);
26079566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
260828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2609c84da90fSDmitry Karpeev *flg = jac->offdiag_use_amat;
26103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2611c84da90fSDmitry Karpeev }
2612c84da90fSDmitry Karpeev
2613cc4c1da9SBarry Smith /*@
2614f1580f4eSBarry Smith PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT`
2615704ba839SBarry Smith
2616c3339decSBarry Smith Logically Collective
2617704ba839SBarry Smith
2618704ba839SBarry Smith Input Parameters:
2619704ba839SBarry Smith + pc - the preconditioner context
262060f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used
2621f1580f4eSBarry Smith - is - the index set that defines the elements in this split
2622704ba839SBarry Smith
262360f59c3bSBarry Smith Level: intermediate
262460f59c3bSBarry Smith
2625a6ffb8dbSJed Brown Notes:
262680670ca5SBarry Smith Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST`
2627a6ffb8dbSJed Brown
2628db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options
2629db4c96c1SJed Brown for this split will be available under the prefix -fieldsplit_SPLITNAME_.
2630d32f9abdSBarry Smith
263180670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()`
2632704ba839SBarry Smith @*/
PCFieldSplitSetIS(PC pc,const char splitname[],IS is)2633d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is)
2634d71ae5a4SJacob Faibussowitsch {
2635704ba839SBarry Smith PetscFunctionBegin;
26360700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26374f572ea9SToby Isaac if (splitname) PetscAssertPointer(splitname, 2);
2638db4c96c1SJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 3);
2639cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is));
26403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2641704ba839SBarry Smith }
2642704ba839SBarry Smith
2643cc4c1da9SBarry Smith /*@
2644f1580f4eSBarry Smith PCFieldSplitGetIS - Retrieves the elements for a split as an `IS`
264557a9adfeSMatthew G Knepley
2646c3339decSBarry Smith Logically Collective
264757a9adfeSMatthew G Knepley
264857a9adfeSMatthew G Knepley Input Parameters:
264957a9adfeSMatthew G Knepley + pc - the preconditioner context
265057a9adfeSMatthew G Knepley - splitname - name of this split
265157a9adfeSMatthew G Knepley
265257a9adfeSMatthew G Knepley Output Parameter:
2653feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found
265457a9adfeSMatthew G Knepley
265557a9adfeSMatthew G Knepley Level: intermediate
265657a9adfeSMatthew G Knepley
265780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()`
265857a9adfeSMatthew G Knepley @*/
PCFieldSplitGetIS(PC pc,const char splitname[],IS * is)2659d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is)
2660d71ae5a4SJacob Faibussowitsch {
266157a9adfeSMatthew G Knepley PetscFunctionBegin;
266257a9adfeSMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26634f572ea9SToby Isaac PetscAssertPointer(splitname, 2);
26644f572ea9SToby Isaac PetscAssertPointer(is, 3);
266557a9adfeSMatthew G Knepley {
266657a9adfeSMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
266757a9adfeSMatthew G Knepley PC_FieldSplitLink ilink = jac->head;
266857a9adfeSMatthew G Knepley PetscBool found;
266957a9adfeSMatthew G Knepley
26700298fd71SBarry Smith *is = NULL;
267157a9adfeSMatthew G Knepley while (ilink) {
26729566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(ilink->splitname, splitname, &found));
267357a9adfeSMatthew G Knepley if (found) {
267457a9adfeSMatthew G Knepley *is = ilink->is;
267557a9adfeSMatthew G Knepley break;
267657a9adfeSMatthew G Knepley }
267757a9adfeSMatthew G Knepley ilink = ilink->next;
267857a9adfeSMatthew G Knepley }
267957a9adfeSMatthew G Knepley }
26803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
268157a9adfeSMatthew G Knepley }
268257a9adfeSMatthew G Knepley
2683cc4c1da9SBarry Smith /*@
2684f1580f4eSBarry Smith PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS`
2685998f007dSPierre Jolivet
2686c3339decSBarry Smith Logically Collective
2687998f007dSPierre Jolivet
2688998f007dSPierre Jolivet Input Parameters:
2689998f007dSPierre Jolivet + pc - the preconditioner context
2690998f007dSPierre Jolivet - index - index of this split
2691998f007dSPierre Jolivet
2692998f007dSPierre Jolivet Output Parameter:
2693feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split
2694998f007dSPierre Jolivet
2695998f007dSPierre Jolivet Level: intermediate
2696998f007dSPierre Jolivet
269780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`,
269880670ca5SBarry Smith
2699998f007dSPierre Jolivet @*/
PCFieldSplitGetISByIndex(PC pc,PetscInt index,IS * is)2700d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is)
2701d71ae5a4SJacob Faibussowitsch {
2702998f007dSPierre Jolivet PetscFunctionBegin;
270363a3b9bcSJacob Faibussowitsch PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index);
2704998f007dSPierre Jolivet PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27054f572ea9SToby Isaac PetscAssertPointer(is, 3);
2706998f007dSPierre Jolivet {
2707998f007dSPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2708998f007dSPierre Jolivet PC_FieldSplitLink ilink = jac->head;
2709998f007dSPierre Jolivet PetscInt i = 0;
271063a3b9bcSJacob Faibussowitsch PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits);
2711998f007dSPierre Jolivet
2712998f007dSPierre Jolivet while (i < index) {
2713998f007dSPierre Jolivet ilink = ilink->next;
2714998f007dSPierre Jolivet ++i;
2715998f007dSPierre Jolivet }
27169566063dSJacob Faibussowitsch PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is));
2717998f007dSPierre Jolivet }
27183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2719998f007dSPierre Jolivet }
2720998f007dSPierre Jolivet
272151f519a2SBarry Smith /*@
272251f519a2SBarry Smith PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
272380670ca5SBarry Smith fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used.
272451f519a2SBarry Smith
2725c3339decSBarry Smith Logically Collective
272651f519a2SBarry Smith
272751f519a2SBarry Smith Input Parameters:
272851f519a2SBarry Smith + pc - the preconditioner context
272951f519a2SBarry Smith - bs - the block size
273051f519a2SBarry Smith
273151f519a2SBarry Smith Level: intermediate
273251f519a2SBarry Smith
273380670ca5SBarry Smith Note:
273480670ca5SBarry Smith If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields.
273580670ca5SBarry Smith
273660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
273751f519a2SBarry Smith @*/
PCFieldSplitSetBlockSize(PC pc,PetscInt bs)2738d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs)
2739d71ae5a4SJacob Faibussowitsch {
274051f519a2SBarry Smith PetscFunctionBegin;
27410700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2742c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, bs, 2);
2743cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs));
27443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
274551f519a2SBarry Smith }
274651f519a2SBarry Smith
27470971522cSBarry Smith /*@C
2748f1580f4eSBarry Smith PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits
27490971522cSBarry Smith
2750c3339decSBarry Smith Collective
27510971522cSBarry Smith
27520971522cSBarry Smith Input Parameter:
27530971522cSBarry Smith . pc - the preconditioner context
27540971522cSBarry Smith
27550971522cSBarry Smith Output Parameters:
275613e0d083SBarry Smith + n - the number of splits
2757f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2758196cc216SBarry Smith
27590971522cSBarry Smith Level: advanced
27600971522cSBarry Smith
2761f1580f4eSBarry Smith Notes:
2762f1580f4eSBarry Smith After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2763f1580f4eSBarry Smith (not the `KSP`, just the array that contains them).
2764f1580f4eSBarry Smith
2765f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`.
2766f1580f4eSBarry Smith
2767f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the
2768f1580f4eSBarry Smith Schur complement and the `KSP` object used to iterate over the Schur complement.
2769f1580f4eSBarry Smith To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`.
2770f1580f4eSBarry Smith
2771f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the
2772f1580f4eSBarry Smith inner linear system defined by the matrix H in each loop.
2773f1580f4eSBarry Smith
2774feaf08eaSBarry Smith Fortran Note:
2775e41f517fSBarry Smith Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed
2776f1580f4eSBarry Smith
2777feefa0e1SJacob Faibussowitsch Developer Notes:
2778f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2779f1580f4eSBarry Smith
278060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()`
27810971522cSBarry Smith @*/
PCFieldSplitGetSubKSP(PC pc,PetscInt * n,KSP * subksp[])2782d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2783d71ae5a4SJacob Faibussowitsch {
27840971522cSBarry Smith PetscFunctionBegin;
27850700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27864f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2);
2787cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
27883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
27890971522cSBarry Smith }
27900971522cSBarry Smith
2791285fb4e2SStefano Zampini /*@C
2792f1580f4eSBarry Smith PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT`
2793285fb4e2SStefano Zampini
279460f59c3bSBarry Smith Collective
2795285fb4e2SStefano Zampini
2796285fb4e2SStefano Zampini Input Parameter:
2797285fb4e2SStefano Zampini . pc - the preconditioner context
2798285fb4e2SStefano Zampini
2799285fb4e2SStefano Zampini Output Parameters:
2800285fb4e2SStefano Zampini + n - the number of splits
2801f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2802285fb4e2SStefano Zampini
2803285fb4e2SStefano Zampini Level: advanced
2804285fb4e2SStefano Zampini
2805f1580f4eSBarry Smith Notes:
2806f1580f4eSBarry Smith After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2807f1580f4eSBarry Smith (not the `KSP` just the array that contains them).
2808f1580f4eSBarry Smith
2809f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`.
2810f1580f4eSBarry Smith
2811f1580f4eSBarry Smith If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order)
2812f1580f4eSBarry Smith + 1 - the `KSP` used for the (1,1) block
2813f1580f4eSBarry Smith . 2 - the `KSP` used for the Schur complement (not the one used for the interior Schur solver)
2814f1580f4eSBarry Smith - 3 - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block).
2815f1580f4eSBarry Smith
2816f1580f4eSBarry Smith It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`.
2817f1580f4eSBarry Smith
2818feaf08eaSBarry Smith Fortran Note:
2819e41f517fSBarry Smith Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed
2820f1580f4eSBarry Smith
2821f1580f4eSBarry Smith Developer Notes:
2822f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2823f1580f4eSBarry Smith
2824f1580f4eSBarry Smith Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged?
2825f1580f4eSBarry Smith
282660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()`
2827285fb4e2SStefano Zampini @*/
PCFieldSplitSchurGetSubKSP(PC pc,PetscInt * n,KSP * subksp[])2828d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2829d71ae5a4SJacob Faibussowitsch {
2830285fb4e2SStefano Zampini PetscFunctionBegin;
2831285fb4e2SStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
28324f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2);
2833cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
28343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2835285fb4e2SStefano Zampini }
2836285fb4e2SStefano Zampini
2837e69d4d44SBarry Smith /*@
2838c14e9f00SDavid Andrs PCFieldSplitSetSchurPre - Indicates from what operator the preconditioner is constructed for the Schur complement.
2839a1e3cbf9SBarry Smith The default is the A11 matrix.
2840e69d4d44SBarry Smith
2841c3339decSBarry Smith Collective
2842e69d4d44SBarry Smith
2843e69d4d44SBarry Smith Input Parameters:
2844e69d4d44SBarry Smith + pc - the preconditioner context
2845f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default),
2846f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`,
2847f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL`
284860f59c3bSBarry Smith - pre - matrix to use for preconditioning, or `NULL`
2849084e4875SJed Brown
2850f1580f4eSBarry Smith Options Database Keys:
2851d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments
2852a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator
2853e69d4d44SBarry Smith
285460f59c3bSBarry Smith Level: intermediate
285560f59c3bSBarry Smith
2856fd1303e9SJungho Lee Notes:
2857f1580f4eSBarry Smith If ptype is
2858f1580f4eSBarry Smith + a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
2859f1580f4eSBarry Smith matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix
2860f1580f4eSBarry Smith . self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
2861e7593814SPierre Jolivet The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM`
2862f1580f4eSBarry Smith . user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
2863f1580f4eSBarry Smith to this function).
2864a077d33dSBarry Smith . selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $
2865f1580f4eSBarry Smith This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
2866d59693daSPierre Jolivet lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump`
2867f1580f4eSBarry Smith - full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation
2868f1580f4eSBarry Smith computed internally by `PCFIELDSPLIT` (this is expensive)
2869f1580f4eSBarry Smith useful mostly as a test that the Schur complement approach can work for your problem
2870fd1303e9SJungho Lee
2871d59693daSPierre Jolivet When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense
2872a077d33dSBarry Smith with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and
2873d59693daSPierre Jolivet `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement.
2874fd1303e9SJungho Lee
2875a077d33dSBarry Smith Developer Note:
2876a077d33dSBarry Smith The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere.
2877feefa0e1SJacob Faibussowitsch
2878a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`,
2879a077d33dSBarry Smith `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()`
2880e69d4d44SBarry Smith @*/
PCFieldSplitSetSchurPre(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2881d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2882d71ae5a4SJacob Faibussowitsch {
2883e69d4d44SBarry Smith PetscFunctionBegin;
28840700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2885cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre));
28863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2887e69d4d44SBarry Smith }
2888686bed4dSStefano Zampini
PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2889d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2890d71ae5a4SJacob Faibussowitsch {
28919371c9d4SSatish Balay return PCFieldSplitSetSchurPre(pc, ptype, pre);
28929371c9d4SSatish Balay } /* Deprecated name */
2893e69d4d44SBarry Smith
289437a82bf0SJed Brown /*@
289537a82bf0SJed Brown PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
2896f1580f4eSBarry Smith preconditioned. See `PCFieldSplitSetSchurPre()` for details.
289737a82bf0SJed Brown
2898c3339decSBarry Smith Logically Collective
289937a82bf0SJed Brown
2900f899ff85SJose E. Roman Input Parameter:
290137a82bf0SJed Brown . pc - the preconditioner context
290237a82bf0SJed Brown
290337a82bf0SJed Brown Output Parameters:
2904d59693daSPierre Jolivet + 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`
2905d59693daSPierre Jolivet - pre - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL`
290637a82bf0SJed Brown
290737a82bf0SJed Brown Level: intermediate
290837a82bf0SJed Brown
2909d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC`
291037a82bf0SJed Brown @*/
PCFieldSplitGetSchurPre(PC pc,PCFieldSplitSchurPreType * ptype,Mat * pre)2911d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2912d71ae5a4SJacob Faibussowitsch {
291337a82bf0SJed Brown PetscFunctionBegin;
291437a82bf0SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2915cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre));
29163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2917e69d4d44SBarry Smith }
2918e69d4d44SBarry Smith
291945e7fc46SDmitry Karpeev /*@
2920f1580f4eSBarry Smith PCFieldSplitSchurGetS - extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately
292145e7fc46SDmitry Karpeev
292220f4b53cSBarry Smith Not Collective
292345e7fc46SDmitry Karpeev
292445e7fc46SDmitry Karpeev Input Parameter:
292545e7fc46SDmitry Karpeev . pc - the preconditioner context
292645e7fc46SDmitry Karpeev
292745e7fc46SDmitry Karpeev Output Parameter:
2928470b340bSDmitry Karpeev . S - the Schur complement matrix
292945e7fc46SDmitry Karpeev
293060f59c3bSBarry Smith Level: advanced
293160f59c3bSBarry Smith
2932f1580f4eSBarry Smith Note:
2933f1580f4eSBarry Smith This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`.
293445e7fc46SDmitry Karpeev
293560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`,
2936f1580f4eSBarry Smith `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()`
293745e7fc46SDmitry Karpeev @*/
PCFieldSplitSchurGetS(PC pc,Mat * S)2938d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S)
2939d71ae5a4SJacob Faibussowitsch {
294045e7fc46SDmitry Karpeev const char *t;
294145e7fc46SDmitry Karpeev PetscBool isfs;
294245e7fc46SDmitry Karpeev PC_FieldSplit *jac;
294345e7fc46SDmitry Karpeev
294445e7fc46SDmitry Karpeev PetscFunctionBegin;
294545e7fc46SDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29469566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29479566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
294828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
294945e7fc46SDmitry Karpeev jac = (PC_FieldSplit *)pc->data;
295063a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2951470b340bSDmitry Karpeev if (S) *S = jac->schur;
29523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
295345e7fc46SDmitry Karpeev }
295445e7fc46SDmitry Karpeev
2955470b340bSDmitry Karpeev /*@
2956f1580f4eSBarry Smith PCFieldSplitSchurRestoreS - returns the `MATSCHURCOMPLEMENT` matrix used by this `PC`
2957470b340bSDmitry Karpeev
295820f4b53cSBarry Smith Not Collective
2959470b340bSDmitry Karpeev
2960470b340bSDmitry Karpeev Input Parameters:
2961470b340bSDmitry Karpeev + pc - the preconditioner context
2962a2b725a8SWilliam Gropp - S - the Schur complement matrix
2963470b340bSDmitry Karpeev
2964470b340bSDmitry Karpeev Level: advanced
2965470b340bSDmitry Karpeev
296660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()`
2967470b340bSDmitry Karpeev @*/
PCFieldSplitSchurRestoreS(PC pc,Mat * S)2968d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S)
2969d71ae5a4SJacob Faibussowitsch {
2970470b340bSDmitry Karpeev const char *t;
2971470b340bSDmitry Karpeev PetscBool isfs;
2972470b340bSDmitry Karpeev PC_FieldSplit *jac;
2973470b340bSDmitry Karpeev
2974470b340bSDmitry Karpeev PetscFunctionBegin;
2975470b340bSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29769566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29779566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
297828b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2979470b340bSDmitry Karpeev jac = (PC_FieldSplit *)pc->data;
298063a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
29817827d75bSBarry Smith PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten");
29823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2983470b340bSDmitry Karpeev }
2984470b340bSDmitry Karpeev
PCFieldSplitSetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2985d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2986d71ae5a4SJacob Faibussowitsch {
2987e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2988e69d4d44SBarry Smith
2989e69d4d44SBarry Smith PetscFunctionBegin;
2990084e4875SJed Brown jac->schurpre = ptype;
2991a7476a74SDmitry Karpeev if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
29929566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user));
2993084e4875SJed Brown jac->schur_user = pre;
29949566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
2995084e4875SJed Brown }
29963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
2997e69d4d44SBarry Smith }
2998e69d4d44SBarry Smith
PCFieldSplitGetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType * ptype,Mat * pre)2999d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
3000d71ae5a4SJacob Faibussowitsch {
300137a82bf0SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
300237a82bf0SJed Brown
300337a82bf0SJed Brown PetscFunctionBegin;
30046056e507SPierre Jolivet if (ptype) *ptype = jac->schurpre;
30056056e507SPierre Jolivet if (pre) *pre = jac->schur_user;
30063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
300737a82bf0SJed Brown }
300837a82bf0SJed Brown
3009ab1df9f5SJed Brown /*@
30101d27aa22SBarry Smith PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note`
3011ab1df9f5SJed Brown
3012c3339decSBarry Smith Collective
3013ab1df9f5SJed Brown
3014ab1df9f5SJed Brown Input Parameters:
3015ab1df9f5SJed Brown + pc - the preconditioner context
3016f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default
3017ab1df9f5SJed Brown
3018f1580f4eSBarry Smith Options Database Key:
3019d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full`
3020ab1df9f5SJed Brown
3021ab1df9f5SJed Brown Level: intermediate
3022ab1df9f5SJed Brown
3023ab1df9f5SJed Brown Notes:
3024366f9a6aSPierre Jolivet The `full` factorization is
3025ab1df9f5SJed Brown
3026a077d33dSBarry Smith ```{math}
3027a077d33dSBarry Smith \left(\begin{array}{cc} A & B \\
3028a077d33dSBarry Smith C & E \\
3029a077d33dSBarry Smith \end{array}\right) =
3030366f9a6aSPierre Jolivet \left(\begin{array}{cc} I & 0 \\
3031366f9a6aSPierre Jolivet C A^{-1} & I \\
3032a077d33dSBarry Smith \end{array}\right)
3033a077d33dSBarry Smith \left(\begin{array}{cc} A & 0 \\
3034a077d33dSBarry Smith 0 & S \\
3035a077d33dSBarry Smith \end{array}\right)
3036a077d33dSBarry Smith \left(\begin{array}{cc} I & A^{-1}B \\
3037a077d33dSBarry Smith 0 & I \\
3038366f9a6aSPierre Jolivet \end{array}\right) = L D U,
3039a077d33dSBarry Smith ```
3040a077d33dSBarry Smith
3041366f9a6aSPierre Jolivet where $ S = E - C A^{-1} B $. In practice, the full factorization is applied via block triangular solves with the grouping $L(DU)$. `upper` uses $DU$, `lower` uses $LD$,
3042366f9a6aSPierre Jolivet and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations,
3043a077d33dSBarry Smith thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`.
3044a077d33dSBarry Smith
3045a077d33dSBarry Smith If $A$ and $S$ are solved exactly
3046366f9a6aSPierre Jolivet + 1 - `full` factorization is a direct solver.
3047366f9a6aSPierre Jolivet . 2 - 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.
3048366f9a6aSPierre Jolivet - 3 - 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.
3049ab1df9f5SJed Brown
3050f1580f4eSBarry Smith If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner
30510ffb0e17SBarry Smith application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice.
30520ffb0e17SBarry Smith
3053366f9a6aSPierre Jolivet For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`.
30540ffb0e17SBarry Smith
3055366f9a6aSPierre Jolivet A flexible method like `KSPFGMRES` or `KSPGCR`, [](sec_flexibleksp), 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$).
3056ab1df9f5SJed Brown
30571d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`,
3058a077d33dSBarry Smith [](sec_flexibleksp), `PCFieldSplitSetSchurPre()`
3059ab1df9f5SJed Brown @*/
PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype)3060d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype)
3061d71ae5a4SJacob Faibussowitsch {
3062ab1df9f5SJed Brown PetscFunctionBegin;
3063ab1df9f5SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3064cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype));
30653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3066ab1df9f5SJed Brown }
3067ab1df9f5SJed Brown
PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype)3068d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype)
3069d71ae5a4SJacob Faibussowitsch {
3070ab1df9f5SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3071ab1df9f5SJed Brown
3072ab1df9f5SJed Brown PetscFunctionBegin;
3073ab1df9f5SJed Brown jac->schurfactorization = ftype;
30743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3075ab1df9f5SJed Brown }
3076ab1df9f5SJed Brown
3077c096484dSStefano Zampini /*@
3078f1580f4eSBarry Smith PCFieldSplitSetSchurScale - Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`.
3079c096484dSStefano Zampini
3080c3339decSBarry Smith Collective
3081c096484dSStefano Zampini
3082c096484dSStefano Zampini Input Parameters:
3083c096484dSStefano Zampini + pc - the preconditioner context
3084c096484dSStefano Zampini - scale - scaling factor for the Schur complement
3085c096484dSStefano Zampini
3086f1580f4eSBarry Smith Options Database Key:
30871d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0
3088c096484dSStefano Zampini
3089c096484dSStefano Zampini Level: intermediate
3090c096484dSStefano Zampini
309142747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()`
3092c096484dSStefano Zampini @*/
PCFieldSplitSetSchurScale(PC pc,PetscScalar scale)3093d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale)
3094d71ae5a4SJacob Faibussowitsch {
3095c096484dSStefano Zampini PetscFunctionBegin;
3096c096484dSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3097c096484dSStefano Zampini PetscValidLogicalCollectiveScalar(pc, scale, 2);
3098cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale));
30993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3100c096484dSStefano Zampini }
3101c096484dSStefano Zampini
PCFieldSplitSetSchurScale_FieldSplit(PC pc,PetscScalar scale)3102d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale)
3103d71ae5a4SJacob Faibussowitsch {
3104c096484dSStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3105c096484dSStefano Zampini
3106c096484dSStefano Zampini PetscFunctionBegin;
3107c096484dSStefano Zampini jac->schurscale = scale;
31083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3109c096484dSStefano Zampini }
3110c096484dSStefano Zampini
311130ad9308SMatthew Knepley /*@C
31128c03b21aSDmitry Karpeev PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
311330ad9308SMatthew Knepley
3114c3339decSBarry Smith Collective
311530ad9308SMatthew Knepley
311630ad9308SMatthew Knepley Input Parameter:
311730ad9308SMatthew Knepley . pc - the preconditioner context
311830ad9308SMatthew Knepley
311930ad9308SMatthew Knepley Output Parameters:
3120a04f6461SBarry Smith + A00 - the (0,0) block
3121a04f6461SBarry Smith . A01 - the (0,1) block
3122a04f6461SBarry Smith . A10 - the (1,0) block
3123a04f6461SBarry Smith - A11 - the (1,1) block
312430ad9308SMatthew Knepley
312530ad9308SMatthew Knepley Level: advanced
312630ad9308SMatthew Knepley
31275d83a8b1SBarry Smith Note:
31285d83a8b1SBarry Smith Use `NULL` for any unneeded output arguments
31295d83a8b1SBarry Smith
313060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()`
313130ad9308SMatthew Knepley @*/
PCFieldSplitGetSchurBlocks(PC pc,Mat * A00,Mat * A01,Mat * A10,Mat * A11)3132d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11)
3133d71ae5a4SJacob Faibussowitsch {
313430ad9308SMatthew Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
313530ad9308SMatthew Knepley
313630ad9308SMatthew Knepley PetscFunctionBegin;
31370700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
313808401ef6SPierre Jolivet PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
3139a04f6461SBarry Smith if (A00) *A00 = jac->pmat[0];
3140a04f6461SBarry Smith if (A01) *A01 = jac->B;
3141a04f6461SBarry Smith if (A10) *A10 = jac->C;
3142a04f6461SBarry Smith if (A11) *A11 = jac->pmat[1];
31433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
314430ad9308SMatthew Knepley }
314530ad9308SMatthew Knepley
3146b09e027eSCarola Kruse /*@
31471d27aa22SBarry Smith PCFieldSplitSetGKBTol - Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3148b09e027eSCarola Kruse
3149c3339decSBarry Smith Collective
3150e071a0a4SCarola Kruse
3151b09e027eSCarola Kruse Input Parameters:
3152b09e027eSCarola Kruse + pc - the preconditioner context
3153b09e027eSCarola Kruse - tolerance - the solver tolerance
3154b09e027eSCarola Kruse
3155f1580f4eSBarry Smith Options Database Key:
31561d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5
3157b09e027eSCarola Kruse
3158b09e027eSCarola Kruse Level: intermediate
3159b09e027eSCarola Kruse
3160f1580f4eSBarry Smith Note:
31611d27aa22SBarry Smith The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion.
3162f1580f4eSBarry Smith It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than
31631d27aa22SBarry Smith this estimate, the stopping criterion is satisfactory in practical cases.
3164f1580f4eSBarry Smith
316560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()`
3166b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBTol(PC pc,PetscReal tolerance)3167d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance)
3168d71ae5a4SJacob Faibussowitsch {
3169b09e027eSCarola Kruse PetscFunctionBegin;
3170b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3171de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, tolerance, 2);
3172cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance));
31733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3174b09e027eSCarola Kruse }
3175b09e027eSCarola Kruse
PCFieldSplitSetGKBTol_FieldSplit(PC pc,PetscReal tolerance)3176d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance)
3177d71ae5a4SJacob Faibussowitsch {
3178b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3179b09e027eSCarola Kruse
3180b09e027eSCarola Kruse PetscFunctionBegin;
3181b09e027eSCarola Kruse jac->gkbtol = tolerance;
31823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3183b09e027eSCarola Kruse }
3184b09e027eSCarola Kruse
3185b09e027eSCarola Kruse /*@
318680670ca5SBarry Smith PCFieldSplitSetGKBMaxit - Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3187b09e027eSCarola Kruse
3188c3339decSBarry Smith Collective
3189b09e027eSCarola Kruse
3190b09e027eSCarola Kruse Input Parameters:
3191b09e027eSCarola Kruse + pc - the preconditioner context
3192b09e027eSCarola Kruse - maxit - the maximum number of iterations
3193b09e027eSCarola Kruse
3194f1580f4eSBarry Smith Options Database Key:
31951d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100
3196b09e027eSCarola Kruse
3197b09e027eSCarola Kruse Level: intermediate
3198b09e027eSCarola Kruse
319960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()`
3200b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBMaxit(PC pc,PetscInt maxit)3201d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit)
3202d71ae5a4SJacob Faibussowitsch {
3203b09e027eSCarola Kruse PetscFunctionBegin;
3204b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3205de482cd7SCarola Kruse PetscValidLogicalCollectiveInt(pc, maxit, 2);
3206cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit));
32073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3208b09e027eSCarola Kruse }
3209b09e027eSCarola Kruse
PCFieldSplitSetGKBMaxit_FieldSplit(PC pc,PetscInt maxit)3210d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit)
3211d71ae5a4SJacob Faibussowitsch {
3212b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3213b09e027eSCarola Kruse
3214b09e027eSCarola Kruse PetscFunctionBegin;
3215b09e027eSCarola Kruse jac->gkbmaxit = maxit;
32163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3217b09e027eSCarola Kruse }
3218b09e027eSCarola Kruse
3219b09e027eSCarola Kruse /*@
32201d27aa22SBarry Smith PCFieldSplitSetGKBDelay - Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT`
3221e071a0a4SCarola Kruse preconditioner.
3222b09e027eSCarola Kruse
3223c3339decSBarry Smith Collective
3224b09e027eSCarola Kruse
3225b09e027eSCarola Kruse Input Parameters:
3226b09e027eSCarola Kruse + pc - the preconditioner context
3227b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate
3228b09e027eSCarola Kruse
3229f1580f4eSBarry Smith Options Database Key:
32301d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5
3231b09e027eSCarola Kruse
3232b09e027eSCarola Kruse Level: intermediate
3233b09e027eSCarola Kruse
32341d27aa22SBarry Smith Notes:
32351d27aa22SBarry Smith 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 $
32361d27aa22SBarry Smith is expressed as a truncated sum. The error at iteration k can only be measured at iteration (k + `delay`), and thus the algorithm needs
32371d27aa22SBarry Smith at least (`delay` + 1) iterations to stop.
3238f1580f4eSBarry Smith
32391d27aa22SBarry Smith For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013`
3240f1580f4eSBarry Smith
324160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3242b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBDelay(PC pc,PetscInt delay)3243d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay)
3244d71ae5a4SJacob Faibussowitsch {
3245b09e027eSCarola Kruse PetscFunctionBegin;
3246b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3247b09e027eSCarola Kruse PetscValidLogicalCollectiveInt(pc, delay, 2);
3248cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay));
32493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3250b09e027eSCarola Kruse }
3251b09e027eSCarola Kruse
PCFieldSplitSetGKBDelay_FieldSplit(PC pc,PetscInt delay)3252d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay)
3253d71ae5a4SJacob Faibussowitsch {
3254b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3255b09e027eSCarola Kruse
3256b09e027eSCarola Kruse PetscFunctionBegin;
3257b09e027eSCarola Kruse jac->gkbdelay = delay;
32583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3259b09e027eSCarola Kruse }
3260b09e027eSCarola Kruse
3261b09e027eSCarola Kruse /*@
32621d27aa22SBarry Smith PCFieldSplitSetGKBNu - Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the
32631d27aa22SBarry Smith Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3264b09e027eSCarola Kruse
3265c3339decSBarry Smith Collective
3266f1580f4eSBarry Smith
3267f1580f4eSBarry Smith Input Parameters:
3268f1580f4eSBarry Smith + pc - the preconditioner context
3269f1580f4eSBarry Smith - nu - the shift parameter
3270f1580f4eSBarry Smith
327120f4b53cSBarry Smith Options Database Key:
32721d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1
3273f1580f4eSBarry Smith
3274f1580f4eSBarry Smith Level: intermediate
3275b09e027eSCarola Kruse
3276b09e027eSCarola Kruse Notes:
32771d27aa22SBarry Smith 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 large. However,
32781d27aa22SBarry Smith if `nu` is chosen too large, 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
3279b09e027eSCarola Kruse necessary to find a good balance in between the convergence of the inner and outer loop.
3280b09e027eSCarola Kruse
32811d27aa22SBarry Smith For `nu` = 0, no shift is done. In this case A00 has to be positive definite. The matrix N in {cite}`arioli2013` is then chosen as identity.
3282b09e027eSCarola Kruse
328360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3284b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBNu(PC pc,PetscReal nu)3285d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu)
3286d71ae5a4SJacob Faibussowitsch {
3287b09e027eSCarola Kruse PetscFunctionBegin;
3288b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3289de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, nu, 2);
3290cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu));
32913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3292b09e027eSCarola Kruse }
3293b09e027eSCarola Kruse
PCFieldSplitSetGKBNu_FieldSplit(PC pc,PetscReal nu)3294d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu)
3295d71ae5a4SJacob Faibussowitsch {
3296b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3297b09e027eSCarola Kruse
3298b09e027eSCarola Kruse PetscFunctionBegin;
3299b09e027eSCarola Kruse jac->gkbnu = nu;
33003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3301b09e027eSCarola Kruse }
3302b09e027eSCarola Kruse
PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)3303d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type)
3304d71ae5a4SJacob Faibussowitsch {
330579416396SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
330679416396SBarry Smith
330779416396SBarry Smith PetscFunctionBegin;
330879416396SBarry Smith jac->type = type;
33092e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
33102e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
33112e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
33122e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
33132e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
33142e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
33152e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
33162e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
33172e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
3318e071a0a4SCarola Kruse
33193b224e63SBarry Smith if (type == PC_COMPOSITE_SCHUR) {
33203b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit_Schur;
33217b665727SPierre Jolivet pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur;
3322f5b94327SPierre Jolivet pc->ops->matapply = PCMatApply_FieldSplit_Schur;
33233b224e63SBarry Smith pc->ops->view = PCView_FieldSplit_Schur;
332473716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_Schur;
33252fa5cd67SKarl Rupp
33269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur));
33279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit));
33289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit));
33299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit));
33309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit));
3331a51937d4SCarola Kruse } else if (type == PC_COMPOSITE_GKB) {
3332a51937d4SCarola Kruse pc->ops->apply = PCApply_FieldSplit_GKB;
33337ff38633SStefano Zampini pc->ops->applytranspose = NULL;
3334d484b384SBoris Martin pc->ops->matapply = NULL;
3335a51937d4SCarola Kruse pc->ops->view = PCView_FieldSplit_GKB;
333673716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_GKB;
3337e69d4d44SBarry Smith
33389566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit));
33409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit));
33419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit));
33429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit));
33433b224e63SBarry Smith } else {
33443b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit;
33457ff38633SStefano Zampini pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
3346d484b384SBoris Martin pc->ops->matapply = PCMatApply_FieldSplit;
33473b224e63SBarry Smith pc->ops->view = PCView_FieldSplit;
334873716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit;
33492fa5cd67SKarl Rupp
33509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33513b224e63SBarry Smith }
33523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
335379416396SBarry Smith }
335479416396SBarry Smith
PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)3355d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs)
3356d71ae5a4SJacob Faibussowitsch {
335751f519a2SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
335851f519a2SBarry Smith
335951f519a2SBarry Smith PetscFunctionBegin;
336063a3b9bcSJacob Faibussowitsch PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
33612472a847SBarry Smith 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);
336251f519a2SBarry Smith jac->bs = bs;
33633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
336451f519a2SBarry Smith }
336551f519a2SBarry Smith
PCSetCoordinates_FieldSplit(PC pc,PetscInt dim,PetscInt nloc,PetscReal coords[])3366d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[])
3367d71ae5a4SJacob Faibussowitsch {
33685ddf11f8SNicolas Barnafi PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
33695ddf11f8SNicolas Barnafi PC_FieldSplitLink ilink_current = jac->head;
33705ddf11f8SNicolas Barnafi IS is_owned;
33715ddf11f8SNicolas Barnafi
33725ddf11f8SNicolas Barnafi PetscFunctionBegin;
33735ddf11f8SNicolas Barnafi jac->coordinates_set = PETSC_TRUE; // Internal flag
3374f3fa974cSJacob Faibussowitsch PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL));
33755ddf11f8SNicolas Barnafi
33765ddf11f8SNicolas Barnafi while (ilink_current) {
33775ddf11f8SNicolas Barnafi // For each IS, embed it to get local coords indces
33785ddf11f8SNicolas Barnafi IS is_coords;
33795ddf11f8SNicolas Barnafi PetscInt ndofs_block;
33805ddf11f8SNicolas Barnafi const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
33815ddf11f8SNicolas Barnafi
33825ddf11f8SNicolas Barnafi // Setting drop to true for safety. It should make no difference.
33839566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords));
33849566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(is_coords, &ndofs_block));
33859566063dSJacob Faibussowitsch PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration));
33865ddf11f8SNicolas Barnafi
33875ddf11f8SNicolas Barnafi // Allocate coordinates vector and set it directly
3388f4f49eeaSPierre Jolivet PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords));
33895ddf11f8SNicolas Barnafi for (PetscInt dof = 0; dof < ndofs_block; ++dof) {
3390ad540459SPierre Jolivet for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
33915ddf11f8SNicolas Barnafi }
33925ddf11f8SNicolas Barnafi ilink_current->dim = dim;
33935ddf11f8SNicolas Barnafi ilink_current->ndofs = ndofs_block;
33949566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration));
33959566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_coords));
33965ddf11f8SNicolas Barnafi ilink_current = ilink_current->next;
33975ddf11f8SNicolas Barnafi }
33989566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_owned));
33993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
34005ddf11f8SNicolas Barnafi }
34015ddf11f8SNicolas Barnafi
3402bc08b0f1SBarry Smith /*@
3403f1580f4eSBarry Smith PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
340479416396SBarry Smith
3405c3339decSBarry Smith Collective
340679416396SBarry Smith
3407d8d19677SJose E. Roman Input Parameters:
3408a2b725a8SWilliam Gropp + pc - the preconditioner context
3409a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`,
3410a077d33dSBarry Smith `PC_COMPOSITE_GKB`
341179416396SBarry Smith
341279416396SBarry Smith Options Database Key:
34131d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
341479416396SBarry Smith
3415feefa0e1SJacob Faibussowitsch Level: intermediate
341679416396SBarry Smith
341760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3418a077d33dSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()`
341979416396SBarry Smith @*/
PCFieldSplitSetType(PC pc,PCCompositeType type)3420d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type)
3421d71ae5a4SJacob Faibussowitsch {
342279416396SBarry Smith PetscFunctionBegin;
34230700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3424cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type));
34253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
342679416396SBarry Smith }
342779416396SBarry Smith
3428b02e2d75SMatthew G Knepley /*@
3429f1580f4eSBarry Smith PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
3430b02e2d75SMatthew G Knepley
3431b02e2d75SMatthew G Knepley Not collective
3432b02e2d75SMatthew G Knepley
3433b02e2d75SMatthew G Knepley Input Parameter:
3434b02e2d75SMatthew G Knepley . pc - the preconditioner context
3435b02e2d75SMatthew G Knepley
3436b02e2d75SMatthew G Knepley Output Parameter:
3437f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3438b02e2d75SMatthew G Knepley
3439feefa0e1SJacob Faibussowitsch Level: intermediate
3440b02e2d75SMatthew G Knepley
344160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3442f1580f4eSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3443b02e2d75SMatthew G Knepley @*/
PCFieldSplitGetType(PC pc,PCCompositeType * type)3444d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
3445d71ae5a4SJacob Faibussowitsch {
3446b02e2d75SMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3447b02e2d75SMatthew G Knepley
3448b02e2d75SMatthew G Knepley PetscFunctionBegin;
3449b02e2d75SMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34504f572ea9SToby Isaac PetscAssertPointer(type, 2);
3451b02e2d75SMatthew G Knepley *type = jac->type;
34523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
3453b02e2d75SMatthew G Knepley }
3454b02e2d75SMatthew G Knepley
34554ab8060aSDmitry Karpeev /*@
3456f1580f4eSBarry Smith PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34574ab8060aSDmitry Karpeev
3458c3339decSBarry Smith Logically Collective
34594ab8060aSDmitry Karpeev
34604ab8060aSDmitry Karpeev Input Parameters:
34614ab8060aSDmitry Karpeev + pc - the preconditioner context
3462f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM`
34634ab8060aSDmitry Karpeev
34644ab8060aSDmitry Karpeev Options Database Key:
3465f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM`
34664ab8060aSDmitry Karpeev
3467feefa0e1SJacob Faibussowitsch Level: intermediate
34684ab8060aSDmitry Karpeev
346973ff1848SBarry Smith Developer Note:
347073ff1848SBarry Smith The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database
347173ff1848SBarry Smith
3472f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
34734ab8060aSDmitry Karpeev @*/
PCFieldSplitSetDMSplits(PC pc,PetscBool flg)3474d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg)
3475d71ae5a4SJacob Faibussowitsch {
34764ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
34774ab8060aSDmitry Karpeev PetscBool isfs;
34784ab8060aSDmitry Karpeev
34794ab8060aSDmitry Karpeev PetscFunctionBegin;
34804ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34814ab8060aSDmitry Karpeev PetscValidLogicalCollectiveBool(pc, flg, 2);
34829566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
3483ad540459SPierre Jolivet if (isfs) jac->dm_splits = flg;
34843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
34854ab8060aSDmitry Karpeev }
34864ab8060aSDmitry Karpeev
34874ab8060aSDmitry Karpeev /*@
3488f1580f4eSBarry Smith PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34894ab8060aSDmitry Karpeev
34904ab8060aSDmitry Karpeev Logically Collective
34914ab8060aSDmitry Karpeev
34924ab8060aSDmitry Karpeev Input Parameter:
34934ab8060aSDmitry Karpeev . pc - the preconditioner context
34944ab8060aSDmitry Karpeev
34954ab8060aSDmitry Karpeev Output Parameter:
3496f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM`
34974ab8060aSDmitry Karpeev
3498feefa0e1SJacob Faibussowitsch Level: intermediate
34994ab8060aSDmitry Karpeev
350073ff1848SBarry Smith Developer Note:
350173ff1848SBarry Smith The name should be `PCFieldSplitGetUseDMSplits()`
350273ff1848SBarry Smith
3503f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
35044ab8060aSDmitry Karpeev @*/
PCFieldSplitGetDMSplits(PC pc,PetscBool * flg)3505d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg)
3506d71ae5a4SJacob Faibussowitsch {
35074ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35084ab8060aSDmitry Karpeev PetscBool isfs;
35094ab8060aSDmitry Karpeev
35104ab8060aSDmitry Karpeev PetscFunctionBegin;
35114ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
35124f572ea9SToby Isaac PetscAssertPointer(flg, 2);
35139566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
35144ab8060aSDmitry Karpeev if (isfs) {
35154ab8060aSDmitry Karpeev if (flg) *flg = jac->dm_splits;
35164ab8060aSDmitry Karpeev }
35173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
35184ab8060aSDmitry Karpeev }
35194ab8060aSDmitry Karpeev
35207b752e3dSPatrick Sanan /*@
3521f1580f4eSBarry Smith PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35227b752e3dSPatrick Sanan
35237b752e3dSPatrick Sanan Logically Collective
35247b752e3dSPatrick Sanan
35257b752e3dSPatrick Sanan Input Parameter:
35267b752e3dSPatrick Sanan . pc - the preconditioner context
35277b752e3dSPatrick Sanan
35287b752e3dSPatrick Sanan Output Parameter:
35297b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35307b752e3dSPatrick Sanan
3531feefa0e1SJacob Faibussowitsch Level: intermediate
35327b752e3dSPatrick Sanan
353360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`
35347b752e3dSPatrick Sanan @*/
PCFieldSplitGetDetectSaddlePoint(PC pc,PetscBool * flg)3535d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg)
3536d71ae5a4SJacob Faibussowitsch {
35377b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35387b752e3dSPatrick Sanan
35397b752e3dSPatrick Sanan PetscFunctionBegin;
35407b752e3dSPatrick Sanan *flg = jac->detect;
35413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
35427b752e3dSPatrick Sanan }
35437b752e3dSPatrick Sanan
35447b752e3dSPatrick Sanan /*@
3545f1580f4eSBarry Smith PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35467b752e3dSPatrick Sanan
35477b752e3dSPatrick Sanan Logically Collective
35487b752e3dSPatrick Sanan
35497b752e3dSPatrick Sanan Input Parameter:
35507b752e3dSPatrick Sanan . pc - the preconditioner context
35517b752e3dSPatrick Sanan
35527b752e3dSPatrick Sanan Output Parameter:
35537b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35547b752e3dSPatrick Sanan
35557b752e3dSPatrick Sanan Options Database Key:
3556147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point
3557147403d9SBarry Smith
3558feefa0e1SJacob Faibussowitsch Level: intermediate
355960f59c3bSBarry Smith
3560f1580f4eSBarry Smith Note:
3561f1580f4eSBarry Smith Also sets the split type to `PC_COMPOSITE_SCHUR` (see `PCFieldSplitSetType()`) and the Schur preconditioner type to `PC_FIELDSPLIT_SCHUR_PRE_SELF` (see `PCFieldSplitSetSchurPre()`).
35627b752e3dSPatrick Sanan
356360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`
35647b752e3dSPatrick Sanan @*/
PCFieldSplitSetDetectSaddlePoint(PC pc,PetscBool flg)3565d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg)
3566d71ae5a4SJacob Faibussowitsch {
35677b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35687b752e3dSPatrick Sanan
35697b752e3dSPatrick Sanan PetscFunctionBegin;
35707b752e3dSPatrick Sanan jac->detect = flg;
35717b752e3dSPatrick Sanan if (jac->detect) {
35729566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
35739566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
35747b752e3dSPatrick Sanan }
35753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
35767b752e3dSPatrick Sanan }
35777b752e3dSPatrick Sanan
35780971522cSBarry Smith /*MC
3579a8c7a070SBarry Smith PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
35800b4b7b1cSBarry Smith collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable
35810b4b7b1cSBarry Smith represented on a grid, such as velocity, pressure, or temperature.
35820b4b7b1cSBarry Smith In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`.
35830b4b7b1cSBarry Smith See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details.
35840971522cSBarry Smith
358579416396SBarry Smith Options Database Keys:
3586de37d9f1SPatrick Sanan + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
358781540f2fSBarry Smith . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
3588de37d9f1SPatrick Sanan been supplied explicitly by `-pc_fieldsplit_%d_fields`
358981540f2fSBarry Smith . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
359080670ca5SBarry Smith when the matrix is not of `MatType` `MATNEST`
3591a51937d4SCarola Kruse . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting
3592d59693daSPierre Jolivet . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`; see `PCFieldSplitSetSchurPre()`
35931d27aa22SBarry Smith . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using `-pc_fieldsplit_type schur`;
35941d27aa22SBarry Smith see `PCFieldSplitSetSchurFactType()`
359573ff1848SBarry Smith . -pc_fieldsplit_dm_splits <true,false> (default is true) - Whether to use `DMCreateFieldDecomposition()` for splits
3596fb6809a2SPatrick Sanan - -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver
359779416396SBarry Smith
3598de37d9f1SPatrick Sanan Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` .
3599de37d9f1SPatrick Sanan The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_`
360060f59c3bSBarry Smith For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields.
360160f59c3bSBarry Smith
360222399129SNuno Nobre To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC`
360322399129SNuno Nobre options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`.
360460f59c3bSBarry Smith
360560f59c3bSBarry Smith To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()`
360660f59c3bSBarry Smith and set the options directly on the resulting `KSP` object
360760f59c3bSBarry Smith
360860f59c3bSBarry Smith Level: intermediate
36095d4c12cdSJungho Lee
3610c8a0d604SMatthew G Knepley Notes:
361180670ca5SBarry Smith Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()`
3612f1580f4eSBarry Smith to define a split by an arbitrary collection of entries.
3613d32f9abdSBarry Smith
361473ff1848SBarry Smith If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports
361580670ca5SBarry Smith `DMCreateFieldDecomposition()`, then that is used for the default. Otherwise if the matrix is not `MATNEST`, the splits are defined by entries strided by bs,
3616de37d9f1SPatrick Sanan beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`,
3617d32f9abdSBarry Smith if this is not called the block size defaults to the blocksize of the second matrix passed
3618de37d9f1SPatrick Sanan to `KSPSetOperators()`/`PCSetOperators()`.
3619d32f9abdSBarry Smith
3620de37d9f1SPatrick Sanan For the Schur complement preconditioner if
3621de37d9f1SPatrick Sanan ```{math}
3622de37d9f1SPatrick Sanan J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right]
3623de37d9f1SPatrick Sanan ```
3624e69d4d44SBarry Smith
3625de37d9f1SPatrick Sanan the preconditioner using `full` factorization is logically
3626de37d9f1SPatrick Sanan ```{math}
3627f820a28cSNuno Nobre \left[\begin{array}{cc} I & -\text{ksp}(A_{00}) A_{01} \\ 0 & I \end{array}\right] \left[\begin{array}{cc} \text{ksp}(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]
3628de37d9f1SPatrick Sanan ```
3629cee94454SNuno Nobre where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`. $S$ is the Schur complement
3630de37d9f1SPatrick Sanan ```{math}
3631223e5b4fSPatrick Sanan S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01}
3632de37d9f1SPatrick Sanan ```
36337cbeddf0SNuno Nobre 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`
36347cbeddf0SNuno Nobre was given in providing the SECOND split or 1 if not given). Accordingly, if using `PCFieldSplitGetSubKSP()`, the array of sub-`KSP` contexts will hold two `KSP`s: at its
36357cbeddf0SNuno Nobre 0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`.
3636d82b6cdfSNuno Nobre By default, $A_{11}$ is used to construct a preconditioner for $S$, use `PCFieldSplitSetSchurPre()` for all the possible ways to construct the preconditioner for $S$.
3637de37d9f1SPatrick Sanan
3638de37d9f1SPatrick Sanan The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above,
3639de37d9f1SPatrick Sanan `diag` gives
3640de37d9f1SPatrick Sanan ```{math}
3641f820a28cSNuno Nobre \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\ 0 & -\text{ksp}(S) \end{array}\right]
3642de37d9f1SPatrick Sanan ```
3643de37d9f1SPatrick Sanan 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
3644de37d9f1SPatrick Sanan can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of
3645de37d9f1SPatrick Sanan ```{math}
3646de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & 0 \\ A_{10} & S \end{array}\right]
3647de37d9f1SPatrick Sanan ```
3648cee94454SNuno Nobre where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of
3649de37d9f1SPatrick Sanan ```{math}
3650de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ 0 & S \end{array}\right]
3651de37d9f1SPatrick Sanan ```
3652de37d9f1SPatrick Sanan where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s.
3653de37d9f1SPatrick Sanan
3654de37d9f1SPatrick Sanan If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS`
365580670ca5SBarry Smith is used automatically for a second submatrix.
3656edf189efSBarry Smith
3657f1580f4eSBarry Smith The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1.
365880670ca5SBarry Smith Generally it should be used with the `MATAIJ` or `MATNEST` `MatType`
3659ff218e97SBarry Smith
366080670ca5SBarry Smith The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see,
36611d569b8fSBarry Smith for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`.
366280670ca5SBarry Smith One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers".
36630716a85fSBarry Smith
3664de37d9f1SPatrick Sanan See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`.
3665a6a584a2SBarry Smith
3666de37d9f1SPatrick Sanan The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the
3667de37d9f1SPatrick Sanan residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables.
3668a51937d4SCarola Kruse
3669de37d9f1SPatrick Sanan The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape
3670de37d9f1SPatrick Sanan ```{math}
3671de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right]
3672de37d9f1SPatrick Sanan ```
36731d569b8fSBarry Smith 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}'$.
3674de37d9f1SPatrick Sanan 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_`.
3675a51937d4SCarola Kruse
36760b4b7b1cSBarry Smith Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the
36770b4b7b1cSBarry Smith problem. But this nomenclature is not well-defined.
36780b4b7b1cSBarry Smith
367960f59c3bSBarry Smith Developer Note:
368060f59c3bSBarry Smith The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their
368160f59c3bSBarry Smith user API.
3682f1580f4eSBarry Smith
368360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`,
3684db781477SPatrick Sanan `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`,
3685db781477SPatrick Sanan `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`,
3686db781477SPatrick Sanan `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()`
36870971522cSBarry Smith M*/
36880971522cSBarry Smith
PCCreate_FieldSplit(PC pc)3689d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc)
3690d71ae5a4SJacob Faibussowitsch {
36910971522cSBarry Smith PC_FieldSplit *jac;
36920971522cSBarry Smith
36930971522cSBarry Smith PetscFunctionBegin;
36944dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&jac));
36952fa5cd67SKarl Rupp
36960971522cSBarry Smith jac->bs = -1;
36973e197d65SBarry Smith jac->type = PC_COMPOSITE_MULTIPLICATIVE;
3698e6cab6aaSJed Brown jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
3699c9c6ffaaSJed Brown jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
3700c096484dSStefano Zampini jac->schurscale = -1.0;
3701fbe7908bSJed Brown jac->dm_splits = PETSC_TRUE;
3702a51937d4SCarola Kruse jac->gkbtol = 1e-5;
3703a51937d4SCarola Kruse jac->gkbdelay = 5;
3704a51937d4SCarola Kruse jac->gkbnu = 1;
3705a51937d4SCarola Kruse jac->gkbmaxit = 100;
370651f519a2SBarry Smith
37070971522cSBarry Smith pc->data = (void *)jac;
37080971522cSBarry Smith
37090971522cSBarry Smith pc->ops->setup = PCSetUp_FieldSplit;
3710574deadeSBarry Smith pc->ops->reset = PCReset_FieldSplit;
37110971522cSBarry Smith pc->ops->destroy = PCDestroy_FieldSplit;
37120971522cSBarry Smith pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
37130a545947SLisandro Dalcin pc->ops->applyrichardson = NULL;
37140971522cSBarry Smith
37159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit));
37169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit));
37179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit));
37189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit));
37199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit));
37209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit));
37219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit));
37227ff38633SStefano Zampini
37237ff38633SStefano Zampini /* Initialize function pointers */
37247ff38633SStefano Zampini PetscCall(PCFieldSplitSetType(pc, jac->type));
37253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
37260971522cSBarry Smith }
3727