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 ....*/ 3*d484b384SBoris 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; 22*d484b384SBoris Martin Mat X, Y; 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. */ 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> 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 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 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 */ 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 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])); 4639566063dSJacob Faibussowitsch PetscCall(KSPSetDMActive(ilink->ksp, 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 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 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)); 9399566063dSJacob Faibussowitsch PetscCall(KSPSetDMActive(kspInner, 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)); 9889566063dSJacob Faibussowitsch PetscCall(KSPSetDMActive(jac->kspupper, 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)); 10199566063dSJacob Faibussowitsch PetscCall(KSPSetDMActive(jac->kspschur, 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 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)); 1137c9d0a0b7SPierre Jolivet if (!A) { 1138ab1f0642SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(PetscMalloc1(m * (N + 1), &array)); 1139ab1f0642SPierre Jolivet #if PetscDefined(HAVE_CUDA) 1140ab1f0642SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1))); 1141ab1f0642SPierre Jolivet #endif 1142ab1f0642SPierre Jolivet #if PetscDefined(HAVE_HIP) 1143ab1f0642SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1))); 1144ab1f0642SPierre Jolivet #endif 1145ab1f0642SPierre 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 11465becce15SPierre Jolivet PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", (PetscObject)A)); 11475becce15SPierre Jolivet PetscCall(MatDestroy(&A)); 114873716367SStefano Zampini } 1149c9d0a0b7SPierre Jolivet } 115073716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 115173716367SStefano Zampini } 115273716367SStefano Zampini 115373716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit(PC pc) 115473716367SStefano Zampini { 115573716367SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 115673716367SStefano Zampini PC_FieldSplitLink ilink = jac->head; 115773716367SStefano Zampini 115873716367SStefano Zampini PetscFunctionBegin; 115973716367SStefano Zampini while (ilink) { 116073716367SStefano Zampini PetscCall(KSPSetUp(ilink->ksp)); 116173716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(ilink->ksp)); 116273716367SStefano Zampini ilink = ilink->next; 116373716367SStefano Zampini } 116473716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 116573716367SStefano Zampini } 116673716367SStefano Zampini 116773716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_GKB(PC pc) 116873716367SStefano Zampini { 116973716367SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 117073716367SStefano Zampini PC_FieldSplitLink ilinkA = jac->head; 117173716367SStefano Zampini KSP ksp = ilinkA->ksp; 117273716367SStefano Zampini 117373716367SStefano Zampini PetscFunctionBegin; 117473716367SStefano Zampini PetscCall(KSPSetUp(ksp)); 117573716367SStefano Zampini PetscCall(KSPSetUpOnBlocks(ksp)); 117673716367SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 117773716367SStefano Zampini } 117873716367SStefano Zampini 1179d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y) 1180d71ae5a4SJacob Faibussowitsch { 11813b224e63SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 11823b224e63SBarry Smith PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1183443836d0SMatthew G Knepley KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 1184d9eadc85SPierre Jolivet Mat AinvB = NULL; 1185ab1f0642SPierre Jolivet PetscInt N, P; 11863b224e63SBarry Smith 11873b224e63SBarry Smith PetscFunctionBegin; 1188c5d2311dSJed Brown switch (jac->schurfactorization) { 1189c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 1190a04f6461SBarry Smith /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 11919566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 11929566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 11939566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 11949566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 11959566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 11969566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 11979566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 11989566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 11999566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 12009566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1201e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 12029566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 12039566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 1204e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 12059566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 12069566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->y, jac->schurscale)); 12079566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12089566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12099566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1210c5d2311dSJed Brown break; 1211c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 1212a04f6461SBarry Smith /* [A00 0; A10 S], suitable for left preconditioning */ 12139566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 12149566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 12159566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 12169566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 12179566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 12189566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 12199566063dSJacob Faibussowitsch PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x)); 12209566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, -1.)); 12219566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 12229566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12239566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 12249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1225e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 12269566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1227e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 12289566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 12299566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 12309566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12319566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12329566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1233c5d2311dSJed Brown break; 1234c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 1235a04f6461SBarry Smith /* [A00 A01; 0 S], suitable for right preconditioning */ 12369566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 12379566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 12389566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1239e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 12409566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1241e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 12429566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 12439371c9d4SSatish Balay PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 12449371c9d4SSatish Balay PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x)); 12459566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkA->x, -1.)); 12469566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 12479566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12489566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 12499566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 12509566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 12519566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 12529566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 12539566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12549566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 12559566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1256c5d2311dSJed Brown break; 1257c9c6ffaaSJed Brown case PC_FIELDSPLIT_SCHUR_FACT_FULL: 1258c238f8cdSStefano Zampini /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */ 1259ab1f0642SPierre Jolivet PetscCall(MatGetSize(jac->B, NULL, &P)); 1260ab1f0642SPierre Jolivet N = P; 12619566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 12629566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 12639566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL)); 1264d9eadc85SPierre Jolivet if (kspUpper == kspA) { 1265d9eadc85SPierre Jolivet PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB)); 1266d9eadc85SPierre Jolivet if (AinvB) { 1267d9eadc85SPierre Jolivet PetscCall(MatGetSize(AinvB, NULL, &N)); 1268ab1f0642SPierre Jolivet if (N > P) { // first time PCApply_FieldSplit_Schur() is called 1269f7cbcdf3SPierre Jolivet PetscMemType mtype; 1270ab1f0642SPierre Jolivet Vec c = NULL; 1271f7cbcdf3SPierre Jolivet PetscScalar *array; 1272ab1f0642SPierre Jolivet PetscInt m, M; 1273d9eadc85SPierre Jolivet 1274ab1f0642SPierre Jolivet PetscCall(MatGetSize(jac->B, &M, NULL)); 1275d9eadc85SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, &m, NULL)); 1276ab1f0642SPierre Jolivet PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype)); 1277ab1f0642SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c)); 1278f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA) 1279ab1f0642SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCall(VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c)); 1280f7cbcdf3SPierre Jolivet #endif 1281f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP) 1282ab1f0642SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCall(VecCreateMPIHIPWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c)); 1283f7cbcdf3SPierre Jolivet #endif 1284ab1f0642SPierre Jolivet PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array)); 1285ab1f0642SPierre Jolivet PetscCall(VecCopy(ilinkA->x, c)); 1286d9eadc85SPierre Jolivet PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user)); 1287d9eadc85SPierre Jolivet PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user)); 1288f7cbcdf3SPierre Jolivet PetscCall(VecCopy(c, ilinkA->y)); // retrieve the solution as the last column of the composed Mat 1289f7cbcdf3SPierre Jolivet PetscCall(VecDestroy(&c)); 1290d9eadc85SPierre Jolivet } 1291d9eadc85SPierre Jolivet } 1292d9eadc85SPierre Jolivet } 1293ab1f0642SPierre Jolivet if (N == P) PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y)); 12949566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y)); 12959566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL)); 12969566063dSJacob Faibussowitsch PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x)); 12979566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, -1.0)); 12989566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 12999566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 13003b224e63SBarry Smith 13019566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1302e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 13039566063dSJacob Faibussowitsch PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y)); 1304e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 13059566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 13069566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 13079566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 13083b224e63SBarry Smith 1309443836d0SMatthew G Knepley if (kspUpper == kspA) { 1310d9eadc85SPierre Jolivet if (!AinvB) { 13119566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y)); 13129566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y)); 13139566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 13149566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 13159566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 13169566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 1317d9eadc85SPierre Jolivet } else PetscCall(MatMultAdd(AinvB, ilinkD->y, ilinkA->y, ilinkA->y)); 1318443836d0SMatthew G Knepley } else { 13199566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 13209566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y)); 13219566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 13229566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x)); 13239566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL)); 13249566063dSJacob Faibussowitsch PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z)); 13259566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z)); 13269566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL)); 13279566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z)); 1328443836d0SMatthew G Knepley } 13299566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 13309566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 13319566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 1332c5d2311dSJed Brown } 13333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13343b224e63SBarry Smith } 13353b224e63SBarry Smith 1336*d484b384SBoris Martin /* 1337*d484b384SBoris Martin PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS 1338*d484b384SBoris Martin 1339*d484b384SBoris Martin Input Parameters: 1340*d484b384SBoris Martin + pc - the PC context 1341*d484b384SBoris Martin - X - matrix to copy column-layout from 1342*d484b384SBoris Martin 1343*d484b384SBoris Martin Notes: 1344*d484b384SBoris Martin If matrices already exist with correct column count, they are reused. 1345*d484b384SBoris Martin If column count changed, old matrices are destroyed and new ones created. 1346*d484b384SBoris Martin */ 1347*d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X) 1348*d484b384SBoris Martin { 1349*d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1350*d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head; 1351*d484b384SBoris Martin PetscInt mx, Mx, my, My, N; 1352*d484b384SBoris Martin 1353*d484b384SBoris Martin PetscFunctionBegin; 1354*d484b384SBoris Martin while (ilink) { 1355*d484b384SBoris Martin /* check if reallocation needed (previous allocation with wrong column count) */ 1356*d484b384SBoris Martin if (ilink->X) { 1357*d484b384SBoris Martin PetscCall(MatGetSize(ilink->X, NULL, &N)); 1358*d484b384SBoris Martin if (N != X->cmap->N) { 1359*d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X)); 1360*d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y)); 1361*d484b384SBoris Martin } 1362*d484b384SBoris Martin } 1363*d484b384SBoris Martin /* create if needed */ 1364*d484b384SBoris Martin if (!ilink->X) { 1365*d484b384SBoris Martin VecType xtype, ytype; 1366*d484b384SBoris Martin 1367*d484b384SBoris Martin PetscCall(VecGetType(ilink->x, &xtype)); 1368*d484b384SBoris Martin PetscCall(VecGetType(ilink->y, &ytype)); 1369*d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->x, &mx)); 1370*d484b384SBoris Martin PetscCall(VecGetSize(ilink->x, &Mx)); 1371*d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->y, &my)); 1372*d484b384SBoris Martin PetscCall(VecGetSize(ilink->y, &My)); 1373*d484b384SBoris Martin /* use default lda */ 1374*d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X)); 1375*d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y)); 1376*d484b384SBoris Martin } 1377*d484b384SBoris Martin ilink = ilink->next; 1378*d484b384SBoris Martin } 1379*d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS); 1380*d484b384SBoris Martin } 1381*d484b384SBoris Martin 13827b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y) 13837b665727SPierre Jolivet { 13847b665727SPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 13857b665727SPierre Jolivet PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 13867b665727SPierre Jolivet KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 13877b665727SPierre Jolivet 13887b665727SPierre Jolivet PetscFunctionBegin; 13897b665727SPierre Jolivet switch (jac->schurfactorization) { 13907b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 13917b665727SPierre Jolivet /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 13927b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 13937b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 13947b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 13957b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 13967b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 13977b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 13987b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 13997b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14007b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 14017b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1402e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 14037b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1404e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 14057b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 14067b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 14077b665727SPierre Jolivet PetscCall(VecScale(ilinkD->y, jac->schurscale)); 14087b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14097b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14107b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14117b665727SPierre Jolivet break; 14127b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 14137b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 14147b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 14157b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14167b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 14177b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 14187b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14197b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 14207b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.)); 14217b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 14227b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14237b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 14247b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1425e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 14267b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1427e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 14287b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 14297b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 14307b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14317b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14327b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14337b665727SPierre Jolivet break; 14347b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 14357b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 14367b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 14377b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1438e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 14397b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1440e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 14417b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 14427b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 14437b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 14447b665727SPierre Jolivet PetscCall(VecScale(ilinkA->x, -1.)); 14457b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 14467b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14477b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 14487b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14497b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 14507b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 14517b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14527b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14537b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14547b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14557b665727SPierre Jolivet break; 14567b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_FULL: 14577b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 14587b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 14597b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 14607b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y)); 14617b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y)); 14627b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 14637b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 14647b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.0)); 14657b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 14667b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 14677b665727SPierre Jolivet 14687b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1469e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 14707b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1471e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 14727b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 14737b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 14747b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14757b665727SPierre Jolivet 14767b665727SPierre Jolivet if (kspLower == kspA) { 14777b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y)); 14787b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y)); 14797b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14807b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 14817b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 14827b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14837b665727SPierre Jolivet } else { 14847b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 14857b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 14867b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 14877b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 14887b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 14897b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z)); 14907b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z)); 14917b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 14927b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z)); 14937b665727SPierre Jolivet } 14947b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14957b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14967b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 14977b665727SPierre Jolivet } 14987b665727SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 14997b665727SPierre Jolivet } 15007b665727SPierre Jolivet 15015becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \ 15025becce15SPierre 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) || \ 15035becce15SPierre 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) || \ 15045becce15SPierre Jolivet VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE))) 15055becce15SPierre Jolivet 1506d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y) 1507d71ae5a4SJacob Faibussowitsch { 15080971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 15095a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head; 1510939b8a20SBarry Smith PetscInt cnt, bs; 15110971522cSBarry Smith 15120971522cSBarry Smith PetscFunctionBegin; 151379416396SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) { 151480670ca5SBarry Smith PetscBool matnest; 151580670ca5SBarry Smith 151680670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest)); 151780670ca5SBarry Smith if (jac->defaultsplit && !matnest) { 15189566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs)); 15192472a847SBarry 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); 15209566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs)); 15212472a847SBarry 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); 15229566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 15235a9f2f41SSatish Balay while (ilink) { 15249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15259566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 15269566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 15279566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15285a9f2f41SSatish Balay ilink = ilink->next; 15290971522cSBarry Smith } 15309566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 15311b9fc7fcSBarry Smith } else { 15329566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 15335a9f2f41SSatish Balay while (ilink) { 15349566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 15355a9f2f41SSatish Balay ilink = ilink->next; 15361b9fc7fcSBarry Smith } 15371b9fc7fcSBarry Smith } 1538e52d2c62SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 15399566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 1540e52d2c62SBarry Smith /* solve on first block for first block variables */ 15419566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 15429566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 15439566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15449566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 15459566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 15469566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15479566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 15489566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1549e52d2c62SBarry Smith 1550e52d2c62SBarry Smith /* compute the residual only onto second block variables using first block variables */ 15519566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x)); 1552e52d2c62SBarry Smith ilink = ilink->next; 15539566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 15549566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 15559566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1556e52d2c62SBarry Smith 1557e52d2c62SBarry Smith /* solve on second block variables */ 15589566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15599566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 15609566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 15619566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15629566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 15639566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 156416913363SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 156579416396SBarry Smith if (!jac->w1) { 15669566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1)); 15679566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2)); 156879416396SBarry Smith } 15699566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 15709566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 15713e197d65SBarry Smith cnt = 1; 15725a9f2f41SSatish Balay while (ilink->next) { 15735a9f2f41SSatish Balay ilink = ilink->next; 15743e197d65SBarry Smith /* compute the residual only over the part of the vector needed */ 15759566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x)); 15769566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 15779566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 15789566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 15799566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15809566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 15819566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 15829566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15839566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 15849566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 15853e197d65SBarry Smith } 158651f519a2SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 158711755939SBarry Smith cnt -= 2; 158851f519a2SBarry Smith while (ilink->previous) { 158951f519a2SBarry Smith ilink = ilink->previous; 159011755939SBarry Smith /* compute the residual only over the part of the vector needed */ 15919566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x)); 15929566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 15939566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 15949566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 15959566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15969566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 15979566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 15989566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 15999566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 16009566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 160151f519a2SBarry Smith } 160211755939SBarry Smith } 160363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type); 16043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16050971522cSBarry Smith } 16060971522cSBarry Smith 1607*d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y) 1608*d484b384SBoris Martin { 1609*d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1610*d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head; 1611*d484b384SBoris Martin PetscInt cnt; 1612*d484b384SBoris Martin 1613*d484b384SBoris Martin PetscFunctionBegin; 1614*d484b384SBoris Martin /* create working matrices with the correct number of columns */ 1615*d484b384SBoris Martin PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X)); 1616*d484b384SBoris Martin if (jac->type == PC_COMPOSITE_ADDITIVE) { 1617*d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1618*d484b384SBoris Martin while (ilink) { 1619*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1620*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1621*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1622*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1623*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1624*d484b384SBoris Martin ilink = ilink->next; 1625*d484b384SBoris Martin } 1626*d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 1627*d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1628*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1629*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1630*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1631*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1632*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1633*d484b384SBoris Martin 1634*d484b384SBoris Martin /* compute the residual only onto second block variables using first block variables */ 1635*d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X)); 1636*d484b384SBoris Martin ilink = ilink->next; 1637*d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1638*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1639*d484b384SBoris Martin 1640*d484b384SBoris Martin /* solve on second block variables */ 1641*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1642*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1643*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1644*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1645*d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1646*d484b384SBoris Martin /* general multiplicative with any number of splits */ 1647*d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1648*d484b384SBoris Martin /* first split */ 1649*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1650*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1651*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1652*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1653*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1654*d484b384SBoris Martin cnt = 1; 1655*d484b384SBoris Martin /* forward sweep */ 1656*d484b384SBoris Martin while (ilink->next) { 1657*d484b384SBoris Martin ilink = ilink->next; 1658*d484b384SBoris Martin /* compute the residual only over the part of the vector needed */ 1659*d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X)); 1660*d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1661*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1662*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1663*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1664*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1665*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1666*d484b384SBoris Martin } 1667*d484b384SBoris Martin /* backward sweep for symmetric multiplicative */ 1668*d484b384SBoris Martin if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1669*d484b384SBoris Martin cnt -= 2; 1670*d484b384SBoris Martin while (ilink->previous) { 1671*d484b384SBoris Martin ilink = ilink->previous; 1672*d484b384SBoris Martin /* compute the residual only over the part of the vector needed */ 1673*d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X)); 1674*d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1675*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1676*d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1677*d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1678*d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1679*d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1680*d484b384SBoris Martin } 1681*d484b384SBoris Martin } 1682*d484b384SBoris Martin } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type"); 1683*d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS); 1684*d484b384SBoris Martin } 1685*d484b384SBoris Martin 1686d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y) 1687d71ae5a4SJacob Faibussowitsch { 1688a51937d4SCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1689a51937d4SCarola Kruse PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1690a51937d4SCarola Kruse KSP ksp = ilinkA->ksp; 1691de482cd7SCarola Kruse Vec u, v, Hu, d, work1, work2; 1692e071a0a4SCarola Kruse PetscScalar alpha, z, nrmz2, *vecz; 1693e071a0a4SCarola Kruse PetscReal lowbnd, nu, beta; 1694a51937d4SCarola Kruse PetscInt j, iterGKB; 1695a51937d4SCarola Kruse 1696a51937d4SCarola Kruse PetscFunctionBegin; 16979566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 16989566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 16999566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 17009566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1701e071a0a4SCarola Kruse 1702e071a0a4SCarola Kruse u = jac->u; 1703e071a0a4SCarola Kruse v = jac->v; 1704e071a0a4SCarola Kruse Hu = jac->Hu; 1705e071a0a4SCarola Kruse d = jac->d; 1706e071a0a4SCarola Kruse work1 = jac->w1; 1707e071a0a4SCarola Kruse work2 = jac->w2; 1708e071a0a4SCarola Kruse vecz = jac->vecz; 1709a51937d4SCarola Kruse 1710a51937d4SCarola Kruse /* Change RHS to comply with matrix regularization H = A + nu*B*B' */ 1711a51937d4SCarola Kruse /* Add q = q + nu*B*b */ 1712a51937d4SCarola Kruse if (jac->gkbnu) { 1713a51937d4SCarola Kruse nu = jac->gkbnu; 17149566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, jac->gkbnu)); 17159566063dSJacob Faibussowitsch PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */ 1716a51937d4SCarola Kruse } else { 1717a51937d4SCarola Kruse /* Situation when no augmented Lagrangian is used. Then we set inner */ 1718a51937d4SCarola Kruse /* matrix N = I in [Ar13], and thus nu = 1. */ 1719a51937d4SCarola Kruse nu = 1; 1720a51937d4SCarola Kruse } 1721a51937d4SCarola Kruse 1722a51937d4SCarola Kruse /* Transform rhs from [q,tilde{b}] to [0,b] */ 17239566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 17249566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y)); 17259566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y)); 17269566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 17279566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1)); 17289566063dSJacob Faibussowitsch PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x */ 1729a51937d4SCarola Kruse 1730a51937d4SCarola Kruse /* First step of algorithm */ 17319566063dSJacob Faibussowitsch PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/ 1732e071a0a4SCarola Kruse KSPCheckDot(ksp, beta); 1733addd1e01SJunchao Zhang beta = PetscSqrtReal(nu) * beta; 17349566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c */ 17359566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u = H^{-1}*B*v */ 17369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 17379566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u)); 17389566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u)); 17399566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 17409566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 17419566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha)); 1742e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha); 174308401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1744addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 17459566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha)); 17469566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c */ 1747de482cd7SCarola Kruse 1748a51937d4SCarola Kruse z = beta / alpha; 1749a51937d4SCarola Kruse vecz[1] = z; 1750a51937d4SCarola Kruse 1751de482cd7SCarola Kruse /* Computation of first iterate x(1) and p(1) */ 17529566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u)); 17539566063dSJacob Faibussowitsch PetscCall(VecCopy(d, ilinkD->y)); 17549566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->y, -z)); 1755a51937d4SCarola Kruse 17569371c9d4SSatish Balay iterGKB = 1; 17579371c9d4SSatish Balay lowbnd = 2 * jac->gkbtol; 175848a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1759de482cd7SCarola Kruse 1760a51937d4SCarola Kruse while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) { 1761a51937d4SCarola Kruse iterGKB += 1; 17629566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */ 17639566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu, -alpha, work1)); 17649566063dSJacob Faibussowitsch PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v */ 1765addd1e01SJunchao Zhang beta = beta / PetscSqrtReal(nu); 17669566063dSJacob Faibussowitsch PetscCall(VecScale(v, 1.0 / beta)); 17679566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */ 17689566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); 17699566063dSJacob Faibussowitsch PetscCall(VecAXPY(work2, -beta, Hu)); 17709566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 17719566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u)); 17729566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u)); 17739566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 17749566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 17759566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha)); 1776e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha); 177708401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1778addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 17799566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha)); 1780a51937d4SCarola Kruse 1781e071a0a4SCarola Kruse z = -beta / alpha * z; /* z <- beta/alpha*z */ 1782a51937d4SCarola Kruse vecz[0] = z; 1783a51937d4SCarola Kruse 1784a51937d4SCarola Kruse /* Computation of new iterate x(i+1) and p(i+1) */ 17859566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */ 17869566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u)); /* r = r + z*u */ 17879566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkD->y, -z, d)); /* p = p - z*d */ 17889566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, ilinkA->y, Hu)); /* ||u||_H = u'*H*u */ 17899566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, ilinkA->y, &nrmz2)); 1790a51937d4SCarola Kruse 1791a51937d4SCarola Kruse /* Compute Lower Bound estimate */ 1792a51937d4SCarola Kruse if (iterGKB > jac->gkbdelay) { 1793a51937d4SCarola Kruse lowbnd = 0.0; 1794ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]); 1795addd1e01SJunchao Zhang lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2)); 1796a51937d4SCarola Kruse } 1797a51937d4SCarola Kruse 1798ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2]; 179948a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1800a51937d4SCarola Kruse } 1801a51937d4SCarola Kruse 18029566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 18039566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 18049566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 18059566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 18063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1807a51937d4SCarola Kruse } 1808a51937d4SCarola Kruse 1809421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \ 18103ba16761SJacob 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) || \ 18119371c9d4SSatish 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) || \ 18123ba16761SJacob Faibussowitsch VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE))) 1813421e10b8SBarry Smith 1814d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y) 1815d71ae5a4SJacob Faibussowitsch { 1816421e10b8SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1817421e10b8SBarry Smith PC_FieldSplitLink ilink = jac->head; 1818939b8a20SBarry Smith PetscInt bs; 1819421e10b8SBarry Smith 1820421e10b8SBarry Smith PetscFunctionBegin; 1821421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) { 182280670ca5SBarry Smith PetscBool matnest; 182380670ca5SBarry Smith 182480670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest)); 182580670ca5SBarry Smith if (jac->defaultsplit && !matnest) { 18269566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs)); 18272472a847SBarry 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); 18289566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs)); 18292472a847SBarry 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); 18309566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 1831421e10b8SBarry Smith while (ilink) { 18329566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 18339566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y)); 18349566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 18359566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 1836421e10b8SBarry Smith ilink = ilink->next; 1837421e10b8SBarry Smith } 18389566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 1839421e10b8SBarry Smith } else { 18409566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 1841421e10b8SBarry Smith while (ilink) { 18429566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1843421e10b8SBarry Smith ilink = ilink->next; 1844421e10b8SBarry Smith } 1845421e10b8SBarry Smith } 1846421e10b8SBarry Smith } else { 1847421e10b8SBarry Smith if (!jac->w1) { 18489566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1)); 18499566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2)); 1850421e10b8SBarry Smith } 18519566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 1852421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 18539566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1854421e10b8SBarry Smith while (ilink->next) { 1855421e10b8SBarry Smith ilink = ilink->next; 18569566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 18579566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 18589566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1859421e10b8SBarry Smith } 1860421e10b8SBarry Smith while (ilink->previous) { 1861421e10b8SBarry Smith ilink = ilink->previous; 18629566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 18639566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 18649566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1865421e10b8SBarry Smith } 1866421e10b8SBarry Smith } else { 1867421e10b8SBarry Smith while (ilink->next) { /* get to last entry in linked list */ 1868421e10b8SBarry Smith ilink = ilink->next; 1869421e10b8SBarry Smith } 18709566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 1871421e10b8SBarry Smith while (ilink->previous) { 1872421e10b8SBarry Smith ilink = ilink->previous; 18739566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 18749566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 18759566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 1876421e10b8SBarry Smith } 1877421e10b8SBarry Smith } 1878421e10b8SBarry Smith } 18793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1880421e10b8SBarry Smith } 1881421e10b8SBarry Smith 1882d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc) 1883d71ae5a4SJacob Faibussowitsch { 18840971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 18855a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head, next; 18860971522cSBarry Smith 18870971522cSBarry Smith PetscFunctionBegin; 18885a9f2f41SSatish Balay while (ilink) { 18899566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&ilink->ksp)); 18909566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->x)); 18919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->y)); 18929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->z)); 1893*d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X)); 1894*d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y)); 18959566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&ilink->sctx)); 18969566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 18979566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 18989566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->splitname)); 18999566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields)); 19009566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields_col)); 19015a9f2f41SSatish Balay next = ilink->next; 19029566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink)); 19035a9f2f41SSatish Balay ilink = next; 19040971522cSBarry Smith } 1905f5f0d762SBarry Smith jac->head = NULL; 19069566063dSJacob Faibussowitsch PetscCall(PetscFree2(jac->x, jac->y)); 1907574deadeSBarry Smith if (jac->mat && jac->mat != jac->pmat) { 19089566063dSJacob Faibussowitsch PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat)); 1909574deadeSBarry Smith } else if (jac->mat) { 19100298fd71SBarry Smith jac->mat = NULL; 1911574deadeSBarry Smith } 19129566063dSJacob Faibussowitsch if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat)); 19139566063dSJacob Faibussowitsch if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield)); 1914f5f0d762SBarry Smith jac->nsplits = 0; 19159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w1)); 19169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w2)); 191773716367SStefano Zampini if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL)); 19189566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur)); 19199566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schurp)); 19209566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user)); 19219566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspschur)); 19229566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspupper)); 19239566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->B)); 19249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->C)); 19259566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->H)); 19269566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->u)); 19279566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->v)); 19289566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->Hu)); 19299566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->d)); 19309566063dSJacob Faibussowitsch PetscCall(PetscFree(jac->vecz)); 19319566063dSJacob Faibussowitsch PetscCall(PetscViewerDestroy(&jac->gkbviewer)); 19326dbb499eSCian Wilson jac->isrestrict = PETSC_FALSE; 19333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1934574deadeSBarry Smith } 1935574deadeSBarry Smith 1936d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1937d71ae5a4SJacob Faibussowitsch { 1938574deadeSBarry Smith PetscFunctionBegin; 19399566063dSJacob Faibussowitsch PetscCall(PCReset_FieldSplit(pc)); 19409566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 19412e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL)); 19429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL)); 19439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL)); 19449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL)); 19459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL)); 19462e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL)); 19472e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL)); 19482e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 19492e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 19502e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 19512e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 19522e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 19539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 19549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 19559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 19562e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 19573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19580971522cSBarry Smith } 19590971522cSBarry Smith 1960ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject) 1961d71ae5a4SJacob Faibussowitsch { 19626c924f48SJed Brown PetscInt bs; 19637b752e3dSPatrick Sanan PetscBool flg; 19649dcbbd2bSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 19653b224e63SBarry Smith PCCompositeType ctype; 19661b9fc7fcSBarry Smith 19670971522cSBarry Smith PetscFunctionBegin; 1968d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options"); 19699566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL)); 19709566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg)); 19711baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs)); 19722686e3e9SMatthew G. Knepley jac->diag_use_amat = pc->useAmat; 19739566063dSJacob 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)); 19742686e3e9SMatthew G. Knepley jac->offdiag_use_amat = pc->useAmat; 19759566063dSJacob 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)); 19769566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL)); 19779566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */ 19789566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg)); 19791baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetType(pc, ctype)); 1980c30613efSMatthew Knepley /* Only setup fields once */ 1981b6555650SPierre Jolivet if (jac->bs > 0 && jac->nsplits == 0) { 198280670ca5SBarry Smith /* only allow user to set fields from command line. 1983d32f9abdSBarry Smith otherwise user can set them in PCFieldSplitSetDefaults() */ 19849566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc)); 19859566063dSJacob Faibussowitsch if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n")); 1986d32f9abdSBarry Smith } 1987c5d2311dSJed Brown if (jac->type == PC_COMPOSITE_SCHUR) { 19889566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg)); 19899566063dSJacob Faibussowitsch if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n")); 19909566063dSJacob 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)); 19919566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL)); 19929566063dSJacob Faibussowitsch PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL)); 1993a51937d4SCarola Kruse } else if (jac->type == PC_COMPOSITE_GKB) { 1994a077d33dSBarry Smith PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL)); 1995a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL)); 1996a077d33dSBarry Smith PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0)); 1997a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL)); 19989566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL)); 1999c5d2311dSJed Brown } 200034603f55SBarry Smith /* 200134603f55SBarry Smith In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet. 200234603f55SBarry 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 200334603f55SBarry Smith is called on the outer solver in case changes were made in the options database 200434603f55SBarry Smith 200534603f55SBarry 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() 200634603f55SBarry 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. 200734603f55SBarry Smith Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types. 200834603f55SBarry Smith 200934603f55SBarry Smith There could be a negative side effect of calling the KSPSetFromOptions() below. 201034603f55SBarry Smith 201134603f55SBarry 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 201234603f55SBarry Smith */ 201334603f55SBarry Smith if (jac->issetup) { 201434603f55SBarry Smith PC_FieldSplitLink ilink = jac->head; 201534603f55SBarry Smith if (jac->type == PC_COMPOSITE_SCHUR) { 201634603f55SBarry Smith if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper)); 201734603f55SBarry Smith if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur)); 201834603f55SBarry Smith } 201934603f55SBarry Smith while (ilink) { 202034603f55SBarry Smith if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp)); 202134603f55SBarry Smith ilink = ilink->next; 202234603f55SBarry Smith } 202334603f55SBarry Smith } 2024d0609cedSBarry Smith PetscOptionsHeadEnd(); 20253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20260971522cSBarry Smith } 20270971522cSBarry Smith 2028d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) 2029d71ae5a4SJacob Faibussowitsch { 203097bbdb24SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 20315a9f2f41SSatish Balay PC_FieldSplitLink ilink, next = jac->head; 203269a612a9SBarry Smith char prefix[128]; 20335d4c12cdSJungho Lee PetscInt i; 2034835f2295SStefano Zampini PetscLogEvent nse; 20350971522cSBarry Smith 20360971522cSBarry Smith PetscFunctionBegin; 20376c924f48SJed Brown if (jac->splitdefined) { 20389566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 20393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20406c924f48SJed Brown } 2041ac530a7eSPierre 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]); 20429566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink)); 2043a04f6461SBarry Smith if (splitname) { 20449566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 2045a04f6461SBarry Smith } else { 20469566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3, &ilink->splitname)); 204763a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits)); 2048a04f6461SBarry Smith } 2049835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse)); 2050835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */ 20519566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields)); 20529566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields, fields, n)); 20539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields_col)); 20549566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n)); 20552fa5cd67SKarl Rupp 20565a9f2f41SSatish Balay ilink->nfields = n; 20570298fd71SBarry Smith ilink->next = NULL; 20589566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 20593821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 20609566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 20619566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 20629566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 206369a612a9SBarry Smith 20649566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 20659566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 20660971522cSBarry Smith 20670971522cSBarry Smith if (!next) { 20685a9f2f41SSatish Balay jac->head = ilink; 20690298fd71SBarry Smith ilink->previous = NULL; 20700971522cSBarry Smith } else { 2071ad540459SPierre Jolivet while (next->next) next = next->next; 20725a9f2f41SSatish Balay next->next = ilink; 207351f519a2SBarry Smith ilink->previous = next; 20740971522cSBarry Smith } 20750971522cSBarry Smith jac->nsplits++; 20763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20770971522cSBarry Smith } 20780971522cSBarry Smith 2079d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 2080d71ae5a4SJacob Faibussowitsch { 2081285fb4e2SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2082285fb4e2SStefano Zampini 2083285fb4e2SStefano Zampini PetscFunctionBegin; 2084285fb4e2SStefano Zampini *subksp = NULL; 2085285fb4e2SStefano Zampini if (n) *n = 0; 2086285fb4e2SStefano Zampini if (jac->type == PC_COMPOSITE_SCHUR) { 2087285fb4e2SStefano Zampini PetscInt nn; 2088285fb4e2SStefano Zampini 208928b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()"); 209063a3b9bcSJacob Faibussowitsch PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits); 2091285fb4e2SStefano Zampini nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0); 20929566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nn, subksp)); 2093285fb4e2SStefano Zampini (*subksp)[0] = jac->head->ksp; 2094285fb4e2SStefano Zampini (*subksp)[1] = jac->kspschur; 2095285fb4e2SStefano Zampini if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper; 2096285fb4e2SStefano Zampini if (n) *n = nn; 2097285fb4e2SStefano Zampini } 20983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2099285fb4e2SStefano Zampini } 2100285fb4e2SStefano Zampini 2101d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp) 2102d71ae5a4SJacob Faibussowitsch { 2103e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2104e69d4d44SBarry Smith 2105e69d4d44SBarry Smith PetscFunctionBegin; 210628b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()"); 21079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp)); 21089566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp)); 21092fa5cd67SKarl Rupp 2110e69d4d44SBarry Smith (*subksp)[1] = jac->kspschur; 211113e0d083SBarry Smith if (n) *n = jac->nsplits; 21123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2113e69d4d44SBarry Smith } 21140971522cSBarry Smith 2115d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 2116d71ae5a4SJacob Faibussowitsch { 21170971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 21180971522cSBarry Smith PetscInt cnt = 0; 21195a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head; 21200971522cSBarry Smith 21210971522cSBarry Smith PetscFunctionBegin; 21229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp)); 21235a9f2f41SSatish Balay while (ilink) { 21245a9f2f41SSatish Balay (*subksp)[cnt++] = ilink->ksp; 21255a9f2f41SSatish Balay ilink = ilink->next; 21260971522cSBarry Smith } 212763a3b9bcSJacob 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); 212813e0d083SBarry Smith if (n) *n = jac->nsplits; 21293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21300971522cSBarry Smith } 21310971522cSBarry Smith 2132cc4c1da9SBarry Smith /*@ 2133f1580f4eSBarry Smith PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`. 21346dbb499eSCian Wilson 21356dbb499eSCian Wilson Input Parameters: 21366dbb499eSCian Wilson + pc - the preconditioner context 2137feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted 21386dbb499eSCian Wilson 21396dbb499eSCian Wilson Level: advanced 21406dbb499eSCian Wilson 2141feefa0e1SJacob Faibussowitsch Developer Notes: 2142f1580f4eSBarry Smith It seems the resulting `IS`s will not cover the entire space, so 2143f1580f4eSBarry Smith how can they define a convergent preconditioner? Needs explaining. 2144f1580f4eSBarry Smith 214560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 21466dbb499eSCian Wilson @*/ 2147d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy) 2148d71ae5a4SJacob Faibussowitsch { 21496dbb499eSCian Wilson PetscFunctionBegin; 21506dbb499eSCian Wilson PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 21516dbb499eSCian Wilson PetscValidHeaderSpecific(isy, IS_CLASSID, 2); 2152cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy)); 21533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21546dbb499eSCian Wilson } 21556dbb499eSCian Wilson 2156d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) 2157d71ae5a4SJacob Faibussowitsch { 21586dbb499eSCian Wilson PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 21596dbb499eSCian Wilson PC_FieldSplitLink ilink = jac->head, next; 21606dbb499eSCian Wilson PetscInt localsize, size, sizez, i; 21616dbb499eSCian Wilson const PetscInt *ind, *indz; 21626dbb499eSCian Wilson PetscInt *indc, *indcz; 21636dbb499eSCian Wilson PetscBool flg; 21646dbb499eSCian Wilson 21656dbb499eSCian Wilson PetscFunctionBegin; 21669566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isy, &localsize)); 21679566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy))); 21686dbb499eSCian Wilson size -= localsize; 21696dbb499eSCian Wilson while (ilink) { 21706dbb499eSCian Wilson IS isrl, isr; 21711c7cfba8SBarry Smith PC subpc; 21729566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl)); 21739566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isrl, &localsize)); 21749566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indc)); 21759566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isrl, &ind)); 21769566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indc, ind, localsize)); 21779566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isrl, &ind)); 21789566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isrl)); 21796dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indc + i) += size; 21809566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr)); 21819566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr)); 21829566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 21836dbb499eSCian Wilson ilink->is = isr; 21849566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr)); 21859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 21866dbb499eSCian Wilson ilink->is_col = isr; 21879566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isr)); 21889566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ilink->ksp, &subpc)); 21899566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg)); 21906dbb499eSCian Wilson if (flg) { 21916dbb499eSCian Wilson IS iszl, isz; 21926dbb499eSCian Wilson MPI_Comm comm; 21939566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(ilink->is, &localsize)); 21946dbb499eSCian Wilson comm = PetscObjectComm((PetscObject)ilink->is); 21959566063dSJacob Faibussowitsch PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl)); 21969566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm)); 21976dbb499eSCian Wilson sizez -= localsize; 21989566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(iszl, &localsize)); 21999566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indcz)); 22009566063dSJacob Faibussowitsch PetscCall(ISGetIndices(iszl, &indz)); 22019566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indcz, indz, localsize)); 22029566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(iszl, &indz)); 22039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&iszl)); 22046dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indcz + i) += sizez; 22059566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz)); 22069566063dSJacob Faibussowitsch PetscCall(PCFieldSplitRestrictIS(subpc, isz)); 22079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isz)); 22086dbb499eSCian Wilson } 22096dbb499eSCian Wilson next = ilink->next; 22106dbb499eSCian Wilson ilink = next; 22116dbb499eSCian Wilson } 22126dbb499eSCian Wilson jac->isrestrict = PETSC_TRUE; 22133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22146dbb499eSCian Wilson } 22156dbb499eSCian Wilson 2216d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is) 2217d71ae5a4SJacob Faibussowitsch { 2218704ba839SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2219704ba839SBarry Smith PC_FieldSplitLink ilink, next = jac->head; 2220704ba839SBarry Smith char prefix[128]; 2221835f2295SStefano Zampini PetscLogEvent nse; 2222704ba839SBarry Smith 2223704ba839SBarry Smith PetscFunctionBegin; 22246c924f48SJed Brown if (jac->splitdefined) { 22259566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 22263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22276c924f48SJed Brown } 22289566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink)); 2229a04f6461SBarry Smith if (splitname) { 22309566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 2231a04f6461SBarry Smith } else { 22329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(8, &ilink->splitname)); 223363a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits)); 2234a04f6461SBarry Smith } 2235835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse)); 2236835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */ 22379566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is)); 22389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 2239b5787286SJed Brown ilink->is = is; 22409566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is)); 22419566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 2242b5787286SJed Brown ilink->is_col = is; 22430298fd71SBarry Smith ilink->next = NULL; 22449566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 22453821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 22469566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 22479566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 22489566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 2249704ba839SBarry Smith 22509566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 22519566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 2252704ba839SBarry Smith 2253704ba839SBarry Smith if (!next) { 2254704ba839SBarry Smith jac->head = ilink; 22550298fd71SBarry Smith ilink->previous = NULL; 2256704ba839SBarry Smith } else { 2257ad540459SPierre Jolivet while (next->next) next = next->next; 2258704ba839SBarry Smith next->next = ilink; 2259704ba839SBarry Smith ilink->previous = next; 2260704ba839SBarry Smith } 2261704ba839SBarry Smith jac->nsplits++; 22623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2263704ba839SBarry Smith } 2264704ba839SBarry Smith 22655d83a8b1SBarry Smith /*@ 226660f59c3bSBarry Smith PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT` 22670971522cSBarry Smith 2268c3339decSBarry Smith Logically Collective 22690971522cSBarry Smith 22700971522cSBarry Smith Input Parameters: 22710971522cSBarry Smith + pc - the preconditioner context 227260f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used 22730971522cSBarry Smith . n - the number of fields in this split 22743b374dbdSBarry Smith . fields - the fields in this split 227580670ca5SBarry 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 227680670ca5SBarry Smith of the matrix and `fields_col` provides the column indices for that block 227780670ca5SBarry Smith 227880670ca5SBarry Smith Options Database Key: 227980670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split 22800971522cSBarry Smith 22810971522cSBarry Smith Level: intermediate 22820971522cSBarry Smith 228395452b02SPatrick Sanan Notes: 2284f1580f4eSBarry Smith Use `PCFieldSplitSetIS()` to set a general set of indices as a split. 2285d32f9abdSBarry Smith 228680670ca5SBarry Smith If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`. 228780670ca5SBarry Smith 228880670ca5SBarry Smith If the matrix used to construct the preconditioner is not `MATNEST` then 228954c05997SPierre Jolivet `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or 229080670ca5SBarry Smith to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block 2291f1580f4eSBarry 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 229214c74629SNuno Nobre 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x.... 2293f1580f4eSBarry Smith where the numbered entries indicate what is in the split. 2294d32f9abdSBarry Smith 2295db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options 229660f59c3bSBarry Smith for this split will be available under the prefix `-fieldsplit_SPLITNAME_`. 2297db4c96c1SJed Brown 229880670ca5SBarry Smith `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields` 22993b374dbdSBarry Smith 2300feefa0e1SJacob Faibussowitsch Developer Notes: 2301f1580f4eSBarry Smith This routine does not actually create the `IS` representing the split, that is delayed 2302f1580f4eSBarry Smith until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be 23035d4c12cdSJungho Lee available when this routine is called. 23045d4c12cdSJungho Lee 230580670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`, 230654c05997SPierre Jolivet `MatSetBlockSize()`, `MatCreateNest()` 23070971522cSBarry Smith @*/ 2308cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[]) 2309d71ae5a4SJacob Faibussowitsch { 23100971522cSBarry Smith PetscFunctionBegin; 23110700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 23124f572ea9SToby Isaac PetscAssertPointer(splitname, 2); 231363a3b9bcSJacob Faibussowitsch PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname); 23144f572ea9SToby Isaac PetscAssertPointer(fields, 4); 2315cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col)); 23163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23170971522cSBarry Smith } 23180971522cSBarry Smith 2319c84da90fSDmitry Karpeev /*@ 2320f1580f4eSBarry Smith PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2321c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2322c84da90fSDmitry Karpeev 2323c3339decSBarry Smith Logically Collective 2324c84da90fSDmitry Karpeev 2325c84da90fSDmitry Karpeev Input Parameters: 2326c84da90fSDmitry Karpeev + pc - the preconditioner object 2327c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2328c84da90fSDmitry Karpeev 232920f4b53cSBarry Smith Options Database Key: 2330147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks 2331c84da90fSDmitry Karpeev 2332c84da90fSDmitry Karpeev Level: intermediate 2333c84da90fSDmitry Karpeev 233460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT` 2335c84da90fSDmitry Karpeev @*/ 2336d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg) 2337d71ae5a4SJacob Faibussowitsch { 2338c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2339c84da90fSDmitry Karpeev PetscBool isfs; 2340c84da90fSDmitry Karpeev 2341c84da90fSDmitry Karpeev PetscFunctionBegin; 2342c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 23439566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 234428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2345c84da90fSDmitry Karpeev jac->diag_use_amat = flg; 23463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2347c84da90fSDmitry Karpeev } 2348c84da90fSDmitry Karpeev 2349c84da90fSDmitry Karpeev /*@ 2350f1580f4eSBarry Smith PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2351c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2352c84da90fSDmitry Karpeev 2353c3339decSBarry Smith Logically Collective 2354c84da90fSDmitry Karpeev 235520f4b53cSBarry Smith Input Parameter: 2356c84da90fSDmitry Karpeev . pc - the preconditioner object 2357c84da90fSDmitry Karpeev 235820f4b53cSBarry Smith Output Parameter: 2359c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2360c84da90fSDmitry Karpeev 2361c84da90fSDmitry Karpeev Level: intermediate 2362c84da90fSDmitry Karpeev 236360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT` 2364c84da90fSDmitry Karpeev @*/ 2365d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg) 2366d71ae5a4SJacob Faibussowitsch { 2367c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2368c84da90fSDmitry Karpeev PetscBool isfs; 2369c84da90fSDmitry Karpeev 2370c84da90fSDmitry Karpeev PetscFunctionBegin; 2371c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 23724f572ea9SToby Isaac PetscAssertPointer(flg, 2); 23739566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 237428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2375c84da90fSDmitry Karpeev *flg = jac->diag_use_amat; 23763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2377c84da90fSDmitry Karpeev } 2378c84da90fSDmitry Karpeev 2379c84da90fSDmitry Karpeev /*@ 2380f1580f4eSBarry Smith PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2381c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2382c84da90fSDmitry Karpeev 2383c3339decSBarry Smith Logically Collective 2384c84da90fSDmitry Karpeev 2385c84da90fSDmitry Karpeev Input Parameters: 2386c84da90fSDmitry Karpeev + pc - the preconditioner object 2387c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2388c84da90fSDmitry Karpeev 238920f4b53cSBarry Smith Options Database Key: 2390147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks 2391c84da90fSDmitry Karpeev 2392c84da90fSDmitry Karpeev Level: intermediate 2393c84da90fSDmitry Karpeev 239460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT` 2395c84da90fSDmitry Karpeev @*/ 2396d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg) 2397d71ae5a4SJacob Faibussowitsch { 2398c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2399c84da90fSDmitry Karpeev PetscBool isfs; 2400c84da90fSDmitry Karpeev 2401c84da90fSDmitry Karpeev PetscFunctionBegin; 2402c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 24039566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 240428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2405c84da90fSDmitry Karpeev jac->offdiag_use_amat = flg; 24063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2407c84da90fSDmitry Karpeev } 2408c84da90fSDmitry Karpeev 2409c84da90fSDmitry Karpeev /*@ 2410f1580f4eSBarry Smith PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2411c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2412c84da90fSDmitry Karpeev 2413c3339decSBarry Smith Logically Collective 2414c84da90fSDmitry Karpeev 241520f4b53cSBarry Smith Input Parameter: 2416c84da90fSDmitry Karpeev . pc - the preconditioner object 2417c84da90fSDmitry Karpeev 241820f4b53cSBarry Smith Output Parameter: 2419c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2420c84da90fSDmitry Karpeev 2421c84da90fSDmitry Karpeev Level: intermediate 2422c84da90fSDmitry Karpeev 242360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT` 2424c84da90fSDmitry Karpeev @*/ 2425d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg) 2426d71ae5a4SJacob Faibussowitsch { 2427c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2428c84da90fSDmitry Karpeev PetscBool isfs; 2429c84da90fSDmitry Karpeev 2430c84da90fSDmitry Karpeev PetscFunctionBegin; 2431c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 24324f572ea9SToby Isaac PetscAssertPointer(flg, 2); 24339566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 243428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2435c84da90fSDmitry Karpeev *flg = jac->offdiag_use_amat; 24363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2437c84da90fSDmitry Karpeev } 2438c84da90fSDmitry Karpeev 2439cc4c1da9SBarry Smith /*@ 2440f1580f4eSBarry Smith PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT` 2441704ba839SBarry Smith 2442c3339decSBarry Smith Logically Collective 2443704ba839SBarry Smith 2444704ba839SBarry Smith Input Parameters: 2445704ba839SBarry Smith + pc - the preconditioner context 244660f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used 2447f1580f4eSBarry Smith - is - the index set that defines the elements in this split 2448704ba839SBarry Smith 244960f59c3bSBarry Smith Level: intermediate 245060f59c3bSBarry Smith 2451a6ffb8dbSJed Brown Notes: 245280670ca5SBarry Smith Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST` 2453a6ffb8dbSJed Brown 2454db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options 2455db4c96c1SJed Brown for this split will be available under the prefix -fieldsplit_SPLITNAME_. 2456d32f9abdSBarry Smith 245780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()` 2458704ba839SBarry Smith @*/ 2459d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is) 2460d71ae5a4SJacob Faibussowitsch { 2461704ba839SBarry Smith PetscFunctionBegin; 24620700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 24634f572ea9SToby Isaac if (splitname) PetscAssertPointer(splitname, 2); 2464db4c96c1SJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 3); 2465cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is)); 24663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2467704ba839SBarry Smith } 2468704ba839SBarry Smith 2469cc4c1da9SBarry Smith /*@ 2470f1580f4eSBarry Smith PCFieldSplitGetIS - Retrieves the elements for a split as an `IS` 247157a9adfeSMatthew G Knepley 2472c3339decSBarry Smith Logically Collective 247357a9adfeSMatthew G Knepley 247457a9adfeSMatthew G Knepley Input Parameters: 247557a9adfeSMatthew G Knepley + pc - the preconditioner context 247657a9adfeSMatthew G Knepley - splitname - name of this split 247757a9adfeSMatthew G Knepley 247857a9adfeSMatthew G Knepley Output Parameter: 2479feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found 248057a9adfeSMatthew G Knepley 248157a9adfeSMatthew G Knepley Level: intermediate 248257a9adfeSMatthew G Knepley 248380670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()` 248457a9adfeSMatthew G Knepley @*/ 2485d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is) 2486d71ae5a4SJacob Faibussowitsch { 248757a9adfeSMatthew G Knepley PetscFunctionBegin; 248857a9adfeSMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 24894f572ea9SToby Isaac PetscAssertPointer(splitname, 2); 24904f572ea9SToby Isaac PetscAssertPointer(is, 3); 249157a9adfeSMatthew G Knepley { 249257a9adfeSMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 249357a9adfeSMatthew G Knepley PC_FieldSplitLink ilink = jac->head; 249457a9adfeSMatthew G Knepley PetscBool found; 249557a9adfeSMatthew G Knepley 24960298fd71SBarry Smith *is = NULL; 249757a9adfeSMatthew G Knepley while (ilink) { 24989566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(ilink->splitname, splitname, &found)); 249957a9adfeSMatthew G Knepley if (found) { 250057a9adfeSMatthew G Knepley *is = ilink->is; 250157a9adfeSMatthew G Knepley break; 250257a9adfeSMatthew G Knepley } 250357a9adfeSMatthew G Knepley ilink = ilink->next; 250457a9adfeSMatthew G Knepley } 250557a9adfeSMatthew G Knepley } 25063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 250757a9adfeSMatthew G Knepley } 250857a9adfeSMatthew G Knepley 2509cc4c1da9SBarry Smith /*@ 2510f1580f4eSBarry Smith PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS` 2511998f007dSPierre Jolivet 2512c3339decSBarry Smith Logically Collective 2513998f007dSPierre Jolivet 2514998f007dSPierre Jolivet Input Parameters: 2515998f007dSPierre Jolivet + pc - the preconditioner context 2516998f007dSPierre Jolivet - index - index of this split 2517998f007dSPierre Jolivet 2518998f007dSPierre Jolivet Output Parameter: 2519feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split 2520998f007dSPierre Jolivet 2521998f007dSPierre Jolivet Level: intermediate 2522998f007dSPierre Jolivet 252380670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`, 252480670ca5SBarry Smith 2525998f007dSPierre Jolivet @*/ 2526d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is) 2527d71ae5a4SJacob Faibussowitsch { 2528998f007dSPierre Jolivet PetscFunctionBegin; 252963a3b9bcSJacob Faibussowitsch PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index); 2530998f007dSPierre Jolivet PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 25314f572ea9SToby Isaac PetscAssertPointer(is, 3); 2532998f007dSPierre Jolivet { 2533998f007dSPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2534998f007dSPierre Jolivet PC_FieldSplitLink ilink = jac->head; 2535998f007dSPierre Jolivet PetscInt i = 0; 253663a3b9bcSJacob Faibussowitsch PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits); 2537998f007dSPierre Jolivet 2538998f007dSPierre Jolivet while (i < index) { 2539998f007dSPierre Jolivet ilink = ilink->next; 2540998f007dSPierre Jolivet ++i; 2541998f007dSPierre Jolivet } 25429566063dSJacob Faibussowitsch PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is)); 2543998f007dSPierre Jolivet } 25443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2545998f007dSPierre Jolivet } 2546998f007dSPierre Jolivet 254751f519a2SBarry Smith /*@ 254851f519a2SBarry Smith PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 254980670ca5SBarry Smith fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used. 255051f519a2SBarry Smith 2551c3339decSBarry Smith Logically Collective 255251f519a2SBarry Smith 255351f519a2SBarry Smith Input Parameters: 255451f519a2SBarry Smith + pc - the preconditioner context 255551f519a2SBarry Smith - bs - the block size 255651f519a2SBarry Smith 255751f519a2SBarry Smith Level: intermediate 255851f519a2SBarry Smith 255980670ca5SBarry Smith Note: 256080670ca5SBarry Smith If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields. 256180670ca5SBarry Smith 256260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 256351f519a2SBarry Smith @*/ 2564d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs) 2565d71ae5a4SJacob Faibussowitsch { 256651f519a2SBarry Smith PetscFunctionBegin; 25670700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2568c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, bs, 2); 2569cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs)); 25703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 257151f519a2SBarry Smith } 257251f519a2SBarry Smith 25730971522cSBarry Smith /*@C 2574f1580f4eSBarry Smith PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits 25750971522cSBarry Smith 2576c3339decSBarry Smith Collective 25770971522cSBarry Smith 25780971522cSBarry Smith Input Parameter: 25790971522cSBarry Smith . pc - the preconditioner context 25800971522cSBarry Smith 25810971522cSBarry Smith Output Parameters: 258213e0d083SBarry Smith + n - the number of splits 2583f1580f4eSBarry Smith - subksp - the array of `KSP` contexts 2584196cc216SBarry Smith 25850971522cSBarry Smith Level: advanced 25860971522cSBarry Smith 2587f1580f4eSBarry Smith Notes: 2588f1580f4eSBarry Smith After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2589f1580f4eSBarry Smith (not the `KSP`, just the array that contains them). 2590f1580f4eSBarry Smith 2591f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`. 2592f1580f4eSBarry Smith 2593f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the 2594f1580f4eSBarry Smith Schur complement and the `KSP` object used to iterate over the Schur complement. 2595f1580f4eSBarry Smith To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`. 2596f1580f4eSBarry Smith 2597f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the 2598f1580f4eSBarry Smith inner linear system defined by the matrix H in each loop. 2599f1580f4eSBarry Smith 2600feaf08eaSBarry Smith Fortran Note: 2601e41f517fSBarry Smith Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed 2602f1580f4eSBarry Smith 2603feefa0e1SJacob Faibussowitsch Developer Notes: 2604f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2605f1580f4eSBarry Smith 260660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()` 26070971522cSBarry Smith @*/ 2608d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2609d71ae5a4SJacob Faibussowitsch { 26100971522cSBarry Smith PetscFunctionBegin; 26110700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 26124f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2); 2613cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 26143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 26150971522cSBarry Smith } 26160971522cSBarry Smith 2617285fb4e2SStefano Zampini /*@C 2618f1580f4eSBarry Smith PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT` 2619285fb4e2SStefano Zampini 262060f59c3bSBarry Smith Collective 2621285fb4e2SStefano Zampini 2622285fb4e2SStefano Zampini Input Parameter: 2623285fb4e2SStefano Zampini . pc - the preconditioner context 2624285fb4e2SStefano Zampini 2625285fb4e2SStefano Zampini Output Parameters: 2626285fb4e2SStefano Zampini + n - the number of splits 2627f1580f4eSBarry Smith - subksp - the array of `KSP` contexts 2628285fb4e2SStefano Zampini 2629285fb4e2SStefano Zampini Level: advanced 2630285fb4e2SStefano Zampini 2631f1580f4eSBarry Smith Notes: 2632f1580f4eSBarry Smith After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2633f1580f4eSBarry Smith (not the `KSP` just the array that contains them). 2634f1580f4eSBarry Smith 2635f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`. 2636f1580f4eSBarry Smith 2637f1580f4eSBarry Smith If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order) 2638f1580f4eSBarry Smith + 1 - the `KSP` used for the (1,1) block 2639f1580f4eSBarry Smith . 2 - the `KSP` used for the Schur complement (not the one used for the interior Schur solver) 2640f1580f4eSBarry Smith - 3 - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block). 2641f1580f4eSBarry Smith 2642f1580f4eSBarry Smith It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`. 2643f1580f4eSBarry Smith 2644feaf08eaSBarry Smith Fortran Note: 2645e41f517fSBarry Smith Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed 2646f1580f4eSBarry Smith 2647f1580f4eSBarry Smith Developer Notes: 2648f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2649f1580f4eSBarry Smith 2650f1580f4eSBarry Smith Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged? 2651f1580f4eSBarry Smith 265260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()` 2653285fb4e2SStefano Zampini @*/ 2654d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2655d71ae5a4SJacob Faibussowitsch { 2656285fb4e2SStefano Zampini PetscFunctionBegin; 2657285fb4e2SStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 26584f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2); 2659cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 26603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2661285fb4e2SStefano Zampini } 2662285fb4e2SStefano Zampini 2663e69d4d44SBarry Smith /*@ 2664c14e9f00SDavid Andrs PCFieldSplitSetSchurPre - Indicates from what operator the preconditioner is constructed for the Schur complement. 2665a1e3cbf9SBarry Smith The default is the A11 matrix. 2666e69d4d44SBarry Smith 2667c3339decSBarry Smith Collective 2668e69d4d44SBarry Smith 2669e69d4d44SBarry Smith Input Parameters: 2670e69d4d44SBarry Smith + pc - the preconditioner context 2671f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default), 2672f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`, 2673f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL` 267460f59c3bSBarry Smith - pre - matrix to use for preconditioning, or `NULL` 2675084e4875SJed Brown 2676f1580f4eSBarry Smith Options Database Keys: 2677d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments 2678a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator 2679e69d4d44SBarry Smith 268060f59c3bSBarry Smith Level: intermediate 268160f59c3bSBarry Smith 2682fd1303e9SJungho Lee Notes: 2683f1580f4eSBarry Smith If ptype is 2684f1580f4eSBarry Smith + a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner 2685f1580f4eSBarry Smith matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix 2686f1580f4eSBarry Smith . self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix: 2687e7593814SPierre Jolivet The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM` 2688f1580f4eSBarry Smith . user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument 2689f1580f4eSBarry Smith to this function). 2690a077d33dSBarry Smith . selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $ 2691f1580f4eSBarry Smith This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be 2692d59693daSPierre Jolivet lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump` 2693f1580f4eSBarry Smith - full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation 2694f1580f4eSBarry Smith computed internally by `PCFIELDSPLIT` (this is expensive) 2695f1580f4eSBarry Smith useful mostly as a test that the Schur complement approach can work for your problem 2696fd1303e9SJungho Lee 2697d59693daSPierre Jolivet When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense 2698a077d33dSBarry Smith with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and 2699d59693daSPierre Jolivet `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement. 2700fd1303e9SJungho Lee 2701a077d33dSBarry Smith Developer Note: 2702a077d33dSBarry Smith The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere. 2703feefa0e1SJacob Faibussowitsch 2704a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, 2705a077d33dSBarry Smith `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()` 2706e69d4d44SBarry Smith @*/ 2707d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2708d71ae5a4SJacob Faibussowitsch { 2709e69d4d44SBarry Smith PetscFunctionBegin; 27100700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2711cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre)); 27123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2713e69d4d44SBarry Smith } 2714686bed4dSStefano Zampini 2715d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2716d71ae5a4SJacob Faibussowitsch { 27179371c9d4SSatish Balay return PCFieldSplitSetSchurPre(pc, ptype, pre); 27189371c9d4SSatish Balay } /* Deprecated name */ 2719e69d4d44SBarry Smith 272037a82bf0SJed Brown /*@ 272137a82bf0SJed Brown PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be 2722f1580f4eSBarry Smith preconditioned. See `PCFieldSplitSetSchurPre()` for details. 272337a82bf0SJed Brown 2724c3339decSBarry Smith Logically Collective 272537a82bf0SJed Brown 2726f899ff85SJose E. Roman Input Parameter: 272737a82bf0SJed Brown . pc - the preconditioner context 272837a82bf0SJed Brown 272937a82bf0SJed Brown Output Parameters: 2730d59693daSPierre 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` 2731d59693daSPierre Jolivet - pre - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL` 273237a82bf0SJed Brown 273337a82bf0SJed Brown Level: intermediate 273437a82bf0SJed Brown 2735d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC` 273637a82bf0SJed Brown @*/ 2737d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2738d71ae5a4SJacob Faibussowitsch { 273937a82bf0SJed Brown PetscFunctionBegin; 274037a82bf0SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2741cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre)); 27423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2743e69d4d44SBarry Smith } 2744e69d4d44SBarry Smith 274545e7fc46SDmitry Karpeev /*@ 2746f1580f4eSBarry Smith PCFieldSplitSchurGetS - extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately 274745e7fc46SDmitry Karpeev 274820f4b53cSBarry Smith Not Collective 274945e7fc46SDmitry Karpeev 275045e7fc46SDmitry Karpeev Input Parameter: 275145e7fc46SDmitry Karpeev . pc - the preconditioner context 275245e7fc46SDmitry Karpeev 275345e7fc46SDmitry Karpeev Output Parameter: 2754470b340bSDmitry Karpeev . S - the Schur complement matrix 275545e7fc46SDmitry Karpeev 275660f59c3bSBarry Smith Level: advanced 275760f59c3bSBarry Smith 2758f1580f4eSBarry Smith Note: 2759f1580f4eSBarry Smith This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`. 276045e7fc46SDmitry Karpeev 276160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`, 2762f1580f4eSBarry Smith `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()` 276345e7fc46SDmitry Karpeev @*/ 2764d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S) 2765d71ae5a4SJacob Faibussowitsch { 276645e7fc46SDmitry Karpeev const char *t; 276745e7fc46SDmitry Karpeev PetscBool isfs; 276845e7fc46SDmitry Karpeev PC_FieldSplit *jac; 276945e7fc46SDmitry Karpeev 277045e7fc46SDmitry Karpeev PetscFunctionBegin; 277145e7fc46SDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 27729566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 27739566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 277428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 277545e7fc46SDmitry Karpeev jac = (PC_FieldSplit *)pc->data; 277663a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 2777470b340bSDmitry Karpeev if (S) *S = jac->schur; 27783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 277945e7fc46SDmitry Karpeev } 278045e7fc46SDmitry Karpeev 2781470b340bSDmitry Karpeev /*@ 2782f1580f4eSBarry Smith PCFieldSplitSchurRestoreS - returns the `MATSCHURCOMPLEMENT` matrix used by this `PC` 2783470b340bSDmitry Karpeev 278420f4b53cSBarry Smith Not Collective 2785470b340bSDmitry Karpeev 2786470b340bSDmitry Karpeev Input Parameters: 2787470b340bSDmitry Karpeev + pc - the preconditioner context 2788a2b725a8SWilliam Gropp - S - the Schur complement matrix 2789470b340bSDmitry Karpeev 2790470b340bSDmitry Karpeev Level: advanced 2791470b340bSDmitry Karpeev 279260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()` 2793470b340bSDmitry Karpeev @*/ 2794d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S) 2795d71ae5a4SJacob Faibussowitsch { 2796470b340bSDmitry Karpeev const char *t; 2797470b340bSDmitry Karpeev PetscBool isfs; 2798470b340bSDmitry Karpeev PC_FieldSplit *jac; 2799470b340bSDmitry Karpeev 2800470b340bSDmitry Karpeev PetscFunctionBegin; 2801470b340bSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 28029566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 28039566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 280428b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 2805470b340bSDmitry Karpeev jac = (PC_FieldSplit *)pc->data; 280663a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 28077827d75bSBarry Smith PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten"); 28083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2809470b340bSDmitry Karpeev } 2810470b340bSDmitry Karpeev 2811d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2812d71ae5a4SJacob Faibussowitsch { 2813e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2814e69d4d44SBarry Smith 2815e69d4d44SBarry Smith PetscFunctionBegin; 2816084e4875SJed Brown jac->schurpre = ptype; 2817a7476a74SDmitry Karpeev if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) { 28189566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user)); 2819084e4875SJed Brown jac->schur_user = pre; 28209566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->schur_user)); 2821084e4875SJed Brown } 28223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2823e69d4d44SBarry Smith } 2824e69d4d44SBarry Smith 2825d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2826d71ae5a4SJacob Faibussowitsch { 282737a82bf0SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 282837a82bf0SJed Brown 282937a82bf0SJed Brown PetscFunctionBegin; 28306056e507SPierre Jolivet if (ptype) *ptype = jac->schurpre; 28316056e507SPierre Jolivet if (pre) *pre = jac->schur_user; 28323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 283337a82bf0SJed Brown } 283437a82bf0SJed Brown 2835ab1df9f5SJed Brown /*@ 28361d27aa22SBarry Smith PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note` 2837ab1df9f5SJed Brown 2838c3339decSBarry Smith Collective 2839ab1df9f5SJed Brown 2840ab1df9f5SJed Brown Input Parameters: 2841ab1df9f5SJed Brown + pc - the preconditioner context 2842f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default 2843ab1df9f5SJed Brown 2844f1580f4eSBarry Smith Options Database Key: 2845d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full` 2846ab1df9f5SJed Brown 2847ab1df9f5SJed Brown Level: intermediate 2848ab1df9f5SJed Brown 2849ab1df9f5SJed Brown Notes: 2850366f9a6aSPierre Jolivet The `full` factorization is 2851ab1df9f5SJed Brown 2852a077d33dSBarry Smith ```{math} 2853a077d33dSBarry Smith \left(\begin{array}{cc} A & B \\ 2854a077d33dSBarry Smith C & E \\ 2855a077d33dSBarry Smith \end{array}\right) = 2856366f9a6aSPierre Jolivet \left(\begin{array}{cc} I & 0 \\ 2857366f9a6aSPierre Jolivet C A^{-1} & I \\ 2858a077d33dSBarry Smith \end{array}\right) 2859a077d33dSBarry Smith \left(\begin{array}{cc} A & 0 \\ 2860a077d33dSBarry Smith 0 & S \\ 2861a077d33dSBarry Smith \end{array}\right) 2862a077d33dSBarry Smith \left(\begin{array}{cc} I & A^{-1}B \\ 2863a077d33dSBarry Smith 0 & I \\ 2864366f9a6aSPierre Jolivet \end{array}\right) = L D U, 2865a077d33dSBarry Smith ``` 2866a077d33dSBarry Smith 2867366f9a6aSPierre 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$, 2868366f9a6aSPierre Jolivet and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations, 2869a077d33dSBarry Smith thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`. 2870a077d33dSBarry Smith 2871a077d33dSBarry Smith If $A$ and $S$ are solved exactly 2872366f9a6aSPierre Jolivet + 1 - `full` factorization is a direct solver. 2873366f9a6aSPierre 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. 2874366f9a6aSPierre 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. 2875ab1df9f5SJed Brown 2876f1580f4eSBarry Smith If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner 28770ffb0e17SBarry 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. 28780ffb0e17SBarry Smith 2879366f9a6aSPierre Jolivet For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`. 28800ffb0e17SBarry Smith 2881366f9a6aSPierre 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$). 2882ab1df9f5SJed Brown 28831d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`, 2884a077d33dSBarry Smith [](sec_flexibleksp), `PCFieldSplitSetSchurPre()` 2885ab1df9f5SJed Brown @*/ 2886d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype) 2887d71ae5a4SJacob Faibussowitsch { 2888ab1df9f5SJed Brown PetscFunctionBegin; 2889ab1df9f5SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2890cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype)); 28913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2892ab1df9f5SJed Brown } 2893ab1df9f5SJed Brown 2894d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype) 2895d71ae5a4SJacob Faibussowitsch { 2896ab1df9f5SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2897ab1df9f5SJed Brown 2898ab1df9f5SJed Brown PetscFunctionBegin; 2899ab1df9f5SJed Brown jac->schurfactorization = ftype; 29003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2901ab1df9f5SJed Brown } 2902ab1df9f5SJed Brown 2903c096484dSStefano Zampini /*@ 2904f1580f4eSBarry Smith PCFieldSplitSetSchurScale - Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`. 2905c096484dSStefano Zampini 2906c3339decSBarry Smith Collective 2907c096484dSStefano Zampini 2908c096484dSStefano Zampini Input Parameters: 2909c096484dSStefano Zampini + pc - the preconditioner context 2910c096484dSStefano Zampini - scale - scaling factor for the Schur complement 2911c096484dSStefano Zampini 2912f1580f4eSBarry Smith Options Database Key: 29131d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0 2914c096484dSStefano Zampini 2915c096484dSStefano Zampini Level: intermediate 2916c096484dSStefano Zampini 291742747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()` 2918c096484dSStefano Zampini @*/ 2919d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale) 2920d71ae5a4SJacob Faibussowitsch { 2921c096484dSStefano Zampini PetscFunctionBegin; 2922c096484dSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2923c096484dSStefano Zampini PetscValidLogicalCollectiveScalar(pc, scale, 2); 2924cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale)); 29253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2926c096484dSStefano Zampini } 2927c096484dSStefano Zampini 2928d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale) 2929d71ae5a4SJacob Faibussowitsch { 2930c096484dSStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2931c096484dSStefano Zampini 2932c096484dSStefano Zampini PetscFunctionBegin; 2933c096484dSStefano Zampini jac->schurscale = scale; 29343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2935c096484dSStefano Zampini } 2936c096484dSStefano Zampini 293730ad9308SMatthew Knepley /*@C 29388c03b21aSDmitry Karpeev PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 293930ad9308SMatthew Knepley 2940c3339decSBarry Smith Collective 294130ad9308SMatthew Knepley 294230ad9308SMatthew Knepley Input Parameter: 294330ad9308SMatthew Knepley . pc - the preconditioner context 294430ad9308SMatthew Knepley 294530ad9308SMatthew Knepley Output Parameters: 2946a04f6461SBarry Smith + A00 - the (0,0) block 2947a04f6461SBarry Smith . A01 - the (0,1) block 2948a04f6461SBarry Smith . A10 - the (1,0) block 2949a04f6461SBarry Smith - A11 - the (1,1) block 295030ad9308SMatthew Knepley 295130ad9308SMatthew Knepley Level: advanced 295230ad9308SMatthew Knepley 29535d83a8b1SBarry Smith Note: 29545d83a8b1SBarry Smith Use `NULL` for any unneeded output arguments 29555d83a8b1SBarry Smith 295660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()` 295730ad9308SMatthew Knepley @*/ 2958d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11) 2959d71ae5a4SJacob Faibussowitsch { 296030ad9308SMatthew Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 296130ad9308SMatthew Knepley 296230ad9308SMatthew Knepley PetscFunctionBegin; 29630700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 296408401ef6SPierre Jolivet PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 2965a04f6461SBarry Smith if (A00) *A00 = jac->pmat[0]; 2966a04f6461SBarry Smith if (A01) *A01 = jac->B; 2967a04f6461SBarry Smith if (A10) *A10 = jac->C; 2968a04f6461SBarry Smith if (A11) *A11 = jac->pmat[1]; 29693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 297030ad9308SMatthew Knepley } 297130ad9308SMatthew Knepley 2972b09e027eSCarola Kruse /*@ 29731d27aa22SBarry Smith PCFieldSplitSetGKBTol - Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 2974b09e027eSCarola Kruse 2975c3339decSBarry Smith Collective 2976e071a0a4SCarola Kruse 2977b09e027eSCarola Kruse Input Parameters: 2978b09e027eSCarola Kruse + pc - the preconditioner context 2979b09e027eSCarola Kruse - tolerance - the solver tolerance 2980b09e027eSCarola Kruse 2981f1580f4eSBarry Smith Options Database Key: 29821d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5 2983b09e027eSCarola Kruse 2984b09e027eSCarola Kruse Level: intermediate 2985b09e027eSCarola Kruse 2986f1580f4eSBarry Smith Note: 29871d27aa22SBarry Smith The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion. 2988f1580f4eSBarry Smith It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than 29891d27aa22SBarry Smith this estimate, the stopping criterion is satisfactory in practical cases. 2990f1580f4eSBarry Smith 299160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()` 2992b09e027eSCarola Kruse @*/ 2993d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance) 2994d71ae5a4SJacob Faibussowitsch { 2995b09e027eSCarola Kruse PetscFunctionBegin; 2996b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2997de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, tolerance, 2); 2998cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance)); 29993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3000b09e027eSCarola Kruse } 3001b09e027eSCarola Kruse 3002d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance) 3003d71ae5a4SJacob Faibussowitsch { 3004b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3005b09e027eSCarola Kruse 3006b09e027eSCarola Kruse PetscFunctionBegin; 3007b09e027eSCarola Kruse jac->gkbtol = tolerance; 30083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3009b09e027eSCarola Kruse } 3010b09e027eSCarola Kruse 3011b09e027eSCarola Kruse /*@ 301280670ca5SBarry Smith PCFieldSplitSetGKBMaxit - Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 3013b09e027eSCarola Kruse 3014c3339decSBarry Smith Collective 3015b09e027eSCarola Kruse 3016b09e027eSCarola Kruse Input Parameters: 3017b09e027eSCarola Kruse + pc - the preconditioner context 3018b09e027eSCarola Kruse - maxit - the maximum number of iterations 3019b09e027eSCarola Kruse 3020f1580f4eSBarry Smith Options Database Key: 30211d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100 3022b09e027eSCarola Kruse 3023b09e027eSCarola Kruse Level: intermediate 3024b09e027eSCarola Kruse 302560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()` 3026b09e027eSCarola Kruse @*/ 3027d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit) 3028d71ae5a4SJacob Faibussowitsch { 3029b09e027eSCarola Kruse PetscFunctionBegin; 3030b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3031de482cd7SCarola Kruse PetscValidLogicalCollectiveInt(pc, maxit, 2); 3032cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit)); 30333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3034b09e027eSCarola Kruse } 3035b09e027eSCarola Kruse 3036d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit) 3037d71ae5a4SJacob Faibussowitsch { 3038b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3039b09e027eSCarola Kruse 3040b09e027eSCarola Kruse PetscFunctionBegin; 3041b09e027eSCarola Kruse jac->gkbmaxit = maxit; 30423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3043b09e027eSCarola Kruse } 3044b09e027eSCarola Kruse 3045b09e027eSCarola Kruse /*@ 30461d27aa22SBarry Smith PCFieldSplitSetGKBDelay - Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT` 3047e071a0a4SCarola Kruse preconditioner. 3048b09e027eSCarola Kruse 3049c3339decSBarry Smith Collective 3050b09e027eSCarola Kruse 3051b09e027eSCarola Kruse Input Parameters: 3052b09e027eSCarola Kruse + pc - the preconditioner context 3053b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate 3054b09e027eSCarola Kruse 3055f1580f4eSBarry Smith Options Database Key: 30561d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5 3057b09e027eSCarola Kruse 3058b09e027eSCarola Kruse Level: intermediate 3059b09e027eSCarola Kruse 30601d27aa22SBarry Smith Notes: 30611d27aa22SBarry 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 $ 30621d27aa22SBarry 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 30631d27aa22SBarry Smith at least (`delay` + 1) iterations to stop. 3064f1580f4eSBarry Smith 30651d27aa22SBarry Smith For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013` 3066f1580f4eSBarry Smith 306760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 3068b09e027eSCarola Kruse @*/ 3069d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay) 3070d71ae5a4SJacob Faibussowitsch { 3071b09e027eSCarola Kruse PetscFunctionBegin; 3072b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3073b09e027eSCarola Kruse PetscValidLogicalCollectiveInt(pc, delay, 2); 3074cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay)); 30753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3076b09e027eSCarola Kruse } 3077b09e027eSCarola Kruse 3078d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay) 3079d71ae5a4SJacob Faibussowitsch { 3080b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3081b09e027eSCarola Kruse 3082b09e027eSCarola Kruse PetscFunctionBegin; 3083b09e027eSCarola Kruse jac->gkbdelay = delay; 30843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3085b09e027eSCarola Kruse } 3086b09e027eSCarola Kruse 3087b09e027eSCarola Kruse /*@ 30881d27aa22SBarry Smith PCFieldSplitSetGKBNu - Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the 30891d27aa22SBarry Smith Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 3090b09e027eSCarola Kruse 3091c3339decSBarry Smith Collective 3092f1580f4eSBarry Smith 3093f1580f4eSBarry Smith Input Parameters: 3094f1580f4eSBarry Smith + pc - the preconditioner context 3095f1580f4eSBarry Smith - nu - the shift parameter 3096f1580f4eSBarry Smith 309720f4b53cSBarry Smith Options Database Key: 30981d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1 3099f1580f4eSBarry Smith 3100f1580f4eSBarry Smith Level: intermediate 3101b09e027eSCarola Kruse 3102b09e027eSCarola Kruse Notes: 31031d27aa22SBarry 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, 31041d27aa22SBarry 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 3105b09e027eSCarola Kruse necessary to find a good balance in between the convergence of the inner and outer loop. 3106b09e027eSCarola Kruse 31071d27aa22SBarry 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. 3108b09e027eSCarola Kruse 310960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 3110b09e027eSCarola Kruse @*/ 3111d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu) 3112d71ae5a4SJacob Faibussowitsch { 3113b09e027eSCarola Kruse PetscFunctionBegin; 3114b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3115de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, nu, 2); 3116cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu)); 31173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3118b09e027eSCarola Kruse } 3119b09e027eSCarola Kruse 3120d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu) 3121d71ae5a4SJacob Faibussowitsch { 3122b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3123b09e027eSCarola Kruse 3124b09e027eSCarola Kruse PetscFunctionBegin; 3125b09e027eSCarola Kruse jac->gkbnu = nu; 31263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3127b09e027eSCarola Kruse } 3128b09e027eSCarola Kruse 3129d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type) 3130d71ae5a4SJacob Faibussowitsch { 313179416396SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 313279416396SBarry Smith 313379416396SBarry Smith PetscFunctionBegin; 313479416396SBarry Smith jac->type = type; 31352e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 31362e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 31372e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 31382e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 31392e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 31402e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 31412e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 31422e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 31432e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 3144e071a0a4SCarola Kruse 31453b224e63SBarry Smith if (type == PC_COMPOSITE_SCHUR) { 31463b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit_Schur; 31477b665727SPierre Jolivet pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur; 3148*d484b384SBoris Martin pc->ops->matapply = NULL; 31493b224e63SBarry Smith pc->ops->view = PCView_FieldSplit_Schur; 315073716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_Schur; 31512fa5cd67SKarl Rupp 31529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur)); 31539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit)); 31549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit)); 31559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit)); 31569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit)); 3157a51937d4SCarola Kruse } else if (type == PC_COMPOSITE_GKB) { 3158a51937d4SCarola Kruse pc->ops->apply = PCApply_FieldSplit_GKB; 31597ff38633SStefano Zampini pc->ops->applytranspose = NULL; 3160*d484b384SBoris Martin pc->ops->matapply = NULL; 3161a51937d4SCarola Kruse pc->ops->view = PCView_FieldSplit_GKB; 316273716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_GKB; 3163e69d4d44SBarry Smith 31649566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 31659566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit)); 31669566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit)); 31679566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit)); 31689566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit)); 31693b224e63SBarry Smith } else { 31703b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit; 31717ff38633SStefano Zampini pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 3172*d484b384SBoris Martin pc->ops->matapply = PCMatApply_FieldSplit; 31733b224e63SBarry Smith pc->ops->view = PCView_FieldSplit; 317473716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit; 31752fa5cd67SKarl Rupp 31769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 31773b224e63SBarry Smith } 31783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 317979416396SBarry Smith } 318079416396SBarry Smith 3181d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs) 3182d71ae5a4SJacob Faibussowitsch { 318351f519a2SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 318451f519a2SBarry Smith 318551f519a2SBarry Smith PetscFunctionBegin; 318663a3b9bcSJacob Faibussowitsch PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs); 31872472a847SBarry 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); 318851f519a2SBarry Smith jac->bs = bs; 31893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 319051f519a2SBarry Smith } 319151f519a2SBarry Smith 3192d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[]) 3193d71ae5a4SJacob Faibussowitsch { 31945ddf11f8SNicolas Barnafi PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 31955ddf11f8SNicolas Barnafi PC_FieldSplitLink ilink_current = jac->head; 31965ddf11f8SNicolas Barnafi IS is_owned; 31975ddf11f8SNicolas Barnafi 31985ddf11f8SNicolas Barnafi PetscFunctionBegin; 31995ddf11f8SNicolas Barnafi jac->coordinates_set = PETSC_TRUE; // Internal flag 3200f3fa974cSJacob Faibussowitsch PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL)); 32015ddf11f8SNicolas Barnafi 32025ddf11f8SNicolas Barnafi while (ilink_current) { 32035ddf11f8SNicolas Barnafi // For each IS, embed it to get local coords indces 32045ddf11f8SNicolas Barnafi IS is_coords; 32055ddf11f8SNicolas Barnafi PetscInt ndofs_block; 32065ddf11f8SNicolas Barnafi const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block 32075ddf11f8SNicolas Barnafi 32085ddf11f8SNicolas Barnafi // Setting drop to true for safety. It should make no difference. 32099566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords)); 32109566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(is_coords, &ndofs_block)); 32119566063dSJacob Faibussowitsch PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration)); 32125ddf11f8SNicolas Barnafi 32135ddf11f8SNicolas Barnafi // Allocate coordinates vector and set it directly 3214f4f49eeaSPierre Jolivet PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords)); 32155ddf11f8SNicolas Barnafi for (PetscInt dof = 0; dof < ndofs_block; ++dof) { 3216ad540459SPierre Jolivet for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d]; 32175ddf11f8SNicolas Barnafi } 32185ddf11f8SNicolas Barnafi ilink_current->dim = dim; 32195ddf11f8SNicolas Barnafi ilink_current->ndofs = ndofs_block; 32209566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration)); 32219566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_coords)); 32225ddf11f8SNicolas Barnafi ilink_current = ilink_current->next; 32235ddf11f8SNicolas Barnafi } 32249566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_owned)); 32253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 32265ddf11f8SNicolas Barnafi } 32275ddf11f8SNicolas Barnafi 3228bc08b0f1SBarry Smith /*@ 3229f1580f4eSBarry Smith PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 323079416396SBarry Smith 3231c3339decSBarry Smith Collective 323279416396SBarry Smith 3233d8d19677SJose E. Roman Input Parameters: 3234a2b725a8SWilliam Gropp + pc - the preconditioner context 3235a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, 3236a077d33dSBarry Smith `PC_COMPOSITE_GKB` 323779416396SBarry Smith 323879416396SBarry Smith Options Database Key: 32391d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 324079416396SBarry Smith 3241feefa0e1SJacob Faibussowitsch Level: intermediate 324279416396SBarry Smith 324360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 3244a077d33dSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()` 324579416396SBarry Smith @*/ 3246d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type) 3247d71ae5a4SJacob Faibussowitsch { 324879416396SBarry Smith PetscFunctionBegin; 32490700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3250cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type)); 32513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 325279416396SBarry Smith } 325379416396SBarry Smith 3254b02e2d75SMatthew G Knepley /*@ 3255f1580f4eSBarry Smith PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 3256b02e2d75SMatthew G Knepley 3257b02e2d75SMatthew G Knepley Not collective 3258b02e2d75SMatthew G Knepley 3259b02e2d75SMatthew G Knepley Input Parameter: 3260b02e2d75SMatthew G Knepley . pc - the preconditioner context 3261b02e2d75SMatthew G Knepley 3262b02e2d75SMatthew G Knepley Output Parameter: 3263f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 3264b02e2d75SMatthew G Knepley 3265feefa0e1SJacob Faibussowitsch Level: intermediate 3266b02e2d75SMatthew G Knepley 326760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 3268f1580f4eSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 3269b02e2d75SMatthew G Knepley @*/ 3270d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 3271d71ae5a4SJacob Faibussowitsch { 3272b02e2d75SMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3273b02e2d75SMatthew G Knepley 3274b02e2d75SMatthew G Knepley PetscFunctionBegin; 3275b02e2d75SMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 32764f572ea9SToby Isaac PetscAssertPointer(type, 2); 3277b02e2d75SMatthew G Knepley *type = jac->type; 32783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3279b02e2d75SMatthew G Knepley } 3280b02e2d75SMatthew G Knepley 32814ab8060aSDmitry Karpeev /*@ 3282f1580f4eSBarry Smith PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 32834ab8060aSDmitry Karpeev 3284c3339decSBarry Smith Logically Collective 32854ab8060aSDmitry Karpeev 32864ab8060aSDmitry Karpeev Input Parameters: 32874ab8060aSDmitry Karpeev + pc - the preconditioner context 3288f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM` 32894ab8060aSDmitry Karpeev 32904ab8060aSDmitry Karpeev Options Database Key: 3291f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM` 32924ab8060aSDmitry Karpeev 3293feefa0e1SJacob Faibussowitsch Level: intermediate 32944ab8060aSDmitry Karpeev 329573ff1848SBarry Smith Developer Note: 329673ff1848SBarry Smith The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database 329773ff1848SBarry Smith 3298f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 32994ab8060aSDmitry Karpeev @*/ 3300d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg) 3301d71ae5a4SJacob Faibussowitsch { 33024ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 33034ab8060aSDmitry Karpeev PetscBool isfs; 33044ab8060aSDmitry Karpeev 33054ab8060aSDmitry Karpeev PetscFunctionBegin; 33064ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 33074ab8060aSDmitry Karpeev PetscValidLogicalCollectiveBool(pc, flg, 2); 33089566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 3309ad540459SPierre Jolivet if (isfs) jac->dm_splits = flg; 33103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33114ab8060aSDmitry Karpeev } 33124ab8060aSDmitry Karpeev 33134ab8060aSDmitry Karpeev /*@ 3314f1580f4eSBarry Smith PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 33154ab8060aSDmitry Karpeev 33164ab8060aSDmitry Karpeev Logically Collective 33174ab8060aSDmitry Karpeev 33184ab8060aSDmitry Karpeev Input Parameter: 33194ab8060aSDmitry Karpeev . pc - the preconditioner context 33204ab8060aSDmitry Karpeev 33214ab8060aSDmitry Karpeev Output Parameter: 3322f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM` 33234ab8060aSDmitry Karpeev 3324feefa0e1SJacob Faibussowitsch Level: intermediate 33254ab8060aSDmitry Karpeev 332673ff1848SBarry Smith Developer Note: 332773ff1848SBarry Smith The name should be `PCFieldSplitGetUseDMSplits()` 332873ff1848SBarry Smith 3329f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 33304ab8060aSDmitry Karpeev @*/ 3331d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg) 3332d71ae5a4SJacob Faibussowitsch { 33334ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 33344ab8060aSDmitry Karpeev PetscBool isfs; 33354ab8060aSDmitry Karpeev 33364ab8060aSDmitry Karpeev PetscFunctionBegin; 33374ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 33384f572ea9SToby Isaac PetscAssertPointer(flg, 2); 33399566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 33404ab8060aSDmitry Karpeev if (isfs) { 33414ab8060aSDmitry Karpeev if (flg) *flg = jac->dm_splits; 33424ab8060aSDmitry Karpeev } 33433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33444ab8060aSDmitry Karpeev } 33454ab8060aSDmitry Karpeev 33467b752e3dSPatrick Sanan /*@ 3347f1580f4eSBarry Smith PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 33487b752e3dSPatrick Sanan 33497b752e3dSPatrick Sanan Logically Collective 33507b752e3dSPatrick Sanan 33517b752e3dSPatrick Sanan Input Parameter: 33527b752e3dSPatrick Sanan . pc - the preconditioner context 33537b752e3dSPatrick Sanan 33547b752e3dSPatrick Sanan Output Parameter: 33557b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not 33567b752e3dSPatrick Sanan 3357feefa0e1SJacob Faibussowitsch Level: intermediate 33587b752e3dSPatrick Sanan 335960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()` 33607b752e3dSPatrick Sanan @*/ 3361d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg) 3362d71ae5a4SJacob Faibussowitsch { 33637b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 33647b752e3dSPatrick Sanan 33657b752e3dSPatrick Sanan PetscFunctionBegin; 33667b752e3dSPatrick Sanan *flg = jac->detect; 33673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33687b752e3dSPatrick Sanan } 33697b752e3dSPatrick Sanan 33707b752e3dSPatrick Sanan /*@ 3371f1580f4eSBarry Smith PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 33727b752e3dSPatrick Sanan 33737b752e3dSPatrick Sanan Logically Collective 33747b752e3dSPatrick Sanan 33757b752e3dSPatrick Sanan Input Parameter: 33767b752e3dSPatrick Sanan . pc - the preconditioner context 33777b752e3dSPatrick Sanan 33787b752e3dSPatrick Sanan Output Parameter: 33797b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not 33807b752e3dSPatrick Sanan 33817b752e3dSPatrick Sanan Options Database Key: 3382147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point 3383147403d9SBarry Smith 3384feefa0e1SJacob Faibussowitsch Level: intermediate 338560f59c3bSBarry Smith 3386f1580f4eSBarry Smith Note: 3387f1580f4eSBarry 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()`). 33887b752e3dSPatrick Sanan 338960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF` 33907b752e3dSPatrick Sanan @*/ 3391d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg) 3392d71ae5a4SJacob Faibussowitsch { 33937b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 33947b752e3dSPatrick Sanan 33957b752e3dSPatrick Sanan PetscFunctionBegin; 33967b752e3dSPatrick Sanan jac->detect = flg; 33977b752e3dSPatrick Sanan if (jac->detect) { 33989566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR)); 33999566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL)); 34007b752e3dSPatrick Sanan } 34013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34027b752e3dSPatrick Sanan } 34037b752e3dSPatrick Sanan 34040971522cSBarry Smith /*MC 3405a8c7a070SBarry Smith PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 34060b4b7b1cSBarry Smith collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable 34070b4b7b1cSBarry Smith represented on a grid, such as velocity, pressure, or temperature. 34080b4b7b1cSBarry Smith In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`. 34090b4b7b1cSBarry Smith See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details. 34100971522cSBarry Smith 341179416396SBarry Smith Options Database Keys: 3412de37d9f1SPatrick Sanan + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split 341381540f2fSBarry Smith . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 3414de37d9f1SPatrick Sanan been supplied explicitly by `-pc_fieldsplit_%d_fields` 341581540f2fSBarry Smith . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 341680670ca5SBarry Smith when the matrix is not of `MatType` `MATNEST` 3417a51937d4SCarola Kruse . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting 3418d59693daSPierre Jolivet . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`; see `PCFieldSplitSetSchurPre()` 34191d27aa22SBarry Smith . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using `-pc_fieldsplit_type schur`; 34201d27aa22SBarry Smith see `PCFieldSplitSetSchurFactType()` 342173ff1848SBarry Smith . -pc_fieldsplit_dm_splits <true,false> (default is true) - Whether to use `DMCreateFieldDecomposition()` for splits 3422fb6809a2SPatrick Sanan - -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver 342379416396SBarry Smith 3424de37d9f1SPatrick Sanan Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` . 3425de37d9f1SPatrick Sanan The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_` 342660f59c3bSBarry Smith For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields. 342760f59c3bSBarry Smith 342822399129SNuno Nobre To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC` 342922399129SNuno Nobre options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`. 343060f59c3bSBarry Smith 343160f59c3bSBarry Smith To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()` 343260f59c3bSBarry Smith and set the options directly on the resulting `KSP` object 343360f59c3bSBarry Smith 343460f59c3bSBarry Smith Level: intermediate 34355d4c12cdSJungho Lee 3436c8a0d604SMatthew G Knepley Notes: 343780670ca5SBarry Smith Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()` 3438f1580f4eSBarry Smith to define a split by an arbitrary collection of entries. 3439d32f9abdSBarry Smith 344073ff1848SBarry Smith If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports 344180670ca5SBarry 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, 3442de37d9f1SPatrick Sanan beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`, 3443d32f9abdSBarry Smith if this is not called the block size defaults to the blocksize of the second matrix passed 3444de37d9f1SPatrick Sanan to `KSPSetOperators()`/`PCSetOperators()`. 3445d32f9abdSBarry Smith 3446de37d9f1SPatrick Sanan For the Schur complement preconditioner if 3447de37d9f1SPatrick Sanan ```{math} 3448de37d9f1SPatrick Sanan J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right] 3449de37d9f1SPatrick Sanan ``` 3450e69d4d44SBarry Smith 3451de37d9f1SPatrick Sanan the preconditioner using `full` factorization is logically 3452de37d9f1SPatrick Sanan ```{math} 3453f820a28cSNuno 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] 3454de37d9f1SPatrick Sanan ``` 3455cee94454SNuno Nobre where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`. $S$ is the Schur complement 3456de37d9f1SPatrick Sanan ```{math} 3457223e5b4fSPatrick Sanan S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01} 3458de37d9f1SPatrick Sanan ``` 34597cbeddf0SNuno 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` 34607cbeddf0SNuno 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 34617cbeddf0SNuno Nobre 0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`. 3462d82b6cdfSNuno 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$. 3463de37d9f1SPatrick Sanan 3464de37d9f1SPatrick Sanan The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above, 3465de37d9f1SPatrick Sanan `diag` gives 3466de37d9f1SPatrick Sanan ```{math} 3467f820a28cSNuno Nobre \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\ 0 & -\text{ksp}(S) \end{array}\right] 3468de37d9f1SPatrick Sanan ``` 3469de37d9f1SPatrick 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 3470de37d9f1SPatrick Sanan can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of 3471de37d9f1SPatrick Sanan ```{math} 3472de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & 0 \\ A_{10} & S \end{array}\right] 3473de37d9f1SPatrick Sanan ``` 3474cee94454SNuno Nobre where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of 3475de37d9f1SPatrick Sanan ```{math} 3476de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ 0 & S \end{array}\right] 3477de37d9f1SPatrick Sanan ``` 3478de37d9f1SPatrick Sanan where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s. 3479de37d9f1SPatrick Sanan 3480de37d9f1SPatrick Sanan If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS` 348180670ca5SBarry Smith is used automatically for a second submatrix. 3482edf189efSBarry Smith 3483f1580f4eSBarry Smith The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1. 348480670ca5SBarry Smith Generally it should be used with the `MATAIJ` or `MATNEST` `MatType` 3485ff218e97SBarry Smith 348680670ca5SBarry Smith The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see, 34871d569b8fSBarry Smith for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`. 348880670ca5SBarry Smith One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers". 34890716a85fSBarry Smith 3490de37d9f1SPatrick Sanan See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`. 3491a6a584a2SBarry Smith 3492de37d9f1SPatrick Sanan The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the 3493de37d9f1SPatrick Sanan residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables. 3494a51937d4SCarola Kruse 3495de37d9f1SPatrick Sanan The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape 3496de37d9f1SPatrick Sanan ```{math} 3497de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right] 3498de37d9f1SPatrick Sanan ``` 34991d569b8fSBarry 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}'$. 3500de37d9f1SPatrick 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_`. 3501a51937d4SCarola Kruse 35020b4b7b1cSBarry Smith Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the 35030b4b7b1cSBarry Smith problem. But this nomenclature is not well-defined. 35040b4b7b1cSBarry Smith 350560f59c3bSBarry Smith Developer Note: 350660f59c3bSBarry Smith The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their 350760f59c3bSBarry Smith user API. 3508f1580f4eSBarry Smith 350960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`, 3510db781477SPatrick Sanan `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`, 3511db781477SPatrick Sanan `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`, 3512db781477SPatrick Sanan `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()` 35130971522cSBarry Smith M*/ 35140971522cSBarry Smith 3515d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) 3516d71ae5a4SJacob Faibussowitsch { 35170971522cSBarry Smith PC_FieldSplit *jac; 35180971522cSBarry Smith 35190971522cSBarry Smith PetscFunctionBegin; 35204dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&jac)); 35212fa5cd67SKarl Rupp 35220971522cSBarry Smith jac->bs = -1; 35233e197d65SBarry Smith jac->type = PC_COMPOSITE_MULTIPLICATIVE; 3524e6cab6aaSJed Brown jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 3525c9c6ffaaSJed Brown jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 3526c096484dSStefano Zampini jac->schurscale = -1.0; 3527fbe7908bSJed Brown jac->dm_splits = PETSC_TRUE; 3528a51937d4SCarola Kruse jac->gkbtol = 1e-5; 3529a51937d4SCarola Kruse jac->gkbdelay = 5; 3530a51937d4SCarola Kruse jac->gkbnu = 1; 3531a51937d4SCarola Kruse jac->gkbmaxit = 100; 353251f519a2SBarry Smith 35330971522cSBarry Smith pc->data = (void *)jac; 35340971522cSBarry Smith 35350971522cSBarry Smith pc->ops->setup = PCSetUp_FieldSplit; 3536574deadeSBarry Smith pc->ops->reset = PCReset_FieldSplit; 35370971522cSBarry Smith pc->ops->destroy = PCDestroy_FieldSplit; 35380971522cSBarry Smith pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 35390a545947SLisandro Dalcin pc->ops->applyrichardson = NULL; 35400971522cSBarry Smith 35419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit)); 35429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit)); 35439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit)); 35449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit)); 35459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit)); 35469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit)); 35479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit)); 35487ff38633SStefano Zampini 35497ff38633SStefano Zampini /* Initialize function pointers */ 35507ff38633SStefano Zampini PetscCall(PCFieldSplitSetType(pc, jac->type)); 35513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35520971522cSBarry Smith } 3553