1af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 2a80b646eSBarry Smith #include <petsc/private/kspimpl.h> /* This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/ 3d484b384SBoris Martin #include <petsc/private/matimpl.h> /* MatScatterDense_Private() for PCMatApply() */ 41e25c274SJed Brown #include <petscdm.h> 5f7cbcdf3SPierre Jolivet #include <petscdevice.h> 6f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA) 7f7cbcdf3SPierre Jolivet #include <petscdevice_cuda.h> 8f7cbcdf3SPierre Jolivet #endif 9f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP) 10f7cbcdf3SPierre Jolivet #include <petscdevice_hip.h> 11f7cbcdf3SPierre Jolivet #endif 120971522cSBarry Smith 130a545947SLisandro Dalcin const char *const PCFieldSplitSchurPreTypes[] = {"SELF", "SELFP", "A11", "USER", "FULL", "PCFieldSplitSchurPreType", "PC_FIELDSPLIT_SCHUR_PRE_", NULL}; 140a545947SLisandro Dalcin const char *const PCFieldSplitSchurFactTypes[] = {"DIAG", "LOWER", "UPPER", "FULL", "PCFieldSplitSchurFactType", "PC_FIELDSPLIT_SCHUR_FACT_", NULL}; 15c5d2311dSJed Brown 169df09d43SBarry Smith PetscLogEvent KSP_Solve_FS_0, KSP_Solve_FS_1, KSP_Solve_FS_S, KSP_Solve_FS_U, KSP_Solve_FS_L, KSP_Solve_FS_2, KSP_Solve_FS_3, KSP_Solve_FS_4; 179df09d43SBarry Smith 180971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 190971522cSBarry Smith struct _PC_FieldSplitLink { 2069a612a9SBarry Smith KSP ksp; 21443836d0SMatthew G Knepley Vec x, y, z; 22*f5b94327SPierre Jolivet Mat X, Y, Z; 23db4c96c1SJed Brown char *splitname; 240971522cSBarry Smith PetscInt nfields; 255d4c12cdSJungho Lee PetscInt *fields, *fields_col; 261b9fc7fcSBarry Smith VecScatter sctx; 27f5f0d762SBarry Smith IS is, is_col; 2851f519a2SBarry Smith PC_FieldSplitLink next, previous; 299df09d43SBarry Smith PetscLogEvent event; 305ddf11f8SNicolas Barnafi 315ddf11f8SNicolas Barnafi /* Used only when setting coordinates with PCSetCoordinates */ 325ddf11f8SNicolas Barnafi PetscInt dim; 335ddf11f8SNicolas Barnafi PetscInt ndofs; 345ddf11f8SNicolas Barnafi PetscReal *coords; 350971522cSBarry Smith }; 360971522cSBarry Smith 370971522cSBarry Smith typedef struct { 3868dd23aaSBarry Smith PCCompositeType type; 39ace3abfcSBarry Smith PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 40ace3abfcSBarry Smith PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */ 4130ad9308SMatthew Knepley PetscInt bs; /* Block size for IS and Mat structures */ 4230ad9308SMatthew Knepley PetscInt nsplits; /* Number of field divisions defined */ 4379416396SBarry Smith Vec *x, *y, w1, w2; 44519d70e2SJed Brown Mat *mat; /* The diagonal block for each split */ 45519d70e2SJed Brown Mat *pmat; /* The preconditioning diagonal block for each split */ 4630ad9308SMatthew Knepley Mat *Afield; /* The rows of the matrix associated with each split */ 47ace3abfcSBarry Smith PetscBool issetup; 482fa5cd67SKarl Rupp 4930ad9308SMatthew Knepley /* Only used when Schur complement preconditioning is used */ 5030ad9308SMatthew Knepley Mat B; /* The (0,1) block */ 5130ad9308SMatthew Knepley Mat C; /* The (1,0) block */ 52443836d0SMatthew G Knepley Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */ 537addb90fSBarry Smith Mat schurp; /* Assembled approximation to S built by MatSchurComplement to be used as a matrix for constructing the preconditioner when solving with S */ 547addb90fSBarry Smith Mat schur_user; /* User-provided matrix for constructing the preconditioner for the Schur complement */ 557addb90fSBarry Smith PCFieldSplitSchurPreType schurpre; /* Determines which matrix is used for the Schur complement */ 56c9c6ffaaSJed Brown PCFieldSplitSchurFactType schurfactorization; 5730ad9308SMatthew Knepley KSP kspschur; /* The solver for S */ 58443836d0SMatthew G Knepley KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */ 59c096484dSStefano Zampini PetscScalar schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */ 60c096484dSStefano Zampini 61a51937d4SCarola Kruse /* Only used when Golub-Kahan bidiagonalization preconditioning is used */ 62a51937d4SCarola Kruse Mat H; /* The modified matrix H = A00 + nu*A01*A01' */ 63a51937d4SCarola Kruse PetscReal gkbtol; /* Stopping tolerance for lower bound estimate */ 64a51937d4SCarola Kruse PetscInt gkbdelay; /* The delay window for the stopping criterion */ 65a51937d4SCarola Kruse PetscReal gkbnu; /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */ 66a51937d4SCarola Kruse PetscInt gkbmaxit; /* Maximum number of iterations for outer loop */ 67de482cd7SCarola Kruse PetscBool gkbmonitor; /* Monitor for gkb iterations and the lower bound error */ 68de482cd7SCarola Kruse PetscViewer gkbviewer; /* Viewer context for gkbmonitor */ 69e071a0a4SCarola Kruse Vec u, v, d, Hu; /* Work vectors for the GKB algorithm */ 70e071a0a4SCarola Kruse PetscScalar *vecz; /* Contains intermediate values, eg for lower bound */ 71a51937d4SCarola Kruse 7297bbdb24SBarry Smith PC_FieldSplitLink head; 736dbb499eSCian Wilson PetscBool isrestrict; /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */ 74c1570756SJed Brown PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */ 754ab8060aSDmitry Karpeev PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */ 76c84da90fSDmitry Karpeev PetscBool diag_use_amat; /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 77c84da90fSDmitry Karpeev PetscBool offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 787b752e3dSPatrick Sanan PetscBool detect; /* Whether to form 2-way split by finding zero diagonal entries */ 795ddf11f8SNicolas Barnafi PetscBool coordinates_set; /* Whether PCSetCoordinates has been called */ 800971522cSBarry Smith } PC_FieldSplit; 810971522cSBarry Smith 8216913363SBarry Smith /* 83f1580f4eSBarry Smith Note: 8495452b02SPatrick Sanan there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 8516913363SBarry Smith inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 8616913363SBarry Smith PC you could change this. 8716913363SBarry Smith */ 88084e4875SJed Brown 897addb90fSBarry Smith /* This helper is so that setting a user-provided matrix is orthogonal to choosing to use it. This way the 90084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 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 1336d484b384SBoris Martin /* 1337d484b384SBoris Martin PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS 1338d484b384SBoris Martin 1339d484b384SBoris Martin Input Parameters: 1340d484b384SBoris Martin + pc - the PC context 1341d484b384SBoris Martin - X - matrix to copy column-layout from 1342d484b384SBoris Martin 1343d484b384SBoris Martin Notes: 1344d484b384SBoris Martin If matrices already exist with correct column count, they are reused. 1345d484b384SBoris Martin If column count changed, old matrices are destroyed and new ones created. 1346d484b384SBoris Martin */ 1347d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X) 1348d484b384SBoris Martin { 1349d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1350d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head; 1351d484b384SBoris Martin PetscInt mx, Mx, my, My, N; 1352d484b384SBoris Martin 1353d484b384SBoris Martin PetscFunctionBegin; 1354d484b384SBoris Martin while (ilink) { 1355d484b384SBoris Martin /* check if reallocation needed (previous allocation with wrong column count) */ 1356d484b384SBoris Martin if (ilink->X) { 1357d484b384SBoris Martin PetscCall(MatGetSize(ilink->X, NULL, &N)); 1358d484b384SBoris Martin if (N != X->cmap->N) { 1359d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X)); 1360d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y)); 1361*f5b94327SPierre Jolivet PetscCall(MatDestroy(&ilink->Z)); 1362d484b384SBoris Martin } 1363d484b384SBoris Martin } 1364d484b384SBoris Martin /* create if needed */ 1365d484b384SBoris Martin if (!ilink->X) { 1366d484b384SBoris Martin VecType xtype, ytype; 1367d484b384SBoris Martin 1368d484b384SBoris Martin PetscCall(VecGetType(ilink->x, &xtype)); 1369d484b384SBoris Martin PetscCall(VecGetType(ilink->y, &ytype)); 1370d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->x, &mx)); 1371d484b384SBoris Martin PetscCall(VecGetSize(ilink->x, &Mx)); 1372d484b384SBoris Martin PetscCall(VecGetLocalSize(ilink->y, &my)); 1373d484b384SBoris Martin PetscCall(VecGetSize(ilink->y, &My)); 1374d484b384SBoris Martin /* use default lda */ 1375d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X)); 1376d484b384SBoris Martin PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y)); 1377d484b384SBoris Martin } 1378d484b384SBoris Martin ilink = ilink->next; 1379d484b384SBoris Martin } 1380d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS); 1381d484b384SBoris Martin } 1382d484b384SBoris Martin 1383*f5b94327SPierre Jolivet static PetscErrorCode PCMatApply_FieldSplit_Schur(PC pc, Mat X, Mat Y) 1384*f5b94327SPierre Jolivet { 1385*f5b94327SPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1386*f5b94327SPierre Jolivet PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1387*f5b94327SPierre Jolivet KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 1388*f5b94327SPierre Jolivet Mat AinvB = NULL; 1389*f5b94327SPierre Jolivet PetscInt N, P; 1390*f5b94327SPierre Jolivet 1391*f5b94327SPierre Jolivet PetscFunctionBegin; 1392*f5b94327SPierre Jolivet /* create working matrices with the correct number of columns */ 1393*f5b94327SPierre Jolivet PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X)); 1394*f5b94327SPierre Jolivet switch (jac->schurfactorization) { 1395*f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 1396*f5b94327SPierre Jolivet /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 1397*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD)); 1398*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD)); 1399*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1400*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y)); 1401*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1402*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1403*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1404*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 1405*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y)); 1406*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 1407*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1408*f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->Y, jac->schurscale)); 1409*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1410*f5b94327SPierre Jolivet break; 1411*f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 1412*f5b94327SPierre Jolivet /* [A00 0; A10 S], suitable for left preconditioning */ 1413*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD)); 1414*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1415*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y)); 1416*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1417*f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X)); 1418*f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->X, -1.0)); 1419*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD)); 1420*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1421*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1422*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 1423*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y)); 1424*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 1425*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1426*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1427*f5b94327SPierre Jolivet break; 1428*f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 1429*f5b94327SPierre Jolivet /* [A00 A01; 0 S], suitable for right preconditioning */ 1430*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD)); 1431*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1432*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 1433*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y)); 1434*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 1435*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1436*f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X)); 1437*f5b94327SPierre Jolivet PetscCall(MatScale(ilinkA->X, -1.0)); 1438*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, ADD_VALUES, SCATTER_FORWARD)); 1439*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1440*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1441*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y)); 1442*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1443*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1444*f5b94327SPierre Jolivet break; 1445*f5b94327SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_FULL: 1446*f5b94327SPierre Jolivet /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */ 1447*f5b94327SPierre Jolivet PetscCall(MatGetSize(jac->B, NULL, &P)); 1448*f5b94327SPierre Jolivet N = P; 1449*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD)); 1450*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL)); 1451*f5b94327SPierre Jolivet if (kspUpper == kspA) { 1452*f5b94327SPierre Jolivet PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB)); 1453*f5b94327SPierre Jolivet if (AinvB) { 1454*f5b94327SPierre Jolivet PetscCall(MatGetSize(AinvB, NULL, &N)); 1455*f5b94327SPierre Jolivet if (N > P) { // first time PCApply_FieldSplit_Schur() is called 1456*f5b94327SPierre Jolivet PetscMemType mtype; 1457*f5b94327SPierre Jolivet Mat C = NULL; 1458*f5b94327SPierre Jolivet PetscScalar *array; 1459*f5b94327SPierre Jolivet PetscInt m, M, q, Q, p; 1460*f5b94327SPierre Jolivet 1461*f5b94327SPierre Jolivet PetscCall(MatGetSize(jac->B, &M, NULL)); 1462*f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, &m, NULL)); 1463*f5b94327SPierre Jolivet PetscCall(MatGetSize(X, NULL, &Q)); 1464*f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(X, NULL, &q)); 1465*f5b94327SPierre Jolivet PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype)); 1466*f5b94327SPierre Jolivet if (N != P + Q) { 1467*f5b94327SPierre Jolivet Mat replace; 1468*f5b94327SPierre Jolivet 1469*f5b94327SPierre Jolivet PetscCall(MatGetLocalSize(jac->B, NULL, &p)); 1470*f5b94327SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) { 1471*f5b94327SPierre Jolivet PetscCall(PetscFree(array)); 1472*f5b94327SPierre Jolivet PetscCall(PetscMalloc1(m * (P + Q), &array)); 1473*f5b94327SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace)); 1474*f5b94327SPierre Jolivet } 1475*f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA) 1476*f5b94327SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) { 1477*f5b94327SPierre Jolivet PetscCallCUDA(cudaFree(array)); 1478*f5b94327SPierre Jolivet PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q))); 1479*f5b94327SPierre Jolivet PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace)); 1480*f5b94327SPierre Jolivet } 1481*f5b94327SPierre Jolivet #endif 1482*f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP) 1483*f5b94327SPierre Jolivet else if (PetscMemTypeHIP(mtype)) { 1484*f5b94327SPierre Jolivet PetscCallHIP(hipFree(array)); 1485*f5b94327SPierre Jolivet PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q))); 1486*f5b94327SPierre Jolivet PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace)); 1487*f5b94327SPierre Jolivet } 1488*f5b94327SPierre Jolivet #endif 1489*f5b94327SPierre Jolivet PetscCall(MatHeaderReplace(AinvB, &replace)); 1490*f5b94327SPierre Jolivet } 1491*f5b94327SPierre Jolivet if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C)); 1492*f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA) 1493*f5b94327SPierre Jolivet else if (PetscMemTypeCUDA(mtype)) PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C)); 1494*f5b94327SPierre Jolivet #endif 1495*f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP) 1496*f5b94327SPierre Jolivet else if (PetscMemTypeHIP(mtype)) PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C)); 1497*f5b94327SPierre Jolivet #endif 1498*f5b94327SPierre Jolivet PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array)); 1499*f5b94327SPierre Jolivet PetscCall(MatCopy(ilinkA->X, C, SAME_NONZERO_PATTERN)); 1500*f5b94327SPierre Jolivet PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user)); 1501*f5b94327SPierre Jolivet PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user)); 1502*f5b94327SPierre Jolivet PetscCall(MatCopy(C, ilinkA->Y, SAME_NONZERO_PATTERN)); // retrieve solutions as last columns of the composed Mat 1503*f5b94327SPierre Jolivet PetscCall(MatDestroy(&C)); 1504*f5b94327SPierre Jolivet } 1505*f5b94327SPierre Jolivet } 1506*f5b94327SPierre Jolivet } 1507*f5b94327SPierre Jolivet if (N == P) PetscCall(KSPMatSolve(kspLower, ilinkA->X, ilinkA->Y)); 1508*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL)); 1509*f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X)); 1510*f5b94327SPierre Jolivet PetscCall(MatScale(ilinkD->X, -1.0)); 1511*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD)); 1512*f5b94327SPierre Jolivet 1513*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1514*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 1515*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y)); 1516*f5b94327SPierre Jolivet PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 1517*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL)); 1518*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1519*f5b94327SPierre Jolivet 1520*f5b94327SPierre Jolivet if (kspUpper == kspA) { 1521*f5b94327SPierre Jolivet if (!AinvB) { 1522*f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->Y)); 1523*f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->X, -1.0, ilinkA->Y, SAME_NONZERO_PATTERN)); 1524*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1525*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y)); 1526*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1527*f5b94327SPierre Jolivet } else { 1528*f5b94327SPierre Jolivet PetscCall(MatMatMult(AinvB, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X)); 1529*f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->Y, 1.0, ilinkA->X, SAME_NONZERO_PATTERN)); 1530*f5b94327SPierre Jolivet } 1531*f5b94327SPierre Jolivet } else { 1532*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL)); 1533*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y)); 1534*f5b94327SPierre Jolivet PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X)); 1535*f5b94327SPierre Jolivet if (!ilinkA->Z) PetscCall(MatDuplicate(ilinkA->X, MAT_DO_NOT_COPY_VALUES, &ilinkA->Z)); 1536*f5b94327SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL)); 1537*f5b94327SPierre Jolivet PetscCall(KSPMatSolve(kspUpper, ilinkA->X, ilinkA->Z)); 1538*f5b94327SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL)); 1539*f5b94327SPierre Jolivet PetscCall(MatAXPY(ilinkA->Y, -1.0, ilinkA->Z, SAME_NONZERO_PATTERN)); 1540*f5b94327SPierre Jolivet } 1541*f5b94327SPierre Jolivet PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE)); 1542*f5b94327SPierre Jolivet } 1543*f5b94327SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 1544*f5b94327SPierre Jolivet } 1545*f5b94327SPierre Jolivet 15467b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y) 15477b665727SPierre Jolivet { 15487b665727SPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 15497b665727SPierre Jolivet PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 15507b665727SPierre Jolivet KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 15517b665727SPierre Jolivet 15527b665727SPierre Jolivet PetscFunctionBegin; 15537b665727SPierre Jolivet switch (jac->schurfactorization) { 15547b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 15557b665727SPierre Jolivet /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 15567b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 15577b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 15587b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 15597b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 15607b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 15617b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 15627b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 15637b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15647b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 15657b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1566e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 15677b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1568e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 15697b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 15707b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 15717b665727SPierre Jolivet PetscCall(VecScale(ilinkD->y, jac->schurscale)); 15727b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15737b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15747b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15757b665727SPierre Jolivet break; 15767b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 15777b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 15787b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 15797b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 15807b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 15817b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 15827b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 15837b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 15847b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.)); 15857b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 15867b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15877b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 15887b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1589e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 15907b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1591e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 15927b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 15937b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 15947b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15957b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15967b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 15977b665727SPierre Jolivet break; 15987b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 15997b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 16007b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 16017b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1602e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 16037b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1604e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 16057b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 16067b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 16077b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 16087b665727SPierre Jolivet PetscCall(VecScale(ilinkA->x, -1.)); 16097b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 16107b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16117b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD)); 16127b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 16137b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 16147b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 16157b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 16167b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16177b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16187b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16197b665727SPierre Jolivet break; 16207b665727SPierre Jolivet case PC_FIELDSPLIT_SCHUR_FACT_FULL: 16217b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 16227b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 16237b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 16247b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y)); 16257b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y)); 16267b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL)); 16277b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x)); 16287b665727SPierre Jolivet PetscCall(VecScale(ilinkD->x, -1.0)); 16297b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 16307b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD)); 16317b665727SPierre Jolivet 16327b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 1633e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1)); 16347b665727SPierre Jolivet PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y)); 1635e0b7e82fSBarry Smith PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1)); 16367b665727SPierre Jolivet PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y)); 16377b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL)); 16387b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16397b665727SPierre Jolivet 16407b665727SPierre Jolivet if (kspLower == kspA) { 16417b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y)); 16427b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y)); 16437b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 16447b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 16457b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 16467b665727SPierre Jolivet PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 16477b665727SPierre Jolivet } else { 16487b665727SPierre Jolivet PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL)); 16497b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y)); 16507b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y)); 16517b665727SPierre Jolivet PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x)); 16527b665727SPierre Jolivet PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 16537b665727SPierre Jolivet PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z)); 16547b665727SPierre Jolivet PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z)); 16557b665727SPierre Jolivet PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL)); 16567b665727SPierre Jolivet PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z)); 16577b665727SPierre Jolivet } 16587b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16597b665727SPierre Jolivet PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16607b665727SPierre Jolivet PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 16617b665727SPierre Jolivet } 16627b665727SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 16637b665727SPierre Jolivet } 16647b665727SPierre Jolivet 16655becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \ 16665becce15SPierre 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) || \ 16675becce15SPierre 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) || \ 16685becce15SPierre Jolivet VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE))) 16695becce15SPierre Jolivet 1670d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y) 1671d71ae5a4SJacob Faibussowitsch { 16720971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 16735a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head; 1674939b8a20SBarry Smith PetscInt cnt, bs; 16750971522cSBarry Smith 16760971522cSBarry Smith PetscFunctionBegin; 167779416396SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) { 167880670ca5SBarry Smith PetscBool matnest; 167980670ca5SBarry Smith 168080670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest)); 168180670ca5SBarry Smith if (jac->defaultsplit && !matnest) { 16829566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs)); 16832472a847SBarry 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); 16849566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs)); 16852472a847SBarry 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); 16869566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 16875a9f2f41SSatish Balay while (ilink) { 16889566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 16899566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 16909566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 16919566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 16925a9f2f41SSatish Balay ilink = ilink->next; 16930971522cSBarry Smith } 16949566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 16951b9fc7fcSBarry Smith } else { 16969566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 16975a9f2f41SSatish Balay while (ilink) { 16989566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 16995a9f2f41SSatish Balay ilink = ilink->next; 17001b9fc7fcSBarry Smith } 17011b9fc7fcSBarry Smith } 1702e52d2c62SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 17039566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 1704e52d2c62SBarry Smith /* solve on first block for first block variables */ 17059566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 17069566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD)); 17079566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17089566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 17099566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 17109566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17119566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 17129566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 1713e52d2c62SBarry Smith 1714e52d2c62SBarry Smith /* compute the residual only onto second block variables using first block variables */ 17159566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x)); 1716e52d2c62SBarry Smith ilink = ilink->next; 17179566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 17189566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 17199566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 1720e52d2c62SBarry Smith 1721e52d2c62SBarry Smith /* solve on second block variables */ 17229566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17239566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 17249566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 17259566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17269566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 17279566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 172816913363SBarry Smith } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 172979416396SBarry Smith if (!jac->w1) { 17309566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1)); 17319566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2)); 173279416396SBarry Smith } 17339566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 17349566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAdd(ilink, x, y)); 17353e197d65SBarry Smith cnt = 1; 17365a9f2f41SSatish Balay while (ilink->next) { 17375a9f2f41SSatish Balay ilink = ilink->next; 17383e197d65SBarry Smith /* compute the residual only over the part of the vector needed */ 17399566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x)); 17409566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 17419566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 17429566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 17439566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17449566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 17459566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 17469566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17479566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 17489566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 17493e197d65SBarry Smith } 175051f519a2SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 175111755939SBarry Smith cnt -= 2; 175251f519a2SBarry Smith while (ilink->previous) { 175351f519a2SBarry Smith ilink = ilink->previous; 175411755939SBarry Smith /* compute the residual only over the part of the vector needed */ 17559566063dSJacob Faibussowitsch PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x)); 17569566063dSJacob Faibussowitsch PetscCall(VecScale(ilink->x, -1.0)); 17579566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 17589566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD)); 17599566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17609566063dSJacob Faibussowitsch PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y)); 17619566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 17629566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 17639566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 17649566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE)); 176551f519a2SBarry Smith } 176611755939SBarry Smith } 176763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type); 17683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 17690971522cSBarry Smith } 17700971522cSBarry Smith 1771d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y) 1772d484b384SBoris Martin { 1773d484b384SBoris Martin PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1774d484b384SBoris Martin PC_FieldSplitLink ilink = jac->head; 1775d484b384SBoris Martin PetscInt cnt; 1776d484b384SBoris Martin 1777d484b384SBoris Martin PetscFunctionBegin; 1778d484b384SBoris Martin /* create working matrices with the correct number of columns */ 1779d484b384SBoris Martin PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X)); 1780d484b384SBoris Martin if (jac->type == PC_COMPOSITE_ADDITIVE) { 1781d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1782d484b384SBoris Martin while (ilink) { 1783d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1784d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1785d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1786d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1787d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1788d484b384SBoris Martin ilink = ilink->next; 1789d484b384SBoris Martin } 1790d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 1791d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1792d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1793d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1794d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1795d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1796d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1797d484b384SBoris Martin 1798d484b384SBoris Martin /* compute the residual only onto second block variables using first block variables */ 1799d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X)); 1800d484b384SBoris Martin ilink = ilink->next; 1801d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1802d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1803d484b384SBoris Martin 1804d484b384SBoris Martin /* solve on second block variables */ 1805d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1806d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1807d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1808d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1809d484b384SBoris Martin } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1810d484b384SBoris Martin /* general multiplicative with any number of splits */ 1811d484b384SBoris Martin PetscCall(MatZeroEntries(Y)); 1812d484b384SBoris Martin /* first split */ 1813d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD)); 1814d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1815d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1816d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1817d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1818d484b384SBoris Martin cnt = 1; 1819d484b384SBoris Martin /* forward sweep */ 1820d484b384SBoris Martin while (ilink->next) { 1821d484b384SBoris Martin ilink = ilink->next; 1822d484b384SBoris Martin /* compute the residual only over the part of the vector needed */ 1823d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X)); 1824d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1825d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1826d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1827d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1828d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1829d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1830d484b384SBoris Martin } 1831d484b384SBoris Martin /* backward sweep for symmetric multiplicative */ 1832d484b384SBoris Martin if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1833d484b384SBoris Martin cnt -= 2; 1834d484b384SBoris Martin while (ilink->previous) { 1835d484b384SBoris Martin ilink = ilink->previous; 1836d484b384SBoris Martin /* compute the residual only over the part of the vector needed */ 1837d484b384SBoris Martin PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X)); 1838d484b384SBoris Martin PetscCall(MatScale(ilink->X, -1.0)); 1839d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD)); 1840d484b384SBoris Martin PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1841d484b384SBoris Martin PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y)); 1842d484b384SBoris Martin PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL)); 1843d484b384SBoris Martin PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE)); 1844d484b384SBoris Martin } 1845d484b384SBoris Martin } 1846d484b384SBoris Martin } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type"); 1847d484b384SBoris Martin PetscFunctionReturn(PETSC_SUCCESS); 1848d484b384SBoris Martin } 1849d484b384SBoris Martin 1850d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y) 1851d71ae5a4SJacob Faibussowitsch { 1852a51937d4SCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1853a51937d4SCarola Kruse PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1854a51937d4SCarola Kruse KSP ksp = ilinkA->ksp; 1855de482cd7SCarola Kruse Vec u, v, Hu, d, work1, work2; 1856e071a0a4SCarola Kruse PetscScalar alpha, z, nrmz2, *vecz; 1857e071a0a4SCarola Kruse PetscReal lowbnd, nu, beta; 1858a51937d4SCarola Kruse PetscInt j, iterGKB; 1859a51937d4SCarola Kruse 1860a51937d4SCarola Kruse PetscFunctionBegin; 18619566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 18629566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 18639566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD)); 18649566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD)); 1865e071a0a4SCarola Kruse 1866e071a0a4SCarola Kruse u = jac->u; 1867e071a0a4SCarola Kruse v = jac->v; 1868e071a0a4SCarola Kruse Hu = jac->Hu; 1869e071a0a4SCarola Kruse d = jac->d; 1870e071a0a4SCarola Kruse work1 = jac->w1; 1871e071a0a4SCarola Kruse work2 = jac->w2; 1872e071a0a4SCarola Kruse vecz = jac->vecz; 1873a51937d4SCarola Kruse 1874a51937d4SCarola Kruse /* Change RHS to comply with matrix regularization H = A + nu*B*B' */ 1875a51937d4SCarola Kruse /* Add q = q + nu*B*b */ 1876a51937d4SCarola Kruse if (jac->gkbnu) { 1877a51937d4SCarola Kruse nu = jac->gkbnu; 18789566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->x, jac->gkbnu)); 18799566063dSJacob Faibussowitsch PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */ 1880a51937d4SCarola Kruse } else { 1881a51937d4SCarola Kruse /* Situation when no augmented Lagrangian is used. Then we set inner */ 1882a51937d4SCarola Kruse /* matrix N = I in [Ar13], and thus nu = 1. */ 1883a51937d4SCarola Kruse nu = 1; 1884a51937d4SCarola Kruse } 1885a51937d4SCarola Kruse 1886a51937d4SCarola Kruse /* Transform rhs from [q,tilde{b}] to [0,b] */ 18879566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 18889566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y)); 18899566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y)); 18909566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL)); 18919566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1)); 18929566063dSJacob Faibussowitsch PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x */ 1893a51937d4SCarola Kruse 1894a51937d4SCarola Kruse /* First step of algorithm */ 18959566063dSJacob Faibussowitsch PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/ 1896e071a0a4SCarola Kruse KSPCheckDot(ksp, beta); 1897addd1e01SJunchao Zhang beta = PetscSqrtReal(nu) * beta; 18989566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c */ 18999566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u = H^{-1}*B*v */ 19009566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 19019566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u)); 19029566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u)); 19039566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 19049566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 19059566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha)); 1906e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha); 190708401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1908addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 19099566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha)); 19109566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c */ 1911de482cd7SCarola Kruse 1912a51937d4SCarola Kruse z = beta / alpha; 1913a51937d4SCarola Kruse vecz[1] = z; 1914a51937d4SCarola Kruse 1915de482cd7SCarola Kruse /* Computation of first iterate x(1) and p(1) */ 19169566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u)); 19179566063dSJacob Faibussowitsch PetscCall(VecCopy(d, ilinkD->y)); 19189566063dSJacob Faibussowitsch PetscCall(VecScale(ilinkD->y, -z)); 1919a51937d4SCarola Kruse 19209371c9d4SSatish Balay iterGKB = 1; 19219371c9d4SSatish Balay lowbnd = 2 * jac->gkbtol; 192248a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1923de482cd7SCarola Kruse 1924a51937d4SCarola Kruse while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) { 1925a51937d4SCarola Kruse iterGKB += 1; 19269566063dSJacob Faibussowitsch PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */ 19279566063dSJacob Faibussowitsch PetscCall(VecAXPBY(v, nu, -alpha, work1)); 19289566063dSJacob Faibussowitsch PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v */ 1929addd1e01SJunchao Zhang beta = beta / PetscSqrtReal(nu); 19309566063dSJacob Faibussowitsch PetscCall(VecScale(v, 1.0 / beta)); 19319566063dSJacob Faibussowitsch PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */ 19329566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); 19339566063dSJacob Faibussowitsch PetscCall(VecAXPY(work2, -beta, Hu)); 19349566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL)); 19359566063dSJacob Faibussowitsch PetscCall(KSPSolve(ksp, work2, u)); 19369566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ksp, pc, u)); 19379566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL)); 19389566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u */ 19399566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, u, &alpha)); 1940e071a0a4SCarola Kruse KSPCheckDot(ksp, alpha); 194108401ef6SPierre Jolivet PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite"); 1942addd1e01SJunchao Zhang alpha = PetscSqrtReal(PetscAbsScalar(alpha)); 19439566063dSJacob Faibussowitsch PetscCall(VecScale(u, 1.0 / alpha)); 1944a51937d4SCarola Kruse 1945e071a0a4SCarola Kruse z = -beta / alpha * z; /* z <- beta/alpha*z */ 1946a51937d4SCarola Kruse vecz[0] = z; 1947a51937d4SCarola Kruse 1948a51937d4SCarola Kruse /* Computation of new iterate x(i+1) and p(i+1) */ 19499566063dSJacob Faibussowitsch PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */ 19509566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkA->y, z, u)); /* r = r + z*u */ 19519566063dSJacob Faibussowitsch PetscCall(VecAXPY(ilinkD->y, -z, d)); /* p = p - z*d */ 19529566063dSJacob Faibussowitsch PetscCall(MatMult(jac->H, ilinkA->y, Hu)); /* ||u||_H = u'*H*u */ 19539566063dSJacob Faibussowitsch PetscCall(VecDot(Hu, ilinkA->y, &nrmz2)); 1954a51937d4SCarola Kruse 1955a51937d4SCarola Kruse /* Compute Lower Bound estimate */ 1956a51937d4SCarola Kruse if (iterGKB > jac->gkbdelay) { 1957a51937d4SCarola Kruse lowbnd = 0.0; 1958ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]); 1959addd1e01SJunchao Zhang lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2)); 1960a51937d4SCarola Kruse } 1961a51937d4SCarola Kruse 1962ad540459SPierre Jolivet for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2]; 196348a46eb9SPierre Jolivet if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd)); 1964a51937d4SCarola Kruse } 1965a51937d4SCarola Kruse 19669566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 19679566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE)); 19689566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 19699566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE)); 19703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1971a51937d4SCarola Kruse } 1972a51937d4SCarola Kruse 1973421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \ 19743ba16761SJacob 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) || \ 19759371c9d4SSatish 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) || \ 19763ba16761SJacob Faibussowitsch VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE))) 1977421e10b8SBarry Smith 1978d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y) 1979d71ae5a4SJacob Faibussowitsch { 1980421e10b8SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 1981421e10b8SBarry Smith PC_FieldSplitLink ilink = jac->head; 1982939b8a20SBarry Smith PetscInt bs; 1983421e10b8SBarry Smith 1984421e10b8SBarry Smith PetscFunctionBegin; 1985421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_ADDITIVE) { 198680670ca5SBarry Smith PetscBool matnest; 198780670ca5SBarry Smith 198880670ca5SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest)); 198980670ca5SBarry Smith if (jac->defaultsplit && !matnest) { 19909566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(x, &bs)); 19912472a847SBarry 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); 19929566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(y, &bs)); 19932472a847SBarry 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); 19949566063dSJacob Faibussowitsch PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES)); 1995421e10b8SBarry Smith while (ilink) { 19969566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 19979566063dSJacob Faibussowitsch PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y)); 19989566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y)); 19999566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL)); 2000421e10b8SBarry Smith ilink = ilink->next; 2001421e10b8SBarry Smith } 20029566063dSJacob Faibussowitsch PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES)); 2003421e10b8SBarry Smith } else { 20049566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 2005421e10b8SBarry Smith while (ilink) { 20069566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 2007421e10b8SBarry Smith ilink = ilink->next; 2008421e10b8SBarry Smith } 2009421e10b8SBarry Smith } 2010421e10b8SBarry Smith } else { 2011421e10b8SBarry Smith if (!jac->w1) { 20129566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w1)); 20139566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &jac->w2)); 2014421e10b8SBarry Smith } 20159566063dSJacob Faibussowitsch PetscCall(VecSet(y, 0.0)); 2016421e10b8SBarry Smith if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 20179566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 2018421e10b8SBarry Smith while (ilink->next) { 2019421e10b8SBarry Smith ilink = ilink->next; 20209566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 20219566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 20229566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 2023421e10b8SBarry Smith } 2024421e10b8SBarry Smith while (ilink->previous) { 2025421e10b8SBarry Smith ilink = ilink->previous; 20269566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 20279566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 20289566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 2029421e10b8SBarry Smith } 2030421e10b8SBarry Smith } else { 2031421e10b8SBarry Smith while (ilink->next) { /* get to last entry in linked list */ 2032421e10b8SBarry Smith ilink = ilink->next; 2033421e10b8SBarry Smith } 20349566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y)); 2035421e10b8SBarry Smith while (ilink->previous) { 2036421e10b8SBarry Smith ilink = ilink->previous; 20379566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(pc->mat, y, jac->w1)); 20389566063dSJacob Faibussowitsch PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x)); 20399566063dSJacob Faibussowitsch PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y)); 2040421e10b8SBarry Smith } 2041421e10b8SBarry Smith } 2042421e10b8SBarry Smith } 20433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2044421e10b8SBarry Smith } 2045421e10b8SBarry Smith 2046d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc) 2047d71ae5a4SJacob Faibussowitsch { 20480971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 20495a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head, next; 20500971522cSBarry Smith 20510971522cSBarry Smith PetscFunctionBegin; 20525a9f2f41SSatish Balay while (ilink) { 20539566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&ilink->ksp)); 20549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->x)); 20559566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->y)); 20569566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ilink->z)); 2057d484b384SBoris Martin PetscCall(MatDestroy(&ilink->X)); 2058d484b384SBoris Martin PetscCall(MatDestroy(&ilink->Y)); 2059*f5b94327SPierre Jolivet PetscCall(MatDestroy(&ilink->Z)); 20609566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&ilink->sctx)); 20619566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 20629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 20639566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->splitname)); 20649566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields)); 20659566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink->fields_col)); 20665a9f2f41SSatish Balay next = ilink->next; 20679566063dSJacob Faibussowitsch PetscCall(PetscFree(ilink)); 20685a9f2f41SSatish Balay ilink = next; 20690971522cSBarry Smith } 2070f5f0d762SBarry Smith jac->head = NULL; 20719566063dSJacob Faibussowitsch PetscCall(PetscFree2(jac->x, jac->y)); 2072574deadeSBarry Smith if (jac->mat && jac->mat != jac->pmat) { 20739566063dSJacob Faibussowitsch PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat)); 2074574deadeSBarry Smith } else if (jac->mat) { 20750298fd71SBarry Smith jac->mat = NULL; 2076574deadeSBarry Smith } 20779566063dSJacob Faibussowitsch if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat)); 20789566063dSJacob Faibussowitsch if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield)); 2079f5f0d762SBarry Smith jac->nsplits = 0; 20809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w1)); 20819566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->w2)); 208273716367SStefano Zampini if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL)); 20839566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur)); 20849566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schurp)); 20859566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user)); 20869566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspschur)); 20879566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&jac->kspupper)); 20889566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->B)); 20899566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->C)); 20909566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->H)); 20919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->u)); 20929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->v)); 20939566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->Hu)); 20949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&jac->d)); 20959566063dSJacob Faibussowitsch PetscCall(PetscFree(jac->vecz)); 20969566063dSJacob Faibussowitsch PetscCall(PetscViewerDestroy(&jac->gkbviewer)); 20976dbb499eSCian Wilson jac->isrestrict = PETSC_FALSE; 20983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2099574deadeSBarry Smith } 2100574deadeSBarry Smith 2101d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc) 2102d71ae5a4SJacob Faibussowitsch { 2103574deadeSBarry Smith PetscFunctionBegin; 21049566063dSJacob Faibussowitsch PetscCall(PCReset_FieldSplit(pc)); 21059566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 21062e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL)); 21079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL)); 21089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL)); 21099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL)); 21109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL)); 21112e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL)); 21122e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL)); 21132e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 21142e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 21152e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 21162e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 21172e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 21189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 21199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 21209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 21212e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 21223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21230971522cSBarry Smith } 21240971522cSBarry Smith 2125ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject) 2126d71ae5a4SJacob Faibussowitsch { 21276c924f48SJed Brown PetscInt bs; 21287b752e3dSPatrick Sanan PetscBool flg; 21299dcbbd2bSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 21303b224e63SBarry Smith PCCompositeType ctype; 21311b9fc7fcSBarry Smith 21320971522cSBarry Smith PetscFunctionBegin; 2133d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options"); 21349566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL)); 21359566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg)); 21361baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs)); 21372686e3e9SMatthew G. Knepley jac->diag_use_amat = pc->useAmat; 21389566063dSJacob 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)); 21392686e3e9SMatthew G. Knepley jac->offdiag_use_amat = pc->useAmat; 21409566063dSJacob 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)); 21419566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL)); 21429566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */ 21439566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg)); 21441baa6e33SBarry Smith if (flg) PetscCall(PCFieldSplitSetType(pc, ctype)); 2145c30613efSMatthew Knepley /* Only setup fields once */ 2146b6555650SPierre Jolivet if (jac->bs > 0 && jac->nsplits == 0) { 214780670ca5SBarry Smith /* only allow user to set fields from command line. 2148d32f9abdSBarry Smith otherwise user can set them in PCFieldSplitSetDefaults() */ 21499566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc)); 21509566063dSJacob Faibussowitsch if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n")); 2151d32f9abdSBarry Smith } 2152c5d2311dSJed Brown if (jac->type == PC_COMPOSITE_SCHUR) { 21539566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg)); 21549566063dSJacob Faibussowitsch if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n")); 21559566063dSJacob 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)); 21569566063dSJacob Faibussowitsch PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL)); 21579566063dSJacob Faibussowitsch PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL)); 2158a51937d4SCarola Kruse } else if (jac->type == PC_COMPOSITE_GKB) { 2159a077d33dSBarry Smith PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL)); 2160a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL)); 2161a077d33dSBarry Smith PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0)); 2162a077d33dSBarry Smith PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL)); 21639566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL)); 2164c5d2311dSJed Brown } 216534603f55SBarry Smith /* 216634603f55SBarry Smith In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet. 216734603f55SBarry 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 216834603f55SBarry Smith is called on the outer solver in case changes were made in the options database 216934603f55SBarry Smith 217034603f55SBarry 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() 217134603f55SBarry 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. 217234603f55SBarry Smith Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types. 217334603f55SBarry Smith 217434603f55SBarry Smith There could be a negative side effect of calling the KSPSetFromOptions() below. 217534603f55SBarry Smith 217634603f55SBarry 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 217734603f55SBarry Smith */ 217834603f55SBarry Smith if (jac->issetup) { 217934603f55SBarry Smith PC_FieldSplitLink ilink = jac->head; 218034603f55SBarry Smith if (jac->type == PC_COMPOSITE_SCHUR) { 218134603f55SBarry Smith if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper)); 218234603f55SBarry Smith if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur)); 218334603f55SBarry Smith } 218434603f55SBarry Smith while (ilink) { 218534603f55SBarry Smith if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp)); 218634603f55SBarry Smith ilink = ilink->next; 218734603f55SBarry Smith } 218834603f55SBarry Smith } 2189d0609cedSBarry Smith PetscOptionsHeadEnd(); 21903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21910971522cSBarry Smith } 21920971522cSBarry Smith 2193d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) 2194d71ae5a4SJacob Faibussowitsch { 219597bbdb24SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 21965a9f2f41SSatish Balay PC_FieldSplitLink ilink, next = jac->head; 219769a612a9SBarry Smith char prefix[128]; 21985d4c12cdSJungho Lee PetscInt i; 2199835f2295SStefano Zampini PetscLogEvent nse; 22000971522cSBarry Smith 22010971522cSBarry Smith PetscFunctionBegin; 22026c924f48SJed Brown if (jac->splitdefined) { 22039566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 22043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22056c924f48SJed Brown } 2206ac530a7eSPierre 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]); 22079566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink)); 2208a04f6461SBarry Smith if (splitname) { 22099566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 2210a04f6461SBarry Smith } else { 22119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3, &ilink->splitname)); 221263a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits)); 2213a04f6461SBarry Smith } 2214835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse)); 2215835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */ 22169566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields)); 22179566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields, fields, n)); 22189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &ilink->fields_col)); 22199566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n)); 22202fa5cd67SKarl Rupp 22215a9f2f41SSatish Balay ilink->nfields = n; 22220298fd71SBarry Smith ilink->next = NULL; 22239566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 22243821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 22259566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 22269566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 22279566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 222869a612a9SBarry Smith 22299566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 22309566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 22310971522cSBarry Smith 22320971522cSBarry Smith if (!next) { 22335a9f2f41SSatish Balay jac->head = ilink; 22340298fd71SBarry Smith ilink->previous = NULL; 22350971522cSBarry Smith } else { 2236ad540459SPierre Jolivet while (next->next) next = next->next; 22375a9f2f41SSatish Balay next->next = ilink; 223851f519a2SBarry Smith ilink->previous = next; 22390971522cSBarry Smith } 22400971522cSBarry Smith jac->nsplits++; 22413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22420971522cSBarry Smith } 22430971522cSBarry Smith 2244d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 2245d71ae5a4SJacob Faibussowitsch { 2246285fb4e2SStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2247285fb4e2SStefano Zampini 2248285fb4e2SStefano Zampini PetscFunctionBegin; 2249285fb4e2SStefano Zampini *subksp = NULL; 2250285fb4e2SStefano Zampini if (n) *n = 0; 2251285fb4e2SStefano Zampini if (jac->type == PC_COMPOSITE_SCHUR) { 2252285fb4e2SStefano Zampini PetscInt nn; 2253285fb4e2SStefano Zampini 225428b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()"); 225563a3b9bcSJacob Faibussowitsch PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits); 2256285fb4e2SStefano Zampini nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0); 22579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nn, subksp)); 2258285fb4e2SStefano Zampini (*subksp)[0] = jac->head->ksp; 2259285fb4e2SStefano Zampini (*subksp)[1] = jac->kspschur; 2260285fb4e2SStefano Zampini if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper; 2261285fb4e2SStefano Zampini if (n) *n = nn; 2262285fb4e2SStefano Zampini } 22633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2264285fb4e2SStefano Zampini } 2265285fb4e2SStefano Zampini 2266d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp) 2267d71ae5a4SJacob Faibussowitsch { 2268e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2269e69d4d44SBarry Smith 2270e69d4d44SBarry Smith PetscFunctionBegin; 227128b400f6SJacob Faibussowitsch PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()"); 22729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp)); 22739566063dSJacob Faibussowitsch PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp)); 22742fa5cd67SKarl Rupp 2275e69d4d44SBarry Smith (*subksp)[1] = jac->kspschur; 227613e0d083SBarry Smith if (n) *n = jac->nsplits; 22773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2278e69d4d44SBarry Smith } 22790971522cSBarry Smith 2280d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) 2281d71ae5a4SJacob Faibussowitsch { 22820971522cSBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 22830971522cSBarry Smith PetscInt cnt = 0; 22845a9f2f41SSatish Balay PC_FieldSplitLink ilink = jac->head; 22850971522cSBarry Smith 22860971522cSBarry Smith PetscFunctionBegin; 22879566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(jac->nsplits, subksp)); 22885a9f2f41SSatish Balay while (ilink) { 22895a9f2f41SSatish Balay (*subksp)[cnt++] = ilink->ksp; 22905a9f2f41SSatish Balay ilink = ilink->next; 22910971522cSBarry Smith } 229263a3b9bcSJacob 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); 229313e0d083SBarry Smith if (n) *n = jac->nsplits; 22943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22950971522cSBarry Smith } 22960971522cSBarry Smith 2297cc4c1da9SBarry Smith /*@ 2298f1580f4eSBarry Smith PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`. 22996dbb499eSCian Wilson 23006dbb499eSCian Wilson Input Parameters: 23016dbb499eSCian Wilson + pc - the preconditioner context 2302feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted 23036dbb499eSCian Wilson 23046dbb499eSCian Wilson Level: advanced 23056dbb499eSCian Wilson 2306feefa0e1SJacob Faibussowitsch Developer Notes: 2307f1580f4eSBarry Smith It seems the resulting `IS`s will not cover the entire space, so 2308f1580f4eSBarry Smith how can they define a convergent preconditioner? Needs explaining. 2309f1580f4eSBarry Smith 231060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 23116dbb499eSCian Wilson @*/ 2312d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy) 2313d71ae5a4SJacob Faibussowitsch { 23146dbb499eSCian Wilson PetscFunctionBegin; 23156dbb499eSCian Wilson PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 23166dbb499eSCian Wilson PetscValidHeaderSpecific(isy, IS_CLASSID, 2); 2317cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy)); 23183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23196dbb499eSCian Wilson } 23206dbb499eSCian Wilson 2321d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) 2322d71ae5a4SJacob Faibussowitsch { 23236dbb499eSCian Wilson PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 23246dbb499eSCian Wilson PC_FieldSplitLink ilink = jac->head, next; 23256dbb499eSCian Wilson PetscInt localsize, size, sizez, i; 23266dbb499eSCian Wilson const PetscInt *ind, *indz; 23276dbb499eSCian Wilson PetscInt *indc, *indcz; 23286dbb499eSCian Wilson PetscBool flg; 23296dbb499eSCian Wilson 23306dbb499eSCian Wilson PetscFunctionBegin; 23319566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isy, &localsize)); 23329566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy))); 23336dbb499eSCian Wilson size -= localsize; 23346dbb499eSCian Wilson while (ilink) { 23356dbb499eSCian Wilson IS isrl, isr; 23361c7cfba8SBarry Smith PC subpc; 23379566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl)); 23389566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isrl, &localsize)); 23399566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indc)); 23409566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isrl, &ind)); 23419566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indc, ind, localsize)); 23429566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isrl, &ind)); 23439566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isrl)); 23446dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indc + i) += size; 23459566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr)); 23469566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr)); 23479566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 23486dbb499eSCian Wilson ilink->is = isr; 23499566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)isr)); 23509566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 23516dbb499eSCian Wilson ilink->is_col = isr; 23529566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isr)); 23539566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ilink->ksp, &subpc)); 23549566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg)); 23556dbb499eSCian Wilson if (flg) { 23566dbb499eSCian Wilson IS iszl, isz; 23576dbb499eSCian Wilson MPI_Comm comm; 23589566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(ilink->is, &localsize)); 23596dbb499eSCian Wilson comm = PetscObjectComm((PetscObject)ilink->is); 23609566063dSJacob Faibussowitsch PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl)); 23619566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm)); 23626dbb499eSCian Wilson sizez -= localsize; 23639566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(iszl, &localsize)); 23649566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(localsize, &indcz)); 23659566063dSJacob Faibussowitsch PetscCall(ISGetIndices(iszl, &indz)); 23669566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(indcz, indz, localsize)); 23679566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(iszl, &indz)); 23689566063dSJacob Faibussowitsch PetscCall(ISDestroy(&iszl)); 23696dbb499eSCian Wilson for (i = 0; i < localsize; i++) *(indcz + i) += sizez; 23709566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz)); 23719566063dSJacob Faibussowitsch PetscCall(PCFieldSplitRestrictIS(subpc, isz)); 23729566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isz)); 23736dbb499eSCian Wilson } 23746dbb499eSCian Wilson next = ilink->next; 23756dbb499eSCian Wilson ilink = next; 23766dbb499eSCian Wilson } 23776dbb499eSCian Wilson jac->isrestrict = PETSC_TRUE; 23783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23796dbb499eSCian Wilson } 23806dbb499eSCian Wilson 2381d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is) 2382d71ae5a4SJacob Faibussowitsch { 2383704ba839SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2384704ba839SBarry Smith PC_FieldSplitLink ilink, next = jac->head; 2385704ba839SBarry Smith char prefix[128]; 2386835f2295SStefano Zampini PetscLogEvent nse; 2387704ba839SBarry Smith 2388704ba839SBarry Smith PetscFunctionBegin; 23896c924f48SJed Brown if (jac->splitdefined) { 23909566063dSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname)); 23913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23926c924f48SJed Brown } 23939566063dSJacob Faibussowitsch PetscCall(PetscNew(&ilink)); 2394a04f6461SBarry Smith if (splitname) { 23959566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(splitname, &ilink->splitname)); 2396a04f6461SBarry Smith } else { 23979566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(8, &ilink->splitname)); 239863a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits)); 2399a04f6461SBarry Smith } 2400835f2295SStefano Zampini PetscCall(PetscMPIIntCast(jac->nsplits, &nse)); 2401835f2295SStefano Zampini ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */ 24029566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is)); 24039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is)); 2404b5787286SJed Brown ilink->is = is; 24059566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is)); 24069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&ilink->is_col)); 2407b5787286SJed Brown ilink->is_col = is; 24080298fd71SBarry Smith ilink->next = NULL; 24099566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp)); 24103821be0aSBarry Smith PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel)); 24119566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure)); 24129566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1)); 24139566063dSJacob Faibussowitsch PetscCall(KSPSetType(ilink->ksp, KSPPREONLY)); 2414704ba839SBarry Smith 24159566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname)); 24169566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix)); 2417704ba839SBarry Smith 2418704ba839SBarry Smith if (!next) { 2419704ba839SBarry Smith jac->head = ilink; 24200298fd71SBarry Smith ilink->previous = NULL; 2421704ba839SBarry Smith } else { 2422ad540459SPierre Jolivet while (next->next) next = next->next; 2423704ba839SBarry Smith next->next = ilink; 2424704ba839SBarry Smith ilink->previous = next; 2425704ba839SBarry Smith } 2426704ba839SBarry Smith jac->nsplits++; 24273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2428704ba839SBarry Smith } 2429704ba839SBarry Smith 24305d83a8b1SBarry Smith /*@ 243160f59c3bSBarry Smith PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT` 24320971522cSBarry Smith 2433c3339decSBarry Smith Logically Collective 24340971522cSBarry Smith 24350971522cSBarry Smith Input Parameters: 24360971522cSBarry Smith + pc - the preconditioner context 243760f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used 24380971522cSBarry Smith . n - the number of fields in this split 24393b374dbdSBarry Smith . fields - the fields in this split 244080670ca5SBarry 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 244180670ca5SBarry Smith of the matrix and `fields_col` provides the column indices for that block 244280670ca5SBarry Smith 244380670ca5SBarry Smith Options Database Key: 244480670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split 24450971522cSBarry Smith 24460971522cSBarry Smith Level: intermediate 24470971522cSBarry Smith 244895452b02SPatrick Sanan Notes: 2449f1580f4eSBarry Smith Use `PCFieldSplitSetIS()` to set a general set of indices as a split. 2450d32f9abdSBarry Smith 245180670ca5SBarry Smith If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`. 245280670ca5SBarry Smith 245380670ca5SBarry Smith If the matrix used to construct the preconditioner is not `MATNEST` then 245454c05997SPierre Jolivet `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or 245580670ca5SBarry Smith to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block 2456f1580f4eSBarry 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 245714c74629SNuno Nobre 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x.... 2458f1580f4eSBarry Smith where the numbered entries indicate what is in the split. 2459d32f9abdSBarry Smith 2460db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options 246160f59c3bSBarry Smith for this split will be available under the prefix `-fieldsplit_SPLITNAME_`. 2462db4c96c1SJed Brown 246380670ca5SBarry Smith `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields` 24643b374dbdSBarry Smith 2465feefa0e1SJacob Faibussowitsch Developer Notes: 2466f1580f4eSBarry Smith This routine does not actually create the `IS` representing the split, that is delayed 2467f1580f4eSBarry Smith until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be 24685d4c12cdSJungho Lee available when this routine is called. 24695d4c12cdSJungho Lee 247080670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`, 247154c05997SPierre Jolivet `MatSetBlockSize()`, `MatCreateNest()` 24720971522cSBarry Smith @*/ 2473cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[]) 2474d71ae5a4SJacob Faibussowitsch { 24750971522cSBarry Smith PetscFunctionBegin; 24760700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 24774f572ea9SToby Isaac PetscAssertPointer(splitname, 2); 247863a3b9bcSJacob Faibussowitsch PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname); 24794f572ea9SToby Isaac PetscAssertPointer(fields, 4); 2480cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col)); 24813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 24820971522cSBarry Smith } 24830971522cSBarry Smith 2484c84da90fSDmitry Karpeev /*@ 2485f1580f4eSBarry Smith PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2486c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2487c84da90fSDmitry Karpeev 2488c3339decSBarry Smith Logically Collective 2489c84da90fSDmitry Karpeev 2490c84da90fSDmitry Karpeev Input Parameters: 2491c84da90fSDmitry Karpeev + pc - the preconditioner object 2492c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2493c84da90fSDmitry Karpeev 249420f4b53cSBarry Smith Options Database Key: 2495147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks 2496c84da90fSDmitry Karpeev 2497c84da90fSDmitry Karpeev Level: intermediate 2498c84da90fSDmitry Karpeev 249960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT` 2500c84da90fSDmitry Karpeev @*/ 2501d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg) 2502d71ae5a4SJacob Faibussowitsch { 2503c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2504c84da90fSDmitry Karpeev PetscBool isfs; 2505c84da90fSDmitry Karpeev 2506c84da90fSDmitry Karpeev PetscFunctionBegin; 2507c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 25089566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 250928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2510c84da90fSDmitry Karpeev jac->diag_use_amat = flg; 25113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2512c84da90fSDmitry Karpeev } 2513c84da90fSDmitry Karpeev 2514c84da90fSDmitry Karpeev /*@ 2515f1580f4eSBarry Smith PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build 2516c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2517c84da90fSDmitry Karpeev 2518c3339decSBarry Smith Logically Collective 2519c84da90fSDmitry Karpeev 252020f4b53cSBarry Smith Input Parameter: 2521c84da90fSDmitry Karpeev . pc - the preconditioner object 2522c84da90fSDmitry Karpeev 252320f4b53cSBarry Smith Output Parameter: 2524c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 2525c84da90fSDmitry Karpeev 2526c84da90fSDmitry Karpeev Level: intermediate 2527c84da90fSDmitry Karpeev 252860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT` 2529c84da90fSDmitry Karpeev @*/ 2530d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg) 2531d71ae5a4SJacob Faibussowitsch { 2532c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2533c84da90fSDmitry Karpeev PetscBool isfs; 2534c84da90fSDmitry Karpeev 2535c84da90fSDmitry Karpeev PetscFunctionBegin; 2536c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 25374f572ea9SToby Isaac PetscAssertPointer(flg, 2); 25389566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 253928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2540c84da90fSDmitry Karpeev *flg = jac->diag_use_amat; 25413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2542c84da90fSDmitry Karpeev } 2543c84da90fSDmitry Karpeev 2544c84da90fSDmitry Karpeev /*@ 2545f1580f4eSBarry Smith PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2546c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2547c84da90fSDmitry Karpeev 2548c3339decSBarry Smith Logically Collective 2549c84da90fSDmitry Karpeev 2550c84da90fSDmitry Karpeev Input Parameters: 2551c84da90fSDmitry Karpeev + pc - the preconditioner object 2552c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2553c84da90fSDmitry Karpeev 255420f4b53cSBarry Smith Options Database Key: 2555147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks 2556c84da90fSDmitry Karpeev 2557c84da90fSDmitry Karpeev Level: intermediate 2558c84da90fSDmitry Karpeev 255960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT` 2560c84da90fSDmitry Karpeev @*/ 2561d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg) 2562d71ae5a4SJacob Faibussowitsch { 2563c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2564c84da90fSDmitry Karpeev PetscBool isfs; 2565c84da90fSDmitry Karpeev 2566c84da90fSDmitry Karpeev PetscFunctionBegin; 2567c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 25689566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 256928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2570c84da90fSDmitry Karpeev jac->offdiag_use_amat = flg; 25713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2572c84da90fSDmitry Karpeev } 2573c84da90fSDmitry Karpeev 2574c84da90fSDmitry Karpeev /*@ 2575f1580f4eSBarry Smith PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build 2576c14e9f00SDavid Andrs the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators. 2577c84da90fSDmitry Karpeev 2578c3339decSBarry Smith Logically Collective 2579c84da90fSDmitry Karpeev 258020f4b53cSBarry Smith Input Parameter: 2581c84da90fSDmitry Karpeev . pc - the preconditioner object 2582c84da90fSDmitry Karpeev 258320f4b53cSBarry Smith Output Parameter: 2584c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2585c84da90fSDmitry Karpeev 2586c84da90fSDmitry Karpeev Level: intermediate 2587c84da90fSDmitry Karpeev 258860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT` 2589c84da90fSDmitry Karpeev @*/ 2590d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg) 2591d71ae5a4SJacob Faibussowitsch { 2592c84da90fSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2593c84da90fSDmitry Karpeev PetscBool isfs; 2594c84da90fSDmitry Karpeev 2595c84da90fSDmitry Karpeev PetscFunctionBegin; 2596c84da90fSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 25974f572ea9SToby Isaac PetscAssertPointer(flg, 2); 25989566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 259928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT); 2600c84da90fSDmitry Karpeev *flg = jac->offdiag_use_amat; 26013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2602c84da90fSDmitry Karpeev } 2603c84da90fSDmitry Karpeev 2604cc4c1da9SBarry Smith /*@ 2605f1580f4eSBarry Smith PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT` 2606704ba839SBarry Smith 2607c3339decSBarry Smith Logically Collective 2608704ba839SBarry Smith 2609704ba839SBarry Smith Input Parameters: 2610704ba839SBarry Smith + pc - the preconditioner context 261160f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used 2612f1580f4eSBarry Smith - is - the index set that defines the elements in this split 2613704ba839SBarry Smith 261460f59c3bSBarry Smith Level: intermediate 261560f59c3bSBarry Smith 2616a6ffb8dbSJed Brown Notes: 261780670ca5SBarry Smith Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST` 2618a6ffb8dbSJed Brown 2619db4c96c1SJed Brown This function is called once per split (it creates a new split each time). Solve options 2620db4c96c1SJed Brown for this split will be available under the prefix -fieldsplit_SPLITNAME_. 2621d32f9abdSBarry Smith 262280670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()` 2623704ba839SBarry Smith @*/ 2624d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is) 2625d71ae5a4SJacob Faibussowitsch { 2626704ba839SBarry Smith PetscFunctionBegin; 26270700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 26284f572ea9SToby Isaac if (splitname) PetscAssertPointer(splitname, 2); 2629db4c96c1SJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 3); 2630cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is)); 26313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2632704ba839SBarry Smith } 2633704ba839SBarry Smith 2634cc4c1da9SBarry Smith /*@ 2635f1580f4eSBarry Smith PCFieldSplitGetIS - Retrieves the elements for a split as an `IS` 263657a9adfeSMatthew G Knepley 2637c3339decSBarry Smith Logically Collective 263857a9adfeSMatthew G Knepley 263957a9adfeSMatthew G Knepley Input Parameters: 264057a9adfeSMatthew G Knepley + pc - the preconditioner context 264157a9adfeSMatthew G Knepley - splitname - name of this split 264257a9adfeSMatthew G Knepley 264357a9adfeSMatthew G Knepley Output Parameter: 2644feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found 264557a9adfeSMatthew G Knepley 264657a9adfeSMatthew G Knepley Level: intermediate 264757a9adfeSMatthew G Knepley 264880670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()` 264957a9adfeSMatthew G Knepley @*/ 2650d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is) 2651d71ae5a4SJacob Faibussowitsch { 265257a9adfeSMatthew G Knepley PetscFunctionBegin; 265357a9adfeSMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 26544f572ea9SToby Isaac PetscAssertPointer(splitname, 2); 26554f572ea9SToby Isaac PetscAssertPointer(is, 3); 265657a9adfeSMatthew G Knepley { 265757a9adfeSMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 265857a9adfeSMatthew G Knepley PC_FieldSplitLink ilink = jac->head; 265957a9adfeSMatthew G Knepley PetscBool found; 266057a9adfeSMatthew G Knepley 26610298fd71SBarry Smith *is = NULL; 266257a9adfeSMatthew G Knepley while (ilink) { 26639566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(ilink->splitname, splitname, &found)); 266457a9adfeSMatthew G Knepley if (found) { 266557a9adfeSMatthew G Knepley *is = ilink->is; 266657a9adfeSMatthew G Knepley break; 266757a9adfeSMatthew G Knepley } 266857a9adfeSMatthew G Knepley ilink = ilink->next; 266957a9adfeSMatthew G Knepley } 267057a9adfeSMatthew G Knepley } 26713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 267257a9adfeSMatthew G Knepley } 267357a9adfeSMatthew G Knepley 2674cc4c1da9SBarry Smith /*@ 2675f1580f4eSBarry Smith PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS` 2676998f007dSPierre Jolivet 2677c3339decSBarry Smith Logically Collective 2678998f007dSPierre Jolivet 2679998f007dSPierre Jolivet Input Parameters: 2680998f007dSPierre Jolivet + pc - the preconditioner context 2681998f007dSPierre Jolivet - index - index of this split 2682998f007dSPierre Jolivet 2683998f007dSPierre Jolivet Output Parameter: 2684feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split 2685998f007dSPierre Jolivet 2686998f007dSPierre Jolivet Level: intermediate 2687998f007dSPierre Jolivet 268880670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`, 268980670ca5SBarry Smith 2690998f007dSPierre Jolivet @*/ 2691d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is) 2692d71ae5a4SJacob Faibussowitsch { 2693998f007dSPierre Jolivet PetscFunctionBegin; 269463a3b9bcSJacob Faibussowitsch PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index); 2695998f007dSPierre Jolivet PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 26964f572ea9SToby Isaac PetscAssertPointer(is, 3); 2697998f007dSPierre Jolivet { 2698998f007dSPierre Jolivet PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2699998f007dSPierre Jolivet PC_FieldSplitLink ilink = jac->head; 2700998f007dSPierre Jolivet PetscInt i = 0; 270163a3b9bcSJacob Faibussowitsch PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits); 2702998f007dSPierre Jolivet 2703998f007dSPierre Jolivet while (i < index) { 2704998f007dSPierre Jolivet ilink = ilink->next; 2705998f007dSPierre Jolivet ++i; 2706998f007dSPierre Jolivet } 27079566063dSJacob Faibussowitsch PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is)); 2708998f007dSPierre Jolivet } 27093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2710998f007dSPierre Jolivet } 2711998f007dSPierre Jolivet 271251f519a2SBarry Smith /*@ 271351f519a2SBarry Smith PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 271480670ca5SBarry Smith fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used. 271551f519a2SBarry Smith 2716c3339decSBarry Smith Logically Collective 271751f519a2SBarry Smith 271851f519a2SBarry Smith Input Parameters: 271951f519a2SBarry Smith + pc - the preconditioner context 272051f519a2SBarry Smith - bs - the block size 272151f519a2SBarry Smith 272251f519a2SBarry Smith Level: intermediate 272351f519a2SBarry Smith 272480670ca5SBarry Smith Note: 272580670ca5SBarry Smith If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields. 272680670ca5SBarry Smith 272760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 272851f519a2SBarry Smith @*/ 2729d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs) 2730d71ae5a4SJacob Faibussowitsch { 273151f519a2SBarry Smith PetscFunctionBegin; 27320700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2733c5eb9154SBarry Smith PetscValidLogicalCollectiveInt(pc, bs, 2); 2734cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs)); 27353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 273651f519a2SBarry Smith } 273751f519a2SBarry Smith 27380971522cSBarry Smith /*@C 2739f1580f4eSBarry Smith PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits 27400971522cSBarry Smith 2741c3339decSBarry Smith Collective 27420971522cSBarry Smith 27430971522cSBarry Smith Input Parameter: 27440971522cSBarry Smith . pc - the preconditioner context 27450971522cSBarry Smith 27460971522cSBarry Smith Output Parameters: 274713e0d083SBarry Smith + n - the number of splits 2748f1580f4eSBarry Smith - subksp - the array of `KSP` contexts 2749196cc216SBarry Smith 27500971522cSBarry Smith Level: advanced 27510971522cSBarry Smith 2752f1580f4eSBarry Smith Notes: 2753f1580f4eSBarry Smith After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2754f1580f4eSBarry Smith (not the `KSP`, just the array that contains them). 2755f1580f4eSBarry Smith 2756f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`. 2757f1580f4eSBarry Smith 2758f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the 2759f1580f4eSBarry Smith Schur complement and the `KSP` object used to iterate over the Schur complement. 2760f1580f4eSBarry Smith To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`. 2761f1580f4eSBarry Smith 2762f1580f4eSBarry Smith If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the 2763f1580f4eSBarry Smith inner linear system defined by the matrix H in each loop. 2764f1580f4eSBarry Smith 2765feaf08eaSBarry Smith Fortran Note: 2766e41f517fSBarry Smith Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed 2767f1580f4eSBarry Smith 2768feefa0e1SJacob Faibussowitsch Developer Notes: 2769f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2770f1580f4eSBarry Smith 277160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()` 27720971522cSBarry Smith @*/ 2773d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2774d71ae5a4SJacob Faibussowitsch { 27750971522cSBarry Smith PetscFunctionBegin; 27760700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 27774f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2); 2778cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 27793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27800971522cSBarry Smith } 27810971522cSBarry Smith 2782285fb4e2SStefano Zampini /*@C 2783f1580f4eSBarry Smith PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT` 2784285fb4e2SStefano Zampini 278560f59c3bSBarry Smith Collective 2786285fb4e2SStefano Zampini 2787285fb4e2SStefano Zampini Input Parameter: 2788285fb4e2SStefano Zampini . pc - the preconditioner context 2789285fb4e2SStefano Zampini 2790285fb4e2SStefano Zampini Output Parameters: 2791285fb4e2SStefano Zampini + n - the number of splits 2792f1580f4eSBarry Smith - subksp - the array of `KSP` contexts 2793285fb4e2SStefano Zampini 2794285fb4e2SStefano Zampini Level: advanced 2795285fb4e2SStefano Zampini 2796f1580f4eSBarry Smith Notes: 2797f1580f4eSBarry Smith After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()` 2798f1580f4eSBarry Smith (not the `KSP` just the array that contains them). 2799f1580f4eSBarry Smith 2800f1580f4eSBarry Smith You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`. 2801f1580f4eSBarry Smith 2802f1580f4eSBarry Smith If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order) 2803f1580f4eSBarry Smith + 1 - the `KSP` used for the (1,1) block 2804f1580f4eSBarry Smith . 2 - the `KSP` used for the Schur complement (not the one used for the interior Schur solver) 2805f1580f4eSBarry Smith - 3 - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block). 2806f1580f4eSBarry Smith 2807f1580f4eSBarry Smith It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`. 2808f1580f4eSBarry Smith 2809feaf08eaSBarry Smith Fortran Note: 2810e41f517fSBarry Smith Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed 2811f1580f4eSBarry Smith 2812f1580f4eSBarry Smith Developer Notes: 2813f1580f4eSBarry Smith There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()` 2814f1580f4eSBarry Smith 2815f1580f4eSBarry Smith Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged? 2816f1580f4eSBarry Smith 281760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()` 2818285fb4e2SStefano Zampini @*/ 2819d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) 2820d71ae5a4SJacob Faibussowitsch { 2821285fb4e2SStefano Zampini PetscFunctionBegin; 2822285fb4e2SStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 28234f572ea9SToby Isaac if (n) PetscAssertPointer(n, 2); 2824cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp)); 28253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2826285fb4e2SStefano Zampini } 2827285fb4e2SStefano Zampini 2828e69d4d44SBarry Smith /*@ 2829c14e9f00SDavid Andrs PCFieldSplitSetSchurPre - Indicates from what operator the preconditioner is constructed for the Schur complement. 2830a1e3cbf9SBarry Smith The default is the A11 matrix. 2831e69d4d44SBarry Smith 2832c3339decSBarry Smith Collective 2833e69d4d44SBarry Smith 2834e69d4d44SBarry Smith Input Parameters: 2835e69d4d44SBarry Smith + pc - the preconditioner context 2836f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default), 2837f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`, 2838f1580f4eSBarry Smith `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL` 283960f59c3bSBarry Smith - pre - matrix to use for preconditioning, or `NULL` 2840084e4875SJed Brown 2841f1580f4eSBarry Smith Options Database Keys: 2842d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments 2843a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator 2844e69d4d44SBarry Smith 284560f59c3bSBarry Smith Level: intermediate 284660f59c3bSBarry Smith 2847fd1303e9SJungho Lee Notes: 2848f1580f4eSBarry Smith If ptype is 2849f1580f4eSBarry Smith + a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner 2850f1580f4eSBarry Smith matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix 2851f1580f4eSBarry Smith . self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix: 2852e7593814SPierre Jolivet The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM` 2853f1580f4eSBarry Smith . user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument 2854f1580f4eSBarry Smith to this function). 2855a077d33dSBarry Smith . selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $ 2856f1580f4eSBarry Smith This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be 2857d59693daSPierre Jolivet lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump` 2858f1580f4eSBarry Smith - full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation 2859f1580f4eSBarry Smith computed internally by `PCFIELDSPLIT` (this is expensive) 2860f1580f4eSBarry Smith useful mostly as a test that the Schur complement approach can work for your problem 2861fd1303e9SJungho Lee 2862d59693daSPierre Jolivet When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense 2863a077d33dSBarry Smith with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and 2864d59693daSPierre Jolivet `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement. 2865fd1303e9SJungho Lee 2866a077d33dSBarry Smith Developer Note: 2867a077d33dSBarry Smith The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere. 2868feefa0e1SJacob Faibussowitsch 2869a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, 2870a077d33dSBarry Smith `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()` 2871e69d4d44SBarry Smith @*/ 2872d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2873d71ae5a4SJacob Faibussowitsch { 2874e69d4d44SBarry Smith PetscFunctionBegin; 28750700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2876cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre)); 28773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2878e69d4d44SBarry Smith } 2879686bed4dSStefano Zampini 2880d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2881d71ae5a4SJacob Faibussowitsch { 28829371c9d4SSatish Balay return PCFieldSplitSetSchurPre(pc, ptype, pre); 28839371c9d4SSatish Balay } /* Deprecated name */ 2884e69d4d44SBarry Smith 288537a82bf0SJed Brown /*@ 288637a82bf0SJed Brown PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be 2887f1580f4eSBarry Smith preconditioned. See `PCFieldSplitSetSchurPre()` for details. 288837a82bf0SJed Brown 2889c3339decSBarry Smith Logically Collective 289037a82bf0SJed Brown 2891f899ff85SJose E. Roman Input Parameter: 289237a82bf0SJed Brown . pc - the preconditioner context 289337a82bf0SJed Brown 289437a82bf0SJed Brown Output Parameters: 2895d59693daSPierre 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` 2896d59693daSPierre Jolivet - pre - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL` 289737a82bf0SJed Brown 289837a82bf0SJed Brown Level: intermediate 289937a82bf0SJed Brown 2900d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC` 290137a82bf0SJed Brown @*/ 2902d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2903d71ae5a4SJacob Faibussowitsch { 290437a82bf0SJed Brown PetscFunctionBegin; 290537a82bf0SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 2906cac4c232SBarry Smith PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre)); 29073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2908e69d4d44SBarry Smith } 2909e69d4d44SBarry Smith 291045e7fc46SDmitry Karpeev /*@ 2911f1580f4eSBarry Smith PCFieldSplitSchurGetS - extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately 291245e7fc46SDmitry Karpeev 291320f4b53cSBarry Smith Not Collective 291445e7fc46SDmitry Karpeev 291545e7fc46SDmitry Karpeev Input Parameter: 291645e7fc46SDmitry Karpeev . pc - the preconditioner context 291745e7fc46SDmitry Karpeev 291845e7fc46SDmitry Karpeev Output Parameter: 2919470b340bSDmitry Karpeev . S - the Schur complement matrix 292045e7fc46SDmitry Karpeev 292160f59c3bSBarry Smith Level: advanced 292260f59c3bSBarry Smith 2923f1580f4eSBarry Smith Note: 2924f1580f4eSBarry Smith This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`. 292545e7fc46SDmitry Karpeev 292660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`, 2927f1580f4eSBarry Smith `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()` 292845e7fc46SDmitry Karpeev @*/ 2929d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S) 2930d71ae5a4SJacob Faibussowitsch { 293145e7fc46SDmitry Karpeev const char *t; 293245e7fc46SDmitry Karpeev PetscBool isfs; 293345e7fc46SDmitry Karpeev PC_FieldSplit *jac; 293445e7fc46SDmitry Karpeev 293545e7fc46SDmitry Karpeev PetscFunctionBegin; 293645e7fc46SDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 29379566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 29389566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 293928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 294045e7fc46SDmitry Karpeev jac = (PC_FieldSplit *)pc->data; 294163a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 2942470b340bSDmitry Karpeev if (S) *S = jac->schur; 29433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 294445e7fc46SDmitry Karpeev } 294545e7fc46SDmitry Karpeev 2946470b340bSDmitry Karpeev /*@ 2947f1580f4eSBarry Smith PCFieldSplitSchurRestoreS - returns the `MATSCHURCOMPLEMENT` matrix used by this `PC` 2948470b340bSDmitry Karpeev 294920f4b53cSBarry Smith Not Collective 2950470b340bSDmitry Karpeev 2951470b340bSDmitry Karpeev Input Parameters: 2952470b340bSDmitry Karpeev + pc - the preconditioner context 2953a2b725a8SWilliam Gropp - S - the Schur complement matrix 2954470b340bSDmitry Karpeev 2955470b340bSDmitry Karpeev Level: advanced 2956470b340bSDmitry Karpeev 295760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()` 2958470b340bSDmitry Karpeev @*/ 2959d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S) 2960d71ae5a4SJacob Faibussowitsch { 2961470b340bSDmitry Karpeev const char *t; 2962470b340bSDmitry Karpeev PetscBool isfs; 2963470b340bSDmitry Karpeev PC_FieldSplit *jac; 2964470b340bSDmitry Karpeev 2965470b340bSDmitry Karpeev PetscFunctionBegin; 2966470b340bSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 29679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetType((PetscObject)pc, &t)); 29689566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs)); 296928b400f6SJacob Faibussowitsch PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t); 2970470b340bSDmitry Karpeev jac = (PC_FieldSplit *)pc->data; 297163a3b9bcSJacob Faibussowitsch PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type); 29727827d75bSBarry Smith PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten"); 29733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2974470b340bSDmitry Karpeev } 2975470b340bSDmitry Karpeev 2976d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) 2977d71ae5a4SJacob Faibussowitsch { 2978e69d4d44SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 2979e69d4d44SBarry Smith 2980e69d4d44SBarry Smith PetscFunctionBegin; 2981084e4875SJed Brown jac->schurpre = ptype; 2982a7476a74SDmitry Karpeev if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) { 29839566063dSJacob Faibussowitsch PetscCall(MatDestroy(&jac->schur_user)); 2984084e4875SJed Brown jac->schur_user = pre; 29859566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)jac->schur_user)); 2986084e4875SJed Brown } 29873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2988e69d4d44SBarry Smith } 2989e69d4d44SBarry Smith 2990d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) 2991d71ae5a4SJacob Faibussowitsch { 299237a82bf0SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 299337a82bf0SJed Brown 299437a82bf0SJed Brown PetscFunctionBegin; 29956056e507SPierre Jolivet if (ptype) *ptype = jac->schurpre; 29966056e507SPierre Jolivet if (pre) *pre = jac->schur_user; 29973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 299837a82bf0SJed Brown } 299937a82bf0SJed Brown 3000ab1df9f5SJed Brown /*@ 30011d27aa22SBarry Smith PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note` 3002ab1df9f5SJed Brown 3003c3339decSBarry Smith Collective 3004ab1df9f5SJed Brown 3005ab1df9f5SJed Brown Input Parameters: 3006ab1df9f5SJed Brown + pc - the preconditioner context 3007f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default 3008ab1df9f5SJed Brown 3009f1580f4eSBarry Smith Options Database Key: 3010d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full` 3011ab1df9f5SJed Brown 3012ab1df9f5SJed Brown Level: intermediate 3013ab1df9f5SJed Brown 3014ab1df9f5SJed Brown Notes: 3015366f9a6aSPierre Jolivet The `full` factorization is 3016ab1df9f5SJed Brown 3017a077d33dSBarry Smith ```{math} 3018a077d33dSBarry Smith \left(\begin{array}{cc} A & B \\ 3019a077d33dSBarry Smith C & E \\ 3020a077d33dSBarry Smith \end{array}\right) = 3021366f9a6aSPierre Jolivet \left(\begin{array}{cc} I & 0 \\ 3022366f9a6aSPierre Jolivet C A^{-1} & I \\ 3023a077d33dSBarry Smith \end{array}\right) 3024a077d33dSBarry Smith \left(\begin{array}{cc} A & 0 \\ 3025a077d33dSBarry Smith 0 & S \\ 3026a077d33dSBarry Smith \end{array}\right) 3027a077d33dSBarry Smith \left(\begin{array}{cc} I & A^{-1}B \\ 3028a077d33dSBarry Smith 0 & I \\ 3029366f9a6aSPierre Jolivet \end{array}\right) = L D U, 3030a077d33dSBarry Smith ``` 3031a077d33dSBarry Smith 3032366f9a6aSPierre 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$, 3033366f9a6aSPierre Jolivet and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations, 3034a077d33dSBarry Smith thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`. 3035a077d33dSBarry Smith 3036a077d33dSBarry Smith If $A$ and $S$ are solved exactly 3037366f9a6aSPierre Jolivet + 1 - `full` factorization is a direct solver. 3038366f9a6aSPierre 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. 3039366f9a6aSPierre 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. 3040ab1df9f5SJed Brown 3041f1580f4eSBarry Smith If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner 30420ffb0e17SBarry 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. 30430ffb0e17SBarry Smith 3044366f9a6aSPierre Jolivet For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`. 30450ffb0e17SBarry Smith 3046366f9a6aSPierre 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$). 3047ab1df9f5SJed Brown 30481d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`, 3049a077d33dSBarry Smith [](sec_flexibleksp), `PCFieldSplitSetSchurPre()` 3050ab1df9f5SJed Brown @*/ 3051d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype) 3052d71ae5a4SJacob Faibussowitsch { 3053ab1df9f5SJed Brown PetscFunctionBegin; 3054ab1df9f5SJed Brown PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3055cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype)); 30563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3057ab1df9f5SJed Brown } 3058ab1df9f5SJed Brown 3059d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype) 3060d71ae5a4SJacob Faibussowitsch { 3061ab1df9f5SJed Brown PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3062ab1df9f5SJed Brown 3063ab1df9f5SJed Brown PetscFunctionBegin; 3064ab1df9f5SJed Brown jac->schurfactorization = ftype; 30653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3066ab1df9f5SJed Brown } 3067ab1df9f5SJed Brown 3068c096484dSStefano Zampini /*@ 3069f1580f4eSBarry Smith PCFieldSplitSetSchurScale - Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`. 3070c096484dSStefano Zampini 3071c3339decSBarry Smith Collective 3072c096484dSStefano Zampini 3073c096484dSStefano Zampini Input Parameters: 3074c096484dSStefano Zampini + pc - the preconditioner context 3075c096484dSStefano Zampini - scale - scaling factor for the Schur complement 3076c096484dSStefano Zampini 3077f1580f4eSBarry Smith Options Database Key: 30781d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0 3079c096484dSStefano Zampini 3080c096484dSStefano Zampini Level: intermediate 3081c096484dSStefano Zampini 308242747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()` 3083c096484dSStefano Zampini @*/ 3084d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale) 3085d71ae5a4SJacob Faibussowitsch { 3086c096484dSStefano Zampini PetscFunctionBegin; 3087c096484dSStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3088c096484dSStefano Zampini PetscValidLogicalCollectiveScalar(pc, scale, 2); 3089cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale)); 30903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3091c096484dSStefano Zampini } 3092c096484dSStefano Zampini 3093d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale) 3094d71ae5a4SJacob Faibussowitsch { 3095c096484dSStefano Zampini PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3096c096484dSStefano Zampini 3097c096484dSStefano Zampini PetscFunctionBegin; 3098c096484dSStefano Zampini jac->schurscale = scale; 30993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3100c096484dSStefano Zampini } 3101c096484dSStefano Zampini 310230ad9308SMatthew Knepley /*@C 31038c03b21aSDmitry Karpeev PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 310430ad9308SMatthew Knepley 3105c3339decSBarry Smith Collective 310630ad9308SMatthew Knepley 310730ad9308SMatthew Knepley Input Parameter: 310830ad9308SMatthew Knepley . pc - the preconditioner context 310930ad9308SMatthew Knepley 311030ad9308SMatthew Knepley Output Parameters: 3111a04f6461SBarry Smith + A00 - the (0,0) block 3112a04f6461SBarry Smith . A01 - the (0,1) block 3113a04f6461SBarry Smith . A10 - the (1,0) block 3114a04f6461SBarry Smith - A11 - the (1,1) block 311530ad9308SMatthew Knepley 311630ad9308SMatthew Knepley Level: advanced 311730ad9308SMatthew Knepley 31185d83a8b1SBarry Smith Note: 31195d83a8b1SBarry Smith Use `NULL` for any unneeded output arguments 31205d83a8b1SBarry Smith 312160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()` 312230ad9308SMatthew Knepley @*/ 3123d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11) 3124d71ae5a4SJacob Faibussowitsch { 312530ad9308SMatthew Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 312630ad9308SMatthew Knepley 312730ad9308SMatthew Knepley PetscFunctionBegin; 31280700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 312908401ef6SPierre Jolivet PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 3130a04f6461SBarry Smith if (A00) *A00 = jac->pmat[0]; 3131a04f6461SBarry Smith if (A01) *A01 = jac->B; 3132a04f6461SBarry Smith if (A10) *A10 = jac->C; 3133a04f6461SBarry Smith if (A11) *A11 = jac->pmat[1]; 31343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 313530ad9308SMatthew Knepley } 313630ad9308SMatthew Knepley 3137b09e027eSCarola Kruse /*@ 31381d27aa22SBarry Smith PCFieldSplitSetGKBTol - Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 3139b09e027eSCarola Kruse 3140c3339decSBarry Smith Collective 3141e071a0a4SCarola Kruse 3142b09e027eSCarola Kruse Input Parameters: 3143b09e027eSCarola Kruse + pc - the preconditioner context 3144b09e027eSCarola Kruse - tolerance - the solver tolerance 3145b09e027eSCarola Kruse 3146f1580f4eSBarry Smith Options Database Key: 31471d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5 3148b09e027eSCarola Kruse 3149b09e027eSCarola Kruse Level: intermediate 3150b09e027eSCarola Kruse 3151f1580f4eSBarry Smith Note: 31521d27aa22SBarry Smith The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion. 3153f1580f4eSBarry Smith It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than 31541d27aa22SBarry Smith this estimate, the stopping criterion is satisfactory in practical cases. 3155f1580f4eSBarry Smith 315660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()` 3157b09e027eSCarola Kruse @*/ 3158d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance) 3159d71ae5a4SJacob Faibussowitsch { 3160b09e027eSCarola Kruse PetscFunctionBegin; 3161b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3162de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, tolerance, 2); 3163cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance)); 31643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3165b09e027eSCarola Kruse } 3166b09e027eSCarola Kruse 3167d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance) 3168d71ae5a4SJacob Faibussowitsch { 3169b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3170b09e027eSCarola Kruse 3171b09e027eSCarola Kruse PetscFunctionBegin; 3172b09e027eSCarola Kruse jac->gkbtol = tolerance; 31733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3174b09e027eSCarola Kruse } 3175b09e027eSCarola Kruse 3176b09e027eSCarola Kruse /*@ 317780670ca5SBarry Smith PCFieldSplitSetGKBMaxit - Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 3178b09e027eSCarola Kruse 3179c3339decSBarry Smith Collective 3180b09e027eSCarola Kruse 3181b09e027eSCarola Kruse Input Parameters: 3182b09e027eSCarola Kruse + pc - the preconditioner context 3183b09e027eSCarola Kruse - maxit - the maximum number of iterations 3184b09e027eSCarola Kruse 3185f1580f4eSBarry Smith Options Database Key: 31861d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100 3187b09e027eSCarola Kruse 3188b09e027eSCarola Kruse Level: intermediate 3189b09e027eSCarola Kruse 319060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()` 3191b09e027eSCarola Kruse @*/ 3192d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit) 3193d71ae5a4SJacob Faibussowitsch { 3194b09e027eSCarola Kruse PetscFunctionBegin; 3195b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3196de482cd7SCarola Kruse PetscValidLogicalCollectiveInt(pc, maxit, 2); 3197cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit)); 31983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3199b09e027eSCarola Kruse } 3200b09e027eSCarola Kruse 3201d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit) 3202d71ae5a4SJacob Faibussowitsch { 3203b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3204b09e027eSCarola Kruse 3205b09e027eSCarola Kruse PetscFunctionBegin; 3206b09e027eSCarola Kruse jac->gkbmaxit = maxit; 32073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3208b09e027eSCarola Kruse } 3209b09e027eSCarola Kruse 3210b09e027eSCarola Kruse /*@ 32111d27aa22SBarry Smith PCFieldSplitSetGKBDelay - Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT` 3212e071a0a4SCarola Kruse preconditioner. 3213b09e027eSCarola Kruse 3214c3339decSBarry Smith Collective 3215b09e027eSCarola Kruse 3216b09e027eSCarola Kruse Input Parameters: 3217b09e027eSCarola Kruse + pc - the preconditioner context 3218b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate 3219b09e027eSCarola Kruse 3220f1580f4eSBarry Smith Options Database Key: 32211d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5 3222b09e027eSCarola Kruse 3223b09e027eSCarola Kruse Level: intermediate 3224b09e027eSCarola Kruse 32251d27aa22SBarry Smith Notes: 32261d27aa22SBarry 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 $ 32271d27aa22SBarry 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 32281d27aa22SBarry Smith at least (`delay` + 1) iterations to stop. 3229f1580f4eSBarry Smith 32301d27aa22SBarry Smith For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013` 3231f1580f4eSBarry Smith 323260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 3233b09e027eSCarola Kruse @*/ 3234d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay) 3235d71ae5a4SJacob Faibussowitsch { 3236b09e027eSCarola Kruse PetscFunctionBegin; 3237b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3238b09e027eSCarola Kruse PetscValidLogicalCollectiveInt(pc, delay, 2); 3239cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay)); 32403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3241b09e027eSCarola Kruse } 3242b09e027eSCarola Kruse 3243d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay) 3244d71ae5a4SJacob Faibussowitsch { 3245b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3246b09e027eSCarola Kruse 3247b09e027eSCarola Kruse PetscFunctionBegin; 3248b09e027eSCarola Kruse jac->gkbdelay = delay; 32493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3250b09e027eSCarola Kruse } 3251b09e027eSCarola Kruse 3252b09e027eSCarola Kruse /*@ 32531d27aa22SBarry Smith PCFieldSplitSetGKBNu - Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the 32541d27aa22SBarry Smith Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT` 3255b09e027eSCarola Kruse 3256c3339decSBarry Smith Collective 3257f1580f4eSBarry Smith 3258f1580f4eSBarry Smith Input Parameters: 3259f1580f4eSBarry Smith + pc - the preconditioner context 3260f1580f4eSBarry Smith - nu - the shift parameter 3261f1580f4eSBarry Smith 326220f4b53cSBarry Smith Options Database Key: 32631d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1 3264f1580f4eSBarry Smith 3265f1580f4eSBarry Smith Level: intermediate 3266b09e027eSCarola Kruse 3267b09e027eSCarola Kruse Notes: 32681d27aa22SBarry 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, 32691d27aa22SBarry 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 3270b09e027eSCarola Kruse necessary to find a good balance in between the convergence of the inner and outer loop. 3271b09e027eSCarola Kruse 32721d27aa22SBarry 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. 3273b09e027eSCarola Kruse 327460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()` 3275b09e027eSCarola Kruse @*/ 3276d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu) 3277d71ae5a4SJacob Faibussowitsch { 3278b09e027eSCarola Kruse PetscFunctionBegin; 3279b09e027eSCarola Kruse PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3280de482cd7SCarola Kruse PetscValidLogicalCollectiveReal(pc, nu, 2); 3281cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu)); 32823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3283b09e027eSCarola Kruse } 3284b09e027eSCarola Kruse 3285d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu) 3286d71ae5a4SJacob Faibussowitsch { 3287b09e027eSCarola Kruse PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3288b09e027eSCarola Kruse 3289b09e027eSCarola Kruse PetscFunctionBegin; 3290b09e027eSCarola Kruse jac->gkbnu = nu; 32913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3292b09e027eSCarola Kruse } 3293b09e027eSCarola Kruse 3294d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type) 3295d71ae5a4SJacob Faibussowitsch { 329679416396SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 329779416396SBarry Smith 329879416396SBarry Smith PetscFunctionBegin; 329979416396SBarry Smith jac->type = type; 33002e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL)); 33012e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL)); 33022e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL)); 33032e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL)); 33042e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL)); 33052e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL)); 33062e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL)); 33072e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL)); 33082e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL)); 3309e071a0a4SCarola Kruse 33103b224e63SBarry Smith if (type == PC_COMPOSITE_SCHUR) { 33113b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit_Schur; 33127b665727SPierre Jolivet pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur; 3313*f5b94327SPierre Jolivet pc->ops->matapply = PCMatApply_FieldSplit_Schur; 33143b224e63SBarry Smith pc->ops->view = PCView_FieldSplit_Schur; 331573716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_Schur; 33162fa5cd67SKarl Rupp 33179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur)); 33189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit)); 33199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit)); 33209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit)); 33219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit)); 3322a51937d4SCarola Kruse } else if (type == PC_COMPOSITE_GKB) { 3323a51937d4SCarola Kruse pc->ops->apply = PCApply_FieldSplit_GKB; 33247ff38633SStefano Zampini pc->ops->applytranspose = NULL; 3325d484b384SBoris Martin pc->ops->matapply = NULL; 3326a51937d4SCarola Kruse pc->ops->view = PCView_FieldSplit_GKB; 332773716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit_GKB; 3328e69d4d44SBarry Smith 33299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 33309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit)); 33319566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit)); 33329566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit)); 33339566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit)); 33343b224e63SBarry Smith } else { 33353b224e63SBarry Smith pc->ops->apply = PCApply_FieldSplit; 33367ff38633SStefano Zampini pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 3337d484b384SBoris Martin pc->ops->matapply = PCMatApply_FieldSplit; 33383b224e63SBarry Smith pc->ops->view = PCView_FieldSplit; 333973716367SStefano Zampini pc->ops->setuponblocks = PCSetUpOnBlocks_FieldSplit; 33402fa5cd67SKarl Rupp 33419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit)); 33423b224e63SBarry Smith } 33433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 334479416396SBarry Smith } 334579416396SBarry Smith 3346d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs) 3347d71ae5a4SJacob Faibussowitsch { 334851f519a2SBarry Smith PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 334951f519a2SBarry Smith 335051f519a2SBarry Smith PetscFunctionBegin; 335163a3b9bcSJacob Faibussowitsch PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs); 33522472a847SBarry 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); 335351f519a2SBarry Smith jac->bs = bs; 33543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 335551f519a2SBarry Smith } 335651f519a2SBarry Smith 3357d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[]) 3358d71ae5a4SJacob Faibussowitsch { 33595ddf11f8SNicolas Barnafi PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 33605ddf11f8SNicolas Barnafi PC_FieldSplitLink ilink_current = jac->head; 33615ddf11f8SNicolas Barnafi IS is_owned; 33625ddf11f8SNicolas Barnafi 33635ddf11f8SNicolas Barnafi PetscFunctionBegin; 33645ddf11f8SNicolas Barnafi jac->coordinates_set = PETSC_TRUE; // Internal flag 3365f3fa974cSJacob Faibussowitsch PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL)); 33665ddf11f8SNicolas Barnafi 33675ddf11f8SNicolas Barnafi while (ilink_current) { 33685ddf11f8SNicolas Barnafi // For each IS, embed it to get local coords indces 33695ddf11f8SNicolas Barnafi IS is_coords; 33705ddf11f8SNicolas Barnafi PetscInt ndofs_block; 33715ddf11f8SNicolas Barnafi const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block 33725ddf11f8SNicolas Barnafi 33735ddf11f8SNicolas Barnafi // Setting drop to true for safety. It should make no difference. 33749566063dSJacob Faibussowitsch PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords)); 33759566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(is_coords, &ndofs_block)); 33769566063dSJacob Faibussowitsch PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration)); 33775ddf11f8SNicolas Barnafi 33785ddf11f8SNicolas Barnafi // Allocate coordinates vector and set it directly 3379f4f49eeaSPierre Jolivet PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords)); 33805ddf11f8SNicolas Barnafi for (PetscInt dof = 0; dof < ndofs_block; ++dof) { 3381ad540459SPierre Jolivet for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d]; 33825ddf11f8SNicolas Barnafi } 33835ddf11f8SNicolas Barnafi ilink_current->dim = dim; 33845ddf11f8SNicolas Barnafi ilink_current->ndofs = ndofs_block; 33859566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration)); 33869566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_coords)); 33875ddf11f8SNicolas Barnafi ilink_current = ilink_current->next; 33885ddf11f8SNicolas Barnafi } 33899566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is_owned)); 33903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33915ddf11f8SNicolas Barnafi } 33925ddf11f8SNicolas Barnafi 3393bc08b0f1SBarry Smith /*@ 3394f1580f4eSBarry Smith PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 339579416396SBarry Smith 3396c3339decSBarry Smith Collective 339779416396SBarry Smith 3398d8d19677SJose E. Roman Input Parameters: 3399a2b725a8SWilliam Gropp + pc - the preconditioner context 3400a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, 3401a077d33dSBarry Smith `PC_COMPOSITE_GKB` 340279416396SBarry Smith 340379416396SBarry Smith Options Database Key: 34041d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 340579416396SBarry Smith 3406feefa0e1SJacob Faibussowitsch Level: intermediate 340779416396SBarry Smith 340860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 3409a077d33dSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()` 341079416396SBarry Smith @*/ 3411d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type) 3412d71ae5a4SJacob Faibussowitsch { 341379416396SBarry Smith PetscFunctionBegin; 34140700a824SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 3415cac4c232SBarry Smith PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type)); 34163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 341779416396SBarry Smith } 341879416396SBarry Smith 3419b02e2d75SMatthew G Knepley /*@ 3420f1580f4eSBarry Smith PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT` 3421b02e2d75SMatthew G Knepley 3422b02e2d75SMatthew G Knepley Not collective 3423b02e2d75SMatthew G Knepley 3424b02e2d75SMatthew G Knepley Input Parameter: 3425b02e2d75SMatthew G Knepley . pc - the preconditioner context 3426b02e2d75SMatthew G Knepley 3427b02e2d75SMatthew G Knepley Output Parameter: 3428f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 3429b02e2d75SMatthew G Knepley 3430feefa0e1SJacob Faibussowitsch Level: intermediate 3431b02e2d75SMatthew G Knepley 343260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, 3433f1580f4eSBarry Smith `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR` 3434b02e2d75SMatthew G Knepley @*/ 3435d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 3436d71ae5a4SJacob Faibussowitsch { 3437b02e2d75SMatthew G Knepley PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 3438b02e2d75SMatthew G Knepley 3439b02e2d75SMatthew G Knepley PetscFunctionBegin; 3440b02e2d75SMatthew G Knepley PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 34414f572ea9SToby Isaac PetscAssertPointer(type, 2); 3442b02e2d75SMatthew G Knepley *type = jac->type; 34433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3444b02e2d75SMatthew G Knepley } 3445b02e2d75SMatthew G Knepley 34464ab8060aSDmitry Karpeev /*@ 3447f1580f4eSBarry Smith PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 34484ab8060aSDmitry Karpeev 3449c3339decSBarry Smith Logically Collective 34504ab8060aSDmitry Karpeev 34514ab8060aSDmitry Karpeev Input Parameters: 34524ab8060aSDmitry Karpeev + pc - the preconditioner context 3453f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM` 34544ab8060aSDmitry Karpeev 34554ab8060aSDmitry Karpeev Options Database Key: 3456f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM` 34574ab8060aSDmitry Karpeev 3458feefa0e1SJacob Faibussowitsch Level: intermediate 34594ab8060aSDmitry Karpeev 346073ff1848SBarry Smith Developer Note: 346173ff1848SBarry Smith The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database 346273ff1848SBarry Smith 3463f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 34644ab8060aSDmitry Karpeev @*/ 3465d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg) 3466d71ae5a4SJacob Faibussowitsch { 34674ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 34684ab8060aSDmitry Karpeev PetscBool isfs; 34694ab8060aSDmitry Karpeev 34704ab8060aSDmitry Karpeev PetscFunctionBegin; 34714ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 34724ab8060aSDmitry Karpeev PetscValidLogicalCollectiveBool(pc, flg, 2); 34739566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 3474ad540459SPierre Jolivet if (isfs) jac->dm_splits = flg; 34753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34764ab8060aSDmitry Karpeev } 34774ab8060aSDmitry Karpeev 34784ab8060aSDmitry Karpeev /*@ 3479f1580f4eSBarry Smith PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible. 34804ab8060aSDmitry Karpeev 34814ab8060aSDmitry Karpeev Logically Collective 34824ab8060aSDmitry Karpeev 34834ab8060aSDmitry Karpeev Input Parameter: 34844ab8060aSDmitry Karpeev . pc - the preconditioner context 34854ab8060aSDmitry Karpeev 34864ab8060aSDmitry Karpeev Output Parameter: 3487f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM` 34884ab8060aSDmitry Karpeev 3489feefa0e1SJacob Faibussowitsch Level: intermediate 34904ab8060aSDmitry Karpeev 349173ff1848SBarry Smith Developer Note: 349273ff1848SBarry Smith The name should be `PCFieldSplitGetUseDMSplits()` 349373ff1848SBarry Smith 3494f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()` 34954ab8060aSDmitry Karpeev @*/ 3496d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg) 3497d71ae5a4SJacob Faibussowitsch { 34984ab8060aSDmitry Karpeev PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 34994ab8060aSDmitry Karpeev PetscBool isfs; 35004ab8060aSDmitry Karpeev 35014ab8060aSDmitry Karpeev PetscFunctionBegin; 35024ab8060aSDmitry Karpeev PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 35034f572ea9SToby Isaac PetscAssertPointer(flg, 2); 35049566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs)); 35054ab8060aSDmitry Karpeev if (isfs) { 35064ab8060aSDmitry Karpeev if (flg) *flg = jac->dm_splits; 35074ab8060aSDmitry Karpeev } 35083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35094ab8060aSDmitry Karpeev } 35104ab8060aSDmitry Karpeev 35117b752e3dSPatrick Sanan /*@ 3512f1580f4eSBarry Smith PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 35137b752e3dSPatrick Sanan 35147b752e3dSPatrick Sanan Logically Collective 35157b752e3dSPatrick Sanan 35167b752e3dSPatrick Sanan Input Parameter: 35177b752e3dSPatrick Sanan . pc - the preconditioner context 35187b752e3dSPatrick Sanan 35197b752e3dSPatrick Sanan Output Parameter: 35207b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not 35217b752e3dSPatrick Sanan 3522feefa0e1SJacob Faibussowitsch Level: intermediate 35237b752e3dSPatrick Sanan 352460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()` 35257b752e3dSPatrick Sanan @*/ 3526d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg) 3527d71ae5a4SJacob Faibussowitsch { 35287b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 35297b752e3dSPatrick Sanan 35307b752e3dSPatrick Sanan PetscFunctionBegin; 35317b752e3dSPatrick Sanan *flg = jac->detect; 35323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35337b752e3dSPatrick Sanan } 35347b752e3dSPatrick Sanan 35357b752e3dSPatrick Sanan /*@ 3536f1580f4eSBarry Smith PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries. 35377b752e3dSPatrick Sanan 35387b752e3dSPatrick Sanan Logically Collective 35397b752e3dSPatrick Sanan 35407b752e3dSPatrick Sanan Input Parameter: 35417b752e3dSPatrick Sanan . pc - the preconditioner context 35427b752e3dSPatrick Sanan 35437b752e3dSPatrick Sanan Output Parameter: 35447b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not 35457b752e3dSPatrick Sanan 35467b752e3dSPatrick Sanan Options Database Key: 3547147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point 3548147403d9SBarry Smith 3549feefa0e1SJacob Faibussowitsch Level: intermediate 355060f59c3bSBarry Smith 3551f1580f4eSBarry Smith Note: 3552f1580f4eSBarry 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()`). 35537b752e3dSPatrick Sanan 355460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF` 35557b752e3dSPatrick Sanan @*/ 3556d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg) 3557d71ae5a4SJacob Faibussowitsch { 35587b752e3dSPatrick Sanan PC_FieldSplit *jac = (PC_FieldSplit *)pc->data; 35597b752e3dSPatrick Sanan 35607b752e3dSPatrick Sanan PetscFunctionBegin; 35617b752e3dSPatrick Sanan jac->detect = flg; 35627b752e3dSPatrick Sanan if (jac->detect) { 35639566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR)); 35649566063dSJacob Faibussowitsch PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL)); 35657b752e3dSPatrick Sanan } 35663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35677b752e3dSPatrick Sanan } 35687b752e3dSPatrick Sanan 35690971522cSBarry Smith /*MC 3570a8c7a070SBarry Smith PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 35710b4b7b1cSBarry Smith collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable 35720b4b7b1cSBarry Smith represented on a grid, such as velocity, pressure, or temperature. 35730b4b7b1cSBarry Smith In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`. 35740b4b7b1cSBarry Smith See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details. 35750971522cSBarry Smith 357679416396SBarry Smith Options Database Keys: 3577de37d9f1SPatrick Sanan + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split 357881540f2fSBarry Smith . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 3579de37d9f1SPatrick Sanan been supplied explicitly by `-pc_fieldsplit_%d_fields` 358081540f2fSBarry Smith . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 358180670ca5SBarry Smith when the matrix is not of `MatType` `MATNEST` 3582a51937d4SCarola Kruse . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting 3583d59693daSPierre Jolivet . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`; see `PCFieldSplitSetSchurPre()` 35841d27aa22SBarry Smith . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using `-pc_fieldsplit_type schur`; 35851d27aa22SBarry Smith see `PCFieldSplitSetSchurFactType()` 358673ff1848SBarry Smith . -pc_fieldsplit_dm_splits <true,false> (default is true) - Whether to use `DMCreateFieldDecomposition()` for splits 3587fb6809a2SPatrick Sanan - -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver 358879416396SBarry Smith 3589de37d9f1SPatrick Sanan Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` . 3590de37d9f1SPatrick Sanan The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_` 359160f59c3bSBarry Smith For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields. 359260f59c3bSBarry Smith 359322399129SNuno Nobre To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC` 359422399129SNuno Nobre options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`. 359560f59c3bSBarry Smith 359660f59c3bSBarry Smith To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()` 359760f59c3bSBarry Smith and set the options directly on the resulting `KSP` object 359860f59c3bSBarry Smith 359960f59c3bSBarry Smith Level: intermediate 36005d4c12cdSJungho Lee 3601c8a0d604SMatthew G Knepley Notes: 360280670ca5SBarry Smith Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()` 3603f1580f4eSBarry Smith to define a split by an arbitrary collection of entries. 3604d32f9abdSBarry Smith 360573ff1848SBarry Smith If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports 360680670ca5SBarry 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, 3607de37d9f1SPatrick Sanan beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`, 3608d32f9abdSBarry Smith if this is not called the block size defaults to the blocksize of the second matrix passed 3609de37d9f1SPatrick Sanan to `KSPSetOperators()`/`PCSetOperators()`. 3610d32f9abdSBarry Smith 3611de37d9f1SPatrick Sanan For the Schur complement preconditioner if 3612de37d9f1SPatrick Sanan ```{math} 3613de37d9f1SPatrick Sanan J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right] 3614de37d9f1SPatrick Sanan ``` 3615e69d4d44SBarry Smith 3616de37d9f1SPatrick Sanan the preconditioner using `full` factorization is logically 3617de37d9f1SPatrick Sanan ```{math} 3618f820a28cSNuno 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] 3619de37d9f1SPatrick Sanan ``` 3620cee94454SNuno Nobre where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`. $S$ is the Schur complement 3621de37d9f1SPatrick Sanan ```{math} 3622223e5b4fSPatrick Sanan S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01} 3623de37d9f1SPatrick Sanan ``` 36247cbeddf0SNuno 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` 36257cbeddf0SNuno 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 36267cbeddf0SNuno Nobre 0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`. 3627d82b6cdfSNuno 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$. 3628de37d9f1SPatrick Sanan 3629de37d9f1SPatrick Sanan The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above, 3630de37d9f1SPatrick Sanan `diag` gives 3631de37d9f1SPatrick Sanan ```{math} 3632f820a28cSNuno Nobre \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\ 0 & -\text{ksp}(S) \end{array}\right] 3633de37d9f1SPatrick Sanan ``` 3634de37d9f1SPatrick 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 3635de37d9f1SPatrick Sanan can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of 3636de37d9f1SPatrick Sanan ```{math} 3637de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & 0 \\ A_{10} & S \end{array}\right] 3638de37d9f1SPatrick Sanan ``` 3639cee94454SNuno Nobre where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of 3640de37d9f1SPatrick Sanan ```{math} 3641de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ 0 & S \end{array}\right] 3642de37d9f1SPatrick Sanan ``` 3643de37d9f1SPatrick Sanan where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s. 3644de37d9f1SPatrick Sanan 3645de37d9f1SPatrick Sanan If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS` 364680670ca5SBarry Smith is used automatically for a second submatrix. 3647edf189efSBarry Smith 3648f1580f4eSBarry Smith The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1. 364980670ca5SBarry Smith Generally it should be used with the `MATAIJ` or `MATNEST` `MatType` 3650ff218e97SBarry Smith 365180670ca5SBarry Smith The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see, 36521d569b8fSBarry Smith for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`. 365380670ca5SBarry Smith One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers". 36540716a85fSBarry Smith 3655de37d9f1SPatrick Sanan See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`. 3656a6a584a2SBarry Smith 3657de37d9f1SPatrick Sanan The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the 3658de37d9f1SPatrick Sanan residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables. 3659a51937d4SCarola Kruse 3660de37d9f1SPatrick Sanan The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape 3661de37d9f1SPatrick Sanan ```{math} 3662de37d9f1SPatrick Sanan \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right] 3663de37d9f1SPatrick Sanan ``` 36641d569b8fSBarry 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}'$. 3665de37d9f1SPatrick 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_`. 3666a51937d4SCarola Kruse 36670b4b7b1cSBarry Smith Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the 36680b4b7b1cSBarry Smith problem. But this nomenclature is not well-defined. 36690b4b7b1cSBarry Smith 367060f59c3bSBarry Smith Developer Note: 367160f59c3bSBarry Smith The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their 367260f59c3bSBarry Smith user API. 3673f1580f4eSBarry Smith 367460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`, 3675db781477SPatrick Sanan `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`, 3676db781477SPatrick Sanan `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`, 3677db781477SPatrick Sanan `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()` 36780971522cSBarry Smith M*/ 36790971522cSBarry Smith 3680d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) 3681d71ae5a4SJacob Faibussowitsch { 36820971522cSBarry Smith PC_FieldSplit *jac; 36830971522cSBarry Smith 36840971522cSBarry Smith PetscFunctionBegin; 36854dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&jac)); 36862fa5cd67SKarl Rupp 36870971522cSBarry Smith jac->bs = -1; 36883e197d65SBarry Smith jac->type = PC_COMPOSITE_MULTIPLICATIVE; 3689e6cab6aaSJed Brown jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 3690c9c6ffaaSJed Brown jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 3691c096484dSStefano Zampini jac->schurscale = -1.0; 3692fbe7908bSJed Brown jac->dm_splits = PETSC_TRUE; 3693a51937d4SCarola Kruse jac->gkbtol = 1e-5; 3694a51937d4SCarola Kruse jac->gkbdelay = 5; 3695a51937d4SCarola Kruse jac->gkbnu = 1; 3696a51937d4SCarola Kruse jac->gkbmaxit = 100; 369751f519a2SBarry Smith 36980971522cSBarry Smith pc->data = (void *)jac; 36990971522cSBarry Smith 37000971522cSBarry Smith pc->ops->setup = PCSetUp_FieldSplit; 3701574deadeSBarry Smith pc->ops->reset = PCReset_FieldSplit; 37020971522cSBarry Smith pc->ops->destroy = PCDestroy_FieldSplit; 37030971522cSBarry Smith pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 37040a545947SLisandro Dalcin pc->ops->applyrichardson = NULL; 37050971522cSBarry Smith 37069566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit)); 37079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit)); 37089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit)); 37099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit)); 37109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit)); 37119566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit)); 37129566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit)); 37137ff38633SStefano Zampini 37147ff38633SStefano Zampini /* Initialize function pointers */ 37157ff38633SStefano Zampini PetscCall(PCFieldSplitSetType(pc, jac->type)); 37163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37170971522cSBarry Smith } 3718