xref: /petsc/src/ksp/pc/impls/redundant/redundant.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
33f457be1SHong Zhang   This file defines a "solve the problem redundantly on each subgroup of processor" preconditioner.
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcimpl.h>
6c6db04a5SJed Brown #include <petscksp.h> /*I "petscksp.h" I*/
74b9ad928SBarry Smith 
84b9ad928SBarry Smith typedef struct {
93e065800SHong Zhang   KSP                ksp;
104b9ad928SBarry Smith   PC                 pc;                    /* actual preconditioner used on each processor */
11ce94432eSBarry Smith   Vec                xsub, ysub;            /* vectors of a subcommunicator to hold parallel vectors of PetscObjectComm((PetscObject)pc) */
123f457be1SHong Zhang   Vec                xdup, ydup;            /* parallel vector that congregates xsub or ysub facilitating vector scattering */
13b3804887SHong Zhang   Mat                pmats;                 /* matrix and optional preconditioner matrix belong to a subcommunicator */
143f457be1SHong Zhang   VecScatter         scatterin, scatterout; /* scatter used to move all values to each processor group (subcommunicator) */
15ace3abfcSBarry Smith   PetscBool          useparallelmat;
16c540e29cSHong Zhang   PetscSubcomm       psubcomm;
171fbd8f88SHong Zhang   PetscInt           nsubcomm; /* num of data structure PetscSubcomm */
18753b7fb9SBarry Smith   PetscBool          shifttypeset;
19753b7fb9SBarry Smith   MatFactorShiftType shifttype;
204b9ad928SBarry Smith } PC_Redundant;
214b9ad928SBarry Smith 
22d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFactorSetShiftType_Redundant(PC pc, MatFactorShiftType shifttype)
23d71ae5a4SJacob Faibussowitsch {
24753b7fb9SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
25753b7fb9SBarry Smith 
26753b7fb9SBarry Smith   PetscFunctionBegin;
27753b7fb9SBarry Smith   if (red->ksp) {
28753b7fb9SBarry Smith     PC pc;
299566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(red->ksp, &pc));
309566063dSJacob Faibussowitsch     PetscCall(PCFactorSetShiftType(pc, shifttype));
31753b7fb9SBarry Smith   } else {
32753b7fb9SBarry Smith     red->shifttypeset = PETSC_TRUE;
33753b7fb9SBarry Smith     red->shifttype    = shifttype;
34753b7fb9SBarry Smith   }
35753b7fb9SBarry Smith   PetscFunctionReturn(0);
36753b7fb9SBarry Smith }
37753b7fb9SBarry Smith 
38d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_Redundant(PC pc, PetscViewer viewer)
39d71ae5a4SJacob Faibussowitsch {
404b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
41ace3abfcSBarry Smith   PetscBool     iascii, isstring;
4203ccd0b4SBarry Smith   PetscViewer   subviewer;
434b9ad928SBarry Smith 
444b9ad928SBarry Smith   PetscFunctionBegin;
459566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
469566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
4732077d6dSBarry Smith   if (iascii) {
4803ccd0b4SBarry Smith     if (!red->psubcomm) {
499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Not yet setup\n"));
5003ccd0b4SBarry Smith     } else {
5163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  First (color=0) of %" PetscInt_FMT " PCs follows\n", red->nsubcomm));
529566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, ((PetscObject)red->pc)->comm, &subviewer));
53f5dd71faSBarry Smith       if (!red->psubcomm->color) { /* only view first redundant pc */
549566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(subviewer));
559566063dSJacob Faibussowitsch         PetscCall(KSPView(red->ksp, subviewer));
569566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(subviewer));
574b9ad928SBarry Smith       }
589566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, ((PetscObject)red->pc)->comm, &subviewer));
594b9ad928SBarry Smith     }
6003ccd0b4SBarry Smith   } else if (isstring) {
619566063dSJacob Faibussowitsch     PetscCall(PetscViewerStringSPrintf(viewer, " Redundant solver preconditioner"));
624b9ad928SBarry Smith   }
634b9ad928SBarry Smith   PetscFunctionReturn(0);
644b9ad928SBarry Smith }
654b9ad928SBarry Smith 
6619b3b6edSHong Zhang #include <../src/mat/impls/aij/mpi/mpiaij.h>
67d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_Redundant(PC pc)
68d71ae5a4SJacob Faibussowitsch {
694b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
701b81debcSHong Zhang   PetscInt      mstart, mend, mlocal, M;
7113f74950SBarry Smith   PetscMPIInt   size;
72ce94432eSBarry Smith   MPI_Comm      comm, subcomm;
73ddc54837SHong Zhang   Vec           x;
743f457be1SHong Zhang 
754b9ad928SBarry Smith   PetscFunctionBegin;
769566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
77ddc54837SHong Zhang 
78ddc54837SHong Zhang   /* if pmatrix set by user is sequential then we do not need to gather the parallel matrix */
799566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
80ddc54837SHong Zhang   if (size == 1) red->useparallelmat = PETSC_FALSE;
811fbd8f88SHong Zhang 
824b9ad928SBarry Smith   if (!pc->setupcalled) {
831b81debcSHong Zhang     PetscInt mloc_sub;
8475024027SHong Zhang     if (!red->psubcomm) { /* create red->psubcomm, new ksp and pc over subcomm */
8575024027SHong Zhang       KSP ksp;
869566063dSJacob Faibussowitsch       PetscCall(PCRedundantGetKSP(pc, &ksp));
871b81debcSHong Zhang     }
8875024027SHong Zhang     subcomm = PetscSubcommChild(red->psubcomm);
891fbd8f88SHong Zhang 
901b81debcSHong Zhang     if (red->useparallelmat) {
911b81debcSHong Zhang       /* grab the parallel matrix and put it into processors of a subcomminicator */
929566063dSJacob Faibussowitsch       PetscCall(MatCreateRedundantMatrix(pc->pmat, red->psubcomm->n, subcomm, MAT_INITIAL_MATRIX, &red->pmats));
93b85f2e9bSHong Zhang 
949566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(subcomm, &size));
95b85f2e9bSHong Zhang       if (size > 1) {
9608cecb0aSPierre Jolivet         PetscBool foundpack, issbaij;
979566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)red->pmats, MATMPISBAIJ, &issbaij));
9808cecb0aSPierre Jolivet         if (!issbaij) {
999566063dSJacob Faibussowitsch           PetscCall(MatGetFactorAvailable(red->pmats, NULL, MAT_FACTOR_LU, &foundpack));
10008cecb0aSPierre Jolivet         } else {
1019566063dSJacob Faibussowitsch           PetscCall(MatGetFactorAvailable(red->pmats, NULL, MAT_FACTOR_CHOLESKY, &foundpack));
10208cecb0aSPierre Jolivet         }
103b85f2e9bSHong Zhang         if (!foundpack) { /* reset default ksp and pc */
1049566063dSJacob Faibussowitsch           PetscCall(KSPSetType(red->ksp, KSPGMRES));
1059566063dSJacob Faibussowitsch           PetscCall(PCSetType(red->pc, PCBJACOBI));
106c1619fb6SBarry Smith         } else {
1079566063dSJacob Faibussowitsch           PetscCall(PCFactorSetMatSolverType(red->pc, NULL));
108b85f2e9bSHong Zhang         }
109b85f2e9bSHong Zhang       }
110b85f2e9bSHong Zhang 
1119566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(red->ksp, red->pmats, red->pmats));
1124b9ad928SBarry Smith 
1131b81debcSHong Zhang       /* get working vectors xsub and ysub */
1149566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(red->pmats, &red->xsub, &red->ysub));
1152fa5cd67SKarl Rupp 
1168b96b0d2SHong Zhang       /* create working vectors xdup and ydup.
1178b96b0d2SHong Zhang        xdup concatenates all xsub's contigously to form a mpi vector over dupcomm  (see PetscSubcommCreate_interlaced())
1188b96b0d2SHong Zhang        ydup concatenates all ysub and has empty local arrays because ysub's arrays will be place into it.
119ce94432eSBarry Smith        Note: we use communicator dupcomm, not PetscObjectComm((PetscObject)pc)! */
1209566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(red->pmats, &mloc_sub, NULL));
1219566063dSJacob Faibussowitsch       PetscCall(VecCreateMPI(PetscSubcommContiguousParent(red->psubcomm), mloc_sub, PETSC_DECIDE, &red->xdup));
1229566063dSJacob Faibussowitsch       PetscCall(VecCreateMPIWithArray(PetscSubcommContiguousParent(red->psubcomm), 1, mloc_sub, PETSC_DECIDE, NULL, &red->ydup));
1233f457be1SHong Zhang 
124f68be91cSHong Zhang       /* create vecscatters */
125f68be91cSHong Zhang       if (!red->scatterin) { /* efficiency of scatterin is independent from psubcomm_type! */
1263f457be1SHong Zhang         IS        is1, is2;
1273f457be1SHong Zhang         PetscInt *idx1, *idx2, i, j, k;
12845fc02eaSBarry Smith 
1299566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(pc->pmat, &x, NULL));
1309566063dSJacob Faibussowitsch         PetscCall(VecGetSize(x, &M));
1319566063dSJacob Faibussowitsch         PetscCall(VecGetOwnershipRange(x, &mstart, &mend));
1321b81debcSHong Zhang         mlocal = mend - mstart;
1339566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(red->psubcomm->n * mlocal, &idx1, red->psubcomm->n * mlocal, &idx2));
1343f457be1SHong Zhang         j = 0;
1351fbd8f88SHong Zhang         for (k = 0; k < red->psubcomm->n; k++) {
1363f457be1SHong Zhang           for (i = mstart; i < mend; i++) {
1373f457be1SHong Zhang             idx1[j]   = i;
138ddc54837SHong Zhang             idx2[j++] = i + M * k;
1393f457be1SHong Zhang           }
1403f457be1SHong Zhang         }
1419566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(comm, red->psubcomm->n * mlocal, idx1, PETSC_COPY_VALUES, &is1));
1429566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(comm, red->psubcomm->n * mlocal, idx2, PETSC_COPY_VALUES, &is2));
1439566063dSJacob Faibussowitsch         PetscCall(VecScatterCreate(x, is1, red->xdup, is2, &red->scatterin));
1449566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is1));
1459566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is2));
1463f457be1SHong Zhang 
1476909748bSHong Zhang         /* Impl below is good for PETSC_SUBCOMM_INTERLACED (no inter-process communication) and PETSC_SUBCOMM_CONTIGUOUS (communication within subcomm) */
1489566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(comm, mlocal, mstart + red->psubcomm->color * M, 1, &is1));
1499566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(comm, mlocal, mstart, 1, &is2));
1509566063dSJacob Faibussowitsch         PetscCall(VecScatterCreate(red->xdup, is1, x, is2, &red->scatterout));
1519566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is1));
1529566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&is2));
1539566063dSJacob Faibussowitsch         PetscCall(PetscFree2(idx1, idx2));
1549566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&x));
1551b81debcSHong Zhang       }
156ab661555SHong Zhang     } else { /* !red->useparallelmat */
1579566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(red->ksp, pc->mat, pc->pmat));
1581b81debcSHong Zhang     }
159ab661555SHong Zhang   } else { /* pc->setupcalled */
1604b9ad928SBarry Smith     if (red->useparallelmat) {
161ab661555SHong Zhang       MatReuse reuse;
1621b81debcSHong Zhang       /* grab the parallel matrix and put it into processors of a subcomminicator */
1631b81debcSHong Zhang       /*--------------------------------------------------------------------------*/
164ab661555SHong Zhang       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
1654b9ad928SBarry Smith         /* destroy old matrices */
1669566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&red->pmats));
167ab661555SHong Zhang         reuse = MAT_INITIAL_MATRIX;
1684b9ad928SBarry Smith       } else {
169ab661555SHong Zhang         reuse = MAT_REUSE_MATRIX;
170ab661555SHong Zhang       }
1719566063dSJacob Faibussowitsch       PetscCall(MatCreateRedundantMatrix(pc->pmat, red->psubcomm->n, PetscSubcommChild(red->psubcomm), reuse, &red->pmats));
1729566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(red->ksp, red->pmats, red->pmats));
173ab661555SHong Zhang     } else { /* !red->useparallelmat */
1749566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(red->ksp, pc->mat, pc->pmat));
1754b9ad928SBarry Smith     }
176ab661555SHong Zhang   }
1771b81debcSHong Zhang 
1781baa6e33SBarry Smith   if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(red->ksp));
1799566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(red->ksp));
1804b9ad928SBarry Smith   PetscFunctionReturn(0);
1814b9ad928SBarry Smith }
1824b9ad928SBarry Smith 
183d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_Redundant(PC pc, Vec x, Vec y)
184d71ae5a4SJacob Faibussowitsch {
1854b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
1863f457be1SHong Zhang   PetscScalar  *array;
1874b9ad928SBarry Smith 
1884b9ad928SBarry Smith   PetscFunctionBegin;
189ddc54837SHong Zhang   if (!red->useparallelmat) {
1909566063dSJacob Faibussowitsch     PetscCall(KSPSolve(red->ksp, x, y));
1919566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(red->ksp, pc, y));
192ddc54837SHong Zhang     PetscFunctionReturn(0);
193ddc54837SHong Zhang   }
194ddc54837SHong Zhang 
1953f457be1SHong Zhang   /* scatter x to xdup */
1969566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD));
1979566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD));
1983f457be1SHong Zhang 
1993f457be1SHong Zhang   /* place xdup's local array into xsub */
2009566063dSJacob Faibussowitsch   PetscCall(VecGetArray(red->xdup, &array));
2019566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array));
2024b9ad928SBarry Smith 
2034b9ad928SBarry Smith   /* apply preconditioner on each processor */
2049566063dSJacob Faibussowitsch   PetscCall(KSPSolve(red->ksp, red->xsub, red->ysub));
2059566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(red->ksp, pc, red->ysub));
2069566063dSJacob Faibussowitsch   PetscCall(VecResetArray(red->xsub));
2079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(red->xdup, &array));
2084b9ad928SBarry Smith 
2093f457be1SHong Zhang   /* place ysub's local array into ydup */
2109566063dSJacob Faibussowitsch   PetscCall(VecGetArray(red->ysub, &array));
2119566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array));
2123f457be1SHong Zhang 
2133f457be1SHong Zhang   /* scatter ydup to y */
2149566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD));
2159566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD));
2169566063dSJacob Faibussowitsch   PetscCall(VecResetArray(red->ydup));
2179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(red->ysub, &array));
2184b9ad928SBarry Smith   PetscFunctionReturn(0);
2194b9ad928SBarry Smith }
2204b9ad928SBarry Smith 
221d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_Redundant(PC pc, Vec x, Vec y)
222d71ae5a4SJacob Faibussowitsch {
223d88bfacbSStefano Zampini   PC_Redundant *red = (PC_Redundant *)pc->data;
224d88bfacbSStefano Zampini   PetscScalar  *array;
225d88bfacbSStefano Zampini 
226d88bfacbSStefano Zampini   PetscFunctionBegin;
227d88bfacbSStefano Zampini   if (!red->useparallelmat) {
2289566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(red->ksp, x, y));
2299566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(red->ksp, pc, y));
230d88bfacbSStefano Zampini     PetscFunctionReturn(0);
231d88bfacbSStefano Zampini   }
232d88bfacbSStefano Zampini 
233d88bfacbSStefano Zampini   /* scatter x to xdup */
2349566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD));
2359566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD));
236d88bfacbSStefano Zampini 
237d88bfacbSStefano Zampini   /* place xdup's local array into xsub */
2389566063dSJacob Faibussowitsch   PetscCall(VecGetArray(red->xdup, &array));
2399566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array));
240d88bfacbSStefano Zampini 
241d88bfacbSStefano Zampini   /* apply preconditioner on each processor */
2429566063dSJacob Faibussowitsch   PetscCall(KSPSolveTranspose(red->ksp, red->xsub, red->ysub));
2439566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(red->ksp, pc, red->ysub));
2449566063dSJacob Faibussowitsch   PetscCall(VecResetArray(red->xsub));
2459566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(red->xdup, &array));
246d88bfacbSStefano Zampini 
247d88bfacbSStefano Zampini   /* place ysub's local array into ydup */
2489566063dSJacob Faibussowitsch   PetscCall(VecGetArray(red->ysub, &array));
2499566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array));
250d88bfacbSStefano Zampini 
251d88bfacbSStefano Zampini   /* scatter ydup to y */
2529566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD));
2539566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD));
2549566063dSJacob Faibussowitsch   PetscCall(VecResetArray(red->ydup));
2559566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(red->ysub, &array));
256d88bfacbSStefano Zampini   PetscFunctionReturn(0);
257d88bfacbSStefano Zampini }
258d88bfacbSStefano Zampini 
259d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_Redundant(PC pc)
260d71ae5a4SJacob Faibussowitsch {
2614b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
2624b9ad928SBarry Smith 
2634b9ad928SBarry Smith   PetscFunctionBegin;
2641b81debcSHong Zhang   if (red->useparallelmat) {
2659566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&red->scatterin));
2669566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&red->scatterout));
2679566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&red->ysub));
2689566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&red->xsub));
2699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&red->xdup));
2709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&red->ydup));
2711b81debcSHong Zhang   }
2729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&red->pmats));
2739566063dSJacob Faibussowitsch   PetscCall(KSPReset(red->ksp));
2741ea5a559SBarry Smith   PetscFunctionReturn(0);
2751ea5a559SBarry Smith }
2761ea5a559SBarry Smith 
277d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_Redundant(PC pc)
278d71ae5a4SJacob Faibussowitsch {
2791ea5a559SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
2801ea5a559SBarry Smith 
2811ea5a559SBarry Smith   PetscFunctionBegin;
2829566063dSJacob Faibussowitsch   PetscCall(PCReset_Redundant(pc));
2839566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&red->ksp));
2849566063dSJacob Faibussowitsch   PetscCall(PetscSubcommDestroy(&red->psubcomm));
2852e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetScatter_C", NULL));
2862e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetNumber_C", NULL));
2872e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetKSP_C", NULL));
2882e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetOperators_C", NULL));
2892e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFactorSetShiftType_C", NULL));
2909566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
2914b9ad928SBarry Smith   PetscFunctionReturn(0);
2924b9ad928SBarry Smith }
2934b9ad928SBarry Smith 
294d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_Redundant(PC pc, PetscOptionItems *PetscOptionsObject)
295d71ae5a4SJacob Faibussowitsch {
296a98ce0f4SHong Zhang   PC_Redundant *red = (PC_Redundant *)pc->data;
297a98ce0f4SHong Zhang 
2984b9ad928SBarry Smith   PetscFunctionBegin;
299d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Redundant options");
3009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_redundant_number", "Number of redundant pc", "PCRedundantSetNumber", red->nsubcomm, &red->nsubcomm, NULL));
301d0609cedSBarry Smith   PetscOptionsHeadEnd();
3024b9ad928SBarry Smith   PetscFunctionReturn(0);
3034b9ad928SBarry Smith }
3044b9ad928SBarry Smith 
305d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCRedundantSetNumber_Redundant(PC pc, PetscInt nreds)
306d71ae5a4SJacob Faibussowitsch {
30709a6bc64SHong Zhang   PC_Redundant *red = (PC_Redundant *)pc->data;
30809a6bc64SHong Zhang 
30909a6bc64SHong Zhang   PetscFunctionBegin;
31009a6bc64SHong Zhang   red->nsubcomm = nreds;
31109a6bc64SHong Zhang   PetscFunctionReturn(0);
31209a6bc64SHong Zhang }
31309a6bc64SHong Zhang 
31409a6bc64SHong Zhang /*@
31509a6bc64SHong Zhang    PCRedundantSetNumber - Sets the number of redundant preconditioner contexts.
31609a6bc64SHong Zhang 
317*c3339decSBarry Smith    Logically Collective
31809a6bc64SHong Zhang 
31909a6bc64SHong Zhang    Input Parameters:
32009a6bc64SHong Zhang +  pc - the preconditioner context
3219b21d695SBarry Smith -  nredundant - number of redundant preconditioner contexts; for example if you are using 64 MPI processes and
3229b21d695SBarry Smith                               use an nredundant of 4 there will be 4 parallel solves each on 16 = 64/4 processes.
32309a6bc64SHong Zhang 
32409a6bc64SHong Zhang    Level: advanced
32509a6bc64SHong Zhang 
326f1580f4eSBarry Smith .seealso: `PCREDUNDANT`
32709a6bc64SHong Zhang @*/
328d71ae5a4SJacob Faibussowitsch PetscErrorCode PCRedundantSetNumber(PC pc, PetscInt nredundant)
329d71ae5a4SJacob Faibussowitsch {
33009a6bc64SHong Zhang   PetscFunctionBegin;
3310700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
33263a3b9bcSJacob Faibussowitsch   PetscCheck(nredundant > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "num of redundant pc %" PetscInt_FMT " must be positive", nredundant);
333cac4c232SBarry Smith   PetscTryMethod(pc, "PCRedundantSetNumber_C", (PC, PetscInt), (pc, nredundant));
33409a6bc64SHong Zhang   PetscFunctionReturn(0);
33509a6bc64SHong Zhang }
33609a6bc64SHong Zhang 
337d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCRedundantSetScatter_Redundant(PC pc, VecScatter in, VecScatter out)
338d71ae5a4SJacob Faibussowitsch {
3394b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
3404b9ad928SBarry Smith 
3414b9ad928SBarry Smith   PetscFunctionBegin;
3429566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)in));
3439566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&red->scatterin));
3442fa5cd67SKarl Rupp 
345c3122656SLisandro Dalcin   red->scatterin = in;
3462fa5cd67SKarl Rupp 
3479566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)out));
3489566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&red->scatterout));
349c3122656SLisandro Dalcin   red->scatterout = out;
3504b9ad928SBarry Smith   PetscFunctionReturn(0);
3514b9ad928SBarry Smith }
3524b9ad928SBarry Smith 
3534b9ad928SBarry Smith /*@
3544b9ad928SBarry Smith    PCRedundantSetScatter - Sets the scatter used to copy values into the
3554b9ad928SBarry Smith      redundant local solve and the scatter to move them back into the global
3564b9ad928SBarry Smith      vector.
3574b9ad928SBarry Smith 
358*c3339decSBarry Smith    Logically Collective
3594b9ad928SBarry Smith 
3604b9ad928SBarry Smith    Input Parameters:
3614b9ad928SBarry Smith +  pc - the preconditioner context
3624b9ad928SBarry Smith .  in - the scatter to move the values in
3634b9ad928SBarry Smith -  out - the scatter to move them out
3644b9ad928SBarry Smith 
3654b9ad928SBarry Smith    Level: advanced
3664b9ad928SBarry Smith 
367f1580f4eSBarry Smith .seealso: `PCREDUNDANT`
3684b9ad928SBarry Smith @*/
369d71ae5a4SJacob Faibussowitsch PetscErrorCode PCRedundantSetScatter(PC pc, VecScatter in, VecScatter out)
370d71ae5a4SJacob Faibussowitsch {
3714b9ad928SBarry Smith   PetscFunctionBegin;
3720700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
37397929ea7SJunchao Zhang   PetscValidHeaderSpecific(in, PETSCSF_CLASSID, 2);
37497929ea7SJunchao Zhang   PetscValidHeaderSpecific(out, PETSCSF_CLASSID, 3);
375cac4c232SBarry Smith   PetscTryMethod(pc, "PCRedundantSetScatter_C", (PC, VecScatter, VecScatter), (pc, in, out));
3764b9ad928SBarry Smith   PetscFunctionReturn(0);
3774b9ad928SBarry Smith }
3784b9ad928SBarry Smith 
379d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCRedundantGetKSP_Redundant(PC pc, KSP *innerksp)
380d71ae5a4SJacob Faibussowitsch {
3814b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
38275024027SHong Zhang   MPI_Comm      comm, subcomm;
38375024027SHong Zhang   const char   *prefix;
38408cecb0aSPierre Jolivet   PetscBool     issbaij;
3854b9ad928SBarry Smith 
3864b9ad928SBarry Smith   PetscFunctionBegin;
38775024027SHong Zhang   if (!red->psubcomm) {
3889566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
389e5acf8a4SHong Zhang 
3909566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3919566063dSJacob Faibussowitsch     PetscCall(PetscSubcommCreate(comm, &red->psubcomm));
3929566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetNumber(red->psubcomm, red->nsubcomm));
3939566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetType(red->psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
394e5acf8a4SHong Zhang 
3959566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetOptionsPrefix(red->psubcomm, prefix));
3969566063dSJacob Faibussowitsch     PetscCall(PetscSubcommSetFromOptions(red->psubcomm));
39775024027SHong Zhang 
39875024027SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
39975024027SHong Zhang     subcomm = PetscSubcommChild(red->psubcomm);
40075024027SHong Zhang 
4019566063dSJacob Faibussowitsch     PetscCall(KSPCreate(subcomm, &red->ksp));
4029566063dSJacob Faibussowitsch     PetscCall(KSPSetErrorIfNotConverged(red->ksp, pc->erroriffailure));
4039566063dSJacob Faibussowitsch     PetscCall(PetscObjectIncrementTabLevel((PetscObject)red->ksp, (PetscObject)pc, 1));
4049566063dSJacob Faibussowitsch     PetscCall(KSPSetType(red->ksp, KSPPREONLY));
4059566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(red->ksp, &red->pc));
4069566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATSEQSBAIJ, &issbaij));
40748a46eb9SPierre Jolivet     if (!issbaij) PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATMPISBAIJ, &issbaij));
40808cecb0aSPierre Jolivet     if (!issbaij) {
4099566063dSJacob Faibussowitsch       PetscCall(PCSetType(red->pc, PCLU));
41008cecb0aSPierre Jolivet     } else {
4119566063dSJacob Faibussowitsch       PetscCall(PCSetType(red->pc, PCCHOLESKY));
41208cecb0aSPierre Jolivet     }
413753b7fb9SBarry Smith     if (red->shifttypeset) {
4149566063dSJacob Faibussowitsch       PetscCall(PCFactorSetShiftType(red->pc, red->shifttype));
415753b7fb9SBarry Smith       red->shifttypeset = PETSC_FALSE;
416753b7fb9SBarry Smith     }
4179566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(red->ksp, prefix));
4189566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(red->ksp, "redundant_"));
41975024027SHong Zhang   }
42083ab6a24SBarry Smith   *innerksp = red->ksp;
4214b9ad928SBarry Smith   PetscFunctionReturn(0);
4224b9ad928SBarry Smith }
4234b9ad928SBarry Smith 
4244b9ad928SBarry Smith /*@
425f1580f4eSBarry Smith    PCRedundantGetKSP - Gets the less parallel `KSP` created by the redundant `PC`.
4264b9ad928SBarry Smith 
4274b9ad928SBarry Smith    Not Collective
4284b9ad928SBarry Smith 
4294b9ad928SBarry Smith    Input Parameter:
4304b9ad928SBarry Smith .  pc - the preconditioner context
4314b9ad928SBarry Smith 
4324b9ad928SBarry Smith    Output Parameter:
433f1580f4eSBarry Smith .  innerksp - the `KSP` on the smaller set of processes
4344b9ad928SBarry Smith 
4354b9ad928SBarry Smith    Level: advanced
4364b9ad928SBarry Smith 
437f1580f4eSBarry Smith .seealso: `PCREDUNDANT`
4384b9ad928SBarry Smith @*/
439d71ae5a4SJacob Faibussowitsch PetscErrorCode PCRedundantGetKSP(PC pc, KSP *innerksp)
440d71ae5a4SJacob Faibussowitsch {
4414b9ad928SBarry Smith   PetscFunctionBegin;
4420700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
44383ab6a24SBarry Smith   PetscValidPointer(innerksp, 2);
444cac4c232SBarry Smith   PetscUseMethod(pc, "PCRedundantGetKSP_C", (PC, KSP *), (pc, innerksp));
4454b9ad928SBarry Smith   PetscFunctionReturn(0);
4464b9ad928SBarry Smith }
4474b9ad928SBarry Smith 
448d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCRedundantGetOperators_Redundant(PC pc, Mat *mat, Mat *pmat)
449d71ae5a4SJacob Faibussowitsch {
4504b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant *)pc->data;
4514b9ad928SBarry Smith 
4524b9ad928SBarry Smith   PetscFunctionBegin;
453b3804887SHong Zhang   if (mat) *mat = red->pmats;
454b3804887SHong Zhang   if (pmat) *pmat = red->pmats;
4554b9ad928SBarry Smith   PetscFunctionReturn(0);
4564b9ad928SBarry Smith }
4574b9ad928SBarry Smith 
4584b9ad928SBarry Smith /*@
4594b9ad928SBarry Smith    PCRedundantGetOperators - gets the sequential matrix and preconditioner matrix
4604b9ad928SBarry Smith 
4614b9ad928SBarry Smith    Not Collective
4624b9ad928SBarry Smith 
4634b9ad928SBarry Smith    Input Parameter:
4644b9ad928SBarry Smith .  pc - the preconditioner context
4654b9ad928SBarry Smith 
4664b9ad928SBarry Smith    Output Parameters:
4674b9ad928SBarry Smith +  mat - the matrix
4684b9ad928SBarry Smith -  pmat - the (possibly different) preconditioner matrix
4694b9ad928SBarry Smith 
4704b9ad928SBarry Smith    Level: advanced
4714b9ad928SBarry Smith 
472f1580f4eSBarry Smith .seealso: `PCREDUNDANT`
4734b9ad928SBarry Smith @*/
474d71ae5a4SJacob Faibussowitsch PetscErrorCode PCRedundantGetOperators(PC pc, Mat *mat, Mat *pmat)
475d71ae5a4SJacob Faibussowitsch {
4764b9ad928SBarry Smith   PetscFunctionBegin;
4770700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4784482741eSBarry Smith   if (mat) PetscValidPointer(mat, 2);
4794482741eSBarry Smith   if (pmat) PetscValidPointer(pmat, 3);
480cac4c232SBarry Smith   PetscUseMethod(pc, "PCRedundantGetOperators_C", (PC, Mat *, Mat *), (pc, mat, pmat));
4814b9ad928SBarry Smith   PetscFunctionReturn(0);
4824b9ad928SBarry Smith }
4834b9ad928SBarry Smith 
48437a17b4dSBarry Smith /*MC
485f1580f4eSBarry Smith      PCREDUNDANT - Runs a `KSP` solver with preconditioner for the entire problem on subgroups of processors
48637a17b4dSBarry Smith 
487f1580f4eSBarry Smith   Options Database Key:
4889b21d695SBarry Smith .  -pc_redundant_number <n> - number of redundant solves, for example if you are using 64 MPI processes and
4899b21d695SBarry Smith                               use an n of 4 there will be 4 parallel solves each on 16 = 64/4 processes.
49009391456SBarry Smith 
49137a17b4dSBarry Smith    Level: intermediate
49237a17b4dSBarry Smith 
49395452b02SPatrick Sanan    Notes:
494f1580f4eSBarry Smith    Options for the redundant preconditioners can be set using the options database prefix -redundant_
49583ab6a24SBarry Smith 
496f1580f4eSBarry Smith    The default `KSP` is preonly and the default `PC` is `PCLU` or `PCCHOLESKY` if Pmat is of type `MATSBAIJ`.
497753b7fb9SBarry Smith 
498f1580f4eSBarry Smith    `PCFactorSetShiftType()` applied to this `PC` will convey they shift type into the inner `PC` if it is factorization based.
499f1580f4eSBarry Smith 
500f1580f4eSBarry Smith    Developer Note:
501f1580f4eSBarry Smith    `PCSetInitialGuessNonzero()` is not used by this class but likely should be.
5029cfaa89bSBarry Smith 
503db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PCRedundantSetScatter()`,
504f1580f4eSBarry Smith           `PCRedundantGetKSP()`, `PCRedundantGetOperators()`, `PCRedundantSetNumber()`, `PCREDISTRIBUTE`
50537a17b4dSBarry Smith M*/
50637a17b4dSBarry Smith 
507d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_Redundant(PC pc)
508d71ae5a4SJacob Faibussowitsch {
5094b9ad928SBarry Smith   PC_Redundant *red;
51069db28dcSHong Zhang   PetscMPIInt   size;
5113f457be1SHong Zhang 
5124b9ad928SBarry Smith   PetscFunctionBegin;
5134dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&red));
5149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));
5152fa5cd67SKarl Rupp 
51669db28dcSHong Zhang   red->nsubcomm       = size;
5174b9ad928SBarry Smith   red->useparallelmat = PETSC_TRUE;
5181fbd8f88SHong Zhang   pc->data            = (void *)red;
5194b9ad928SBarry Smith 
5204b9ad928SBarry Smith   pc->ops->apply          = PCApply_Redundant;
521d88bfacbSStefano Zampini   pc->ops->applytranspose = PCApplyTranspose_Redundant;
5224b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_Redundant;
5234b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_Redundant;
5241ea5a559SBarry Smith   pc->ops->reset          = PCReset_Redundant;
5254b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Redundant;
5264b9ad928SBarry Smith   pc->ops->view           = PCView_Redundant;
5272fa5cd67SKarl Rupp 
5289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetScatter_C", PCRedundantSetScatter_Redundant));
5299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetNumber_C", PCRedundantSetNumber_Redundant));
5309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetKSP_C", PCRedundantGetKSP_Redundant));
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetOperators_C", PCRedundantGetOperators_Redundant));
5329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFactorSetShiftType_C", PCFactorSetShiftType_Redundant));
5334b9ad928SBarry Smith   PetscFunctionReturn(0);
5344b9ad928SBarry Smith }
535