xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 2611ad710242b3c70d66651ef7e40f9450d305e2)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/
641b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h>
71e25c274SJed Brown #include <petscdm.h>
8391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *);
94b9ad928SBarry Smith 
10f3b08a26SMatthew G. Knepley /*
11f3b08a26SMatthew G. Knepley    Contains the list of registered coarse space construction routines
12f3b08a26SMatthew G. Knepley */
13f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL;
14f3b08a26SMatthew G. Knepley 
15d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason)
16d71ae5a4SJacob Faibussowitsch {
1731567311SBarry Smith   PC_MG        *mg = (PC_MG *)pc->data;
1831567311SBarry Smith   PC_MG_Levels *mgc, *mglevels = *mglevelsin;
1931567311SBarry Smith   PetscInt      cycles = (mglevels->level == 1) ? 1 : (PetscInt)mglevels->cycles;
204b9ad928SBarry Smith 
214b9ad928SBarry Smith   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
23fcb023d4SJed Brown   if (!transpose) {
2430b0564aSStefano Zampini     if (matapp) {
259566063dSJacob Faibussowitsch       PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */
269566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL));
2730b0564aSStefano Zampini     } else {
289566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */
299566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
3030b0564aSStefano Zampini     }
31fcb023d4SJed Brown   } else {
3228b400f6SJacob Faibussowitsch     PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
339566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */
349566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
35fcb023d4SJed Brown   }
369566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
3731567311SBarry Smith   if (mglevels->level) { /* not the coarsest grid */
389566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0));
3948a46eb9SPierre Jolivet     if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R));
40fcb023d4SJed Brown     if (!transpose) {
419566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
429566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
43fcb023d4SJed Brown     } else {
449566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
459566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
46fcb023d4SJed Brown     }
479566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0));
484b9ad928SBarry Smith 
494b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
5031567311SBarry Smith     if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) {
514b9ad928SBarry Smith       PetscReal rnorm;
529566063dSJacob Faibussowitsch       PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm));
534b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
5470441072SBarry Smith         if (rnorm < mg->abstol) {
554d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
569566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol));
574b9ad928SBarry Smith         } else {
584d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
599566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n", (double)rnorm, (double)mg->ttol));
604b9ad928SBarry Smith         }
613ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
624b9ad928SBarry Smith       }
634b9ad928SBarry Smith     }
644b9ad928SBarry Smith 
6531567311SBarry Smith     mgc = *(mglevelsin - 1);
669566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
67fcb023d4SJed Brown     if (!transpose) {
689566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B));
699566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b));
70fcb023d4SJed Brown     } else {
719566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B));
729566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b));
73fcb023d4SJed Brown     }
749566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
7530b0564aSStefano Zampini     if (matapp) {
7630b0564aSStefano Zampini       if (!mgc->X) {
779566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X));
7830b0564aSStefano Zampini       } else {
799566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(mgc->X));
8030b0564aSStefano Zampini       }
8130b0564aSStefano Zampini     } else {
829566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mgc->x));
8330b0564aSStefano Zampini     }
8448a46eb9SPierre Jolivet     while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason));
859566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
86fcb023d4SJed Brown     if (!transpose) {
879566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X));
889566063dSJacob Faibussowitsch       else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x));
89fcb023d4SJed Brown     } else {
909566063dSJacob Faibussowitsch       PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x));
91fcb023d4SJed Brown     }
929566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
939566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
94fcb023d4SJed Brown     if (!transpose) {
9530b0564aSStefano Zampini       if (matapp) {
969566063dSJacob Faibussowitsch         PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */
979566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL));
9830b0564aSStefano Zampini       } else {
999566063dSJacob Faibussowitsch         PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */
1009566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
10130b0564aSStefano Zampini       }
102fcb023d4SJed Brown     } else {
10328b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
1049566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */
1059566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
106fcb023d4SJed Brown     }
10741b6fd38SMatthew G. Knepley     if (mglevels->cr) {
10828b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
10941b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1109566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1119566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
1129566063dSJacob Faibussowitsch       PetscCall(KSPSetNoisy_Private(mglevels->crx));
1139566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1149566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11541b6fd38SMatthew G. Knepley     }
1169566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1174b9ad928SBarry Smith   }
1183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1194b9ad928SBarry Smith }
1204b9ad928SBarry Smith 
121d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyRichardson_MG(PC pc, Vec b, Vec x, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt its, PetscBool zeroguess, PetscInt *outits, PCRichardsonConvergedReason *reason)
122d71ae5a4SJacob Faibussowitsch {
123f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
124f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
125391689abSStefano Zampini   PC             tpc;
126391689abSStefano Zampini   PetscBool      changeu, changed;
127f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
1284b9ad928SBarry Smith 
1294b9ad928SBarry Smith   PetscFunctionBegin;
130a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
131a762d673SBarry Smith   for (i = 0; i < levels; i++) {
132a762d673SBarry Smith     if (!mglevels[i]->A) {
1339566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1349566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
135a762d673SBarry Smith     }
136a762d673SBarry Smith   }
137391689abSStefano Zampini 
1389566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1399566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1409566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1419566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
142391689abSStefano Zampini   if (!changed && !changeu) {
1439566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels - 1]->b));
144f3fbd535SBarry Smith     mglevels[levels - 1]->b = b;
145391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
146391689abSStefano Zampini     if (!mglevels[levels - 1]->b) {
147391689abSStefano Zampini       Vec *vec;
148391689abSStefano Zampini 
1499566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
150391689abSStefano Zampini       mglevels[levels - 1]->b = *vec;
1519566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
152391689abSStefano Zampini     }
1539566063dSJacob Faibussowitsch     PetscCall(VecCopy(b, mglevels[levels - 1]->b));
154391689abSStefano Zampini   }
155f3fbd535SBarry Smith   mglevels[levels - 1]->x = x;
1564b9ad928SBarry Smith 
15731567311SBarry Smith   mg->rtol   = rtol;
15831567311SBarry Smith   mg->abstol = abstol;
15931567311SBarry Smith   mg->dtol   = dtol;
1604b9ad928SBarry Smith   if (rtol) {
1614b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1624b9ad928SBarry Smith     PetscReal rnorm;
1637319c654SBarry Smith     if (zeroguess) {
1649566063dSJacob Faibussowitsch       PetscCall(VecNorm(b, NORM_2, &rnorm));
1657319c654SBarry Smith     } else {
1669566063dSJacob Faibussowitsch       PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1679566063dSJacob Faibussowitsch       PetscCall(VecNorm(w, NORM_2, &rnorm));
1687319c654SBarry Smith     }
16931567311SBarry Smith     mg->ttol = PetscMax(rtol * rnorm, abstol);
1702fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1712fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1724b9ad928SBarry Smith 
1734d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
174336babb1SJed Brown      stop prematurely due to small residual */
1754d0a8057SBarry Smith   for (i = 1; i < levels; i++) {
1769566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
177f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
17823067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1799566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1809566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
1814b9ad928SBarry Smith     }
1824d0a8057SBarry Smith   }
1834d0a8057SBarry Smith 
1844d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
1854d0a8057SBarry Smith   for (i = 0; i < its; i++) {
1869566063dSJacob Faibussowitsch     PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1874d0a8057SBarry Smith     if (*reason) break;
1884d0a8057SBarry Smith   }
1894d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1904d0a8057SBarry Smith   *outits = i;
191391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1934b9ad928SBarry Smith }
1944b9ad928SBarry Smith 
195d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc)
196d71ae5a4SJacob Faibussowitsch {
1973aeaf226SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1983aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1992b3cbbdaSStefano Zampini   PetscInt       i, n;
2003aeaf226SBarry Smith 
2013aeaf226SBarry Smith   PetscFunctionBegin;
2023aeaf226SBarry Smith   if (mglevels) {
2033aeaf226SBarry Smith     n = mglevels[0]->levels;
2043aeaf226SBarry Smith     for (i = 0; i < n - 1; i++) {
2059566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->r));
2069566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->b));
2079566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->x));
2089566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->R));
2099566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->B));
2109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->X));
2119566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crx));
2129566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crb));
2139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2169566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2173aeaf226SBarry Smith     }
2189566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crb));
220391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
221391689abSStefano Zampini        changes the rhs during PreSolve */
2229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->b));
2239566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mglevels[n - 1]->B));
2243aeaf226SBarry Smith 
2253aeaf226SBarry Smith     for (i = 0; i < n; i++) {
2262b3cbbdaSStefano Zampini       PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2279566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->A));
22848a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2299566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2309566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2313aeaf226SBarry Smith     }
232f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2333aeaf226SBarry Smith   }
2343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2353aeaf226SBarry Smith }
2363aeaf226SBarry Smith 
23741b6fd38SMatthew G. Knepley /* Implementing CR
23841b6fd38SMatthew G. Knepley 
23941b6fd38SMatthew G. Knepley We only want to make corrections that ``do not change'' the coarse solution. What we mean by not changing is that if I prolong my coarse solution to the fine grid and then inject that fine solution back to the coarse grid, I get the same answer. Injection is what Brannick calls R. We want the complementary projector to Inj, which we will call S, after Brannick, so that Inj S = 0. Now the orthogonal projector onto the range of Inj^T is
24041b6fd38SMatthew G. Knepley 
24141b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
24241b6fd38SMatthew G. Knepley 
24341b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24441b6fd38SMatthew G. Knepley 
24541b6fd38SMatthew G. Knepley   Inj^T Inj
24641b6fd38SMatthew G. Knepley 
24741b6fd38SMatthew G. Knepley and
24841b6fd38SMatthew G. Knepley 
24941b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
25041b6fd38SMatthew G. Knepley 
25141b6fd38SMatthew G. Knepley since
25241b6fd38SMatthew G. Knepley 
25341b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
25441b6fd38SMatthew G. Knepley 
25541b6fd38SMatthew G. Knepley Brannick suggests
25641b6fd38SMatthew G. Knepley 
25741b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
25841b6fd38SMatthew G. Knepley 
25941b6fd38SMatthew G. Knepley but I do not think his :math:`S^T S = I` is correct. Our S is an orthogonal projector, so :math:`S^T S = S^2 = S`. We will use
26041b6fd38SMatthew G. Knepley 
26141b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
26241b6fd38SMatthew G. Knepley 
26341b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26441b6fd38SMatthew G. Knepley 
26541b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
26641b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
26741b6fd38SMatthew G. Knepley */
26841b6fd38SMatthew G. Knepley 
26941b6fd38SMatthew G. Knepley typedef struct {
27041b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
27141b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
27241b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27341b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
27441b6fd38SMatthew G. Knepley } CRContext;
27541b6fd38SMatthew G. Knepley 
276d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc)
277d71ae5a4SJacob Faibussowitsch {
27841b6fd38SMatthew G. Knepley   CRContext *ctx;
27941b6fd38SMatthew G. Knepley   Mat        It;
28041b6fd38SMatthew G. Knepley 
28141b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2829566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2839566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28428b400f6SJacob Faibussowitsch   PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2859566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2869566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2879566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2889566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S, 1.0));
2893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29041b6fd38SMatthew G. Knepley }
29141b6fd38SMatthew G. Knepley 
292d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
293d71ae5a4SJacob Faibussowitsch {
29441b6fd38SMatthew G. Knepley   CRContext *ctx;
29541b6fd38SMatthew G. Knepley 
29641b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2979566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2989566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30041b6fd38SMatthew G. Knepley }
30141b6fd38SMatthew G. Knepley 
302d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc)
303d71ae5a4SJacob Faibussowitsch {
30441b6fd38SMatthew G. Knepley   CRContext *ctx;
30541b6fd38SMatthew G. Knepley 
30641b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3079566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3109566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3119566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
3123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31341b6fd38SMatthew G. Knepley }
31441b6fd38SMatthew G. Knepley 
315d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
316d71ae5a4SJacob Faibussowitsch {
31741b6fd38SMatthew G. Knepley   CRContext *ctx;
31841b6fd38SMatthew G. Knepley 
31941b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3209566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3219566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3229566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
32341b6fd38SMatthew G. Knepley   ctx->mg = pc;
32441b6fd38SMatthew G. Knepley   ctx->l  = l;
3259566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3269566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3279566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3289566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3299566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
3303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33141b6fd38SMatthew G. Knepley }
33241b6fd38SMatthew G. Knepley 
333d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms)
334d71ae5a4SJacob Faibussowitsch {
335f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG *)pc->data;
336ce94432eSBarry Smith   MPI_Comm       comm;
3373aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
33810eca3edSLisandro Dalcin   PCMGType       mgtype   = mg->am;
33910167fecSBarry Smith   PetscInt       mgctype  = (PetscInt)PC_MG_CYCLE_V;
340f3fbd535SBarry Smith   PetscInt       i;
341f3fbd535SBarry Smith   PetscMPIInt    size;
342f3fbd535SBarry Smith   const char    *prefix;
343f3fbd535SBarry Smith   PC             ipc;
3443aeaf226SBarry Smith   PetscInt       n;
3454b9ad928SBarry Smith 
3464b9ad928SBarry Smith   PetscFunctionBegin;
3470700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
348548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc, levels, 2);
3493ba16761SJacob Faibussowitsch   if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS);
3509566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3513aeaf226SBarry Smith   if (mglevels) {
35210eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
3533aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
3549566063dSJacob Faibussowitsch     PetscCall(PCReset_MG(pc));
3553aeaf226SBarry Smith     n = mglevels[0]->levels;
3563aeaf226SBarry Smith     for (i = 0; i < n; i++) {
35748a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3589566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3599566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3609566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3613aeaf226SBarry Smith     }
3629566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3633aeaf226SBarry Smith   }
364f3fbd535SBarry Smith 
365f3fbd535SBarry Smith   mg->nlevels = levels;
366f3fbd535SBarry Smith 
3679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels, &mglevels));
368f3fbd535SBarry Smith 
3699566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
370f3fbd535SBarry Smith 
371a9db87a2SMatthew G Knepley   mg->stageApply = 0;
372f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
3734dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mglevels[i]));
3742fa5cd67SKarl Rupp 
375f3fbd535SBarry Smith     mglevels[i]->level               = i;
376f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
37710eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
378336babb1SJed Brown     mg->default_smoothu              = 2;
379336babb1SJed Brown     mg->default_smoothd              = 2;
38063e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
38163e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
38263e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
38363e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
384f3fbd535SBarry Smith 
385f3fbd535SBarry Smith     if (comms) comm = comms[i];
386d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3879566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3883821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel));
3899566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3909566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3919566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3929566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3930ee9a668SBarry Smith       if (i || levels == 1) {
3940ee9a668SBarry Smith         char tprefix[128];
3950ee9a668SBarry Smith 
3969566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
3979566063dSJacob Faibussowitsch         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
3989566063dSJacob Faibussowitsch         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
3999566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
4009566063dSJacob Faibussowitsch         PetscCall(PCSetType(ipc, PCSOR));
4019566063dSJacob Faibussowitsch         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
402f3fbd535SBarry Smith 
4039566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%d_", (int)i));
4049566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4050ee9a668SBarry Smith       } else {
4069566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
407f3fbd535SBarry Smith 
4089dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4099566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4109566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4119566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
412f3fbd535SBarry Smith         if (size > 1) {
4139566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
414f3fbd535SBarry Smith         } else {
4159566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
416f3fbd535SBarry Smith         }
4179566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
418f3fbd535SBarry Smith       }
419d5a8f7e6SBarry Smith     }
420f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
42131567311SBarry Smith     mg->rtol             = 0.0;
42231567311SBarry Smith     mg->abstol           = 0.0;
42331567311SBarry Smith     mg->dtol             = 0.0;
42431567311SBarry Smith     mg->ttol             = 0.0;
42531567311SBarry Smith     mg->cyclesperpcapply = 1;
426f3fbd535SBarry Smith   }
427f3fbd535SBarry Smith   mg->levels = mglevels;
4289566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4304b9ad928SBarry Smith }
4314b9ad928SBarry Smith 
43297d33e41SMatthew G. Knepley /*@C
433f1580f4eSBarry Smith   PCMGSetLevels - Sets the number of levels to use with `PCMG`.
434f1580f4eSBarry Smith   Must be called before any other `PCMG` routine.
43597d33e41SMatthew G. Knepley 
436c3339decSBarry Smith   Logically Collective
43797d33e41SMatthew G. Knepley 
43897d33e41SMatthew G. Knepley   Input Parameters:
43997d33e41SMatthew G. Knepley + pc     - the preconditioner context
44097d33e41SMatthew G. Knepley . levels - the number of levels
44197d33e41SMatthew G. Knepley - comms  - optional communicators for each level; this is to allow solving the coarser problems
442d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
44320f4b53cSBarry Smith            you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes
44405552d4bSJunchao Zhang            should participate in each level of problem.
44597d33e41SMatthew G. Knepley 
44697d33e41SMatthew G. Knepley   Level: intermediate
44797d33e41SMatthew G. Knepley 
44897d33e41SMatthew G. Knepley   Notes:
44920f4b53cSBarry Smith   If the number of levels is one then the multigrid uses the `-mg_levels` prefix
45020f4b53cSBarry Smith   for setting the level options rather than the `-mg_coarse` prefix.
45197d33e41SMatthew G. Knepley 
452d5a8f7e6SBarry Smith   You can free the information in comms after this routine is called.
453d5a8f7e6SBarry Smith 
454f1580f4eSBarry Smith   The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
455d5a8f7e6SBarry Smith   are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
456d5a8f7e6SBarry Smith   the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
457d5a8f7e6SBarry Smith   of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
458f1580f4eSBarry Smith   the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
459d5a8f7e6SBarry Smith   in the coarse grid solve.
460d5a8f7e6SBarry Smith 
461f1580f4eSBarry Smith   Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
462d5a8f7e6SBarry Smith   must take special care in providing the restriction and interpolation operation. We recommend
463d5a8f7e6SBarry Smith   providing these as two step operations; first perform a standard restriction or interpolation on
464d5a8f7e6SBarry Smith   the full number of ranks for that level and then use an MPI call to copy the resulting vector
46505552d4bSJunchao Zhang   array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
466d5a8f7e6SBarry Smith   cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
46720f4b53cSBarry Smith   receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries.
468d5a8f7e6SBarry Smith 
469feefa0e1SJacob Faibussowitsch   Fortran Notes:
47020f4b53cSBarry Smith   Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM`
471f1580f4eSBarry Smith   is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
472d5a8f7e6SBarry Smith 
473db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()`
47497d33e41SMatthew G. Knepley @*/
475d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms)
476d71ae5a4SJacob Faibussowitsch {
47797d33e41SMatthew G. Knepley   PetscFunctionBegin;
47897d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4794f572ea9SToby Isaac   if (comms) PetscAssertPointer(comms, 3);
480cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
4813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48297d33e41SMatthew G. Knepley }
48397d33e41SMatthew G. Knepley 
484d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc)
485d71ae5a4SJacob Faibussowitsch {
486a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
487a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
488a06653b4SBarry Smith   PetscInt       i, n;
489c07bf074SBarry Smith 
490c07bf074SBarry Smith   PetscFunctionBegin;
4919566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
492a06653b4SBarry Smith   if (mglevels) {
493a06653b4SBarry Smith     n = mglevels[0]->levels;
494a06653b4SBarry Smith     for (i = 0; i < n; i++) {
49548a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
4969566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
4979566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
4989566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
499a06653b4SBarry Smith     }
5009566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
501a06653b4SBarry Smith   }
5029566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5052b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
5062b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5072b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5082b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5092b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5102b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5112b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5122b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5132b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5142b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5152b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
517f3fbd535SBarry Smith }
518f3fbd535SBarry Smith 
519f3fbd535SBarry Smith /*
520f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
521f3fbd535SBarry Smith              or full cycle of multigrid.
522f3fbd535SBarry Smith 
523f3fbd535SBarry Smith   Note:
524f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
525f3fbd535SBarry Smith */
526d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
527d71ae5a4SJacob Faibussowitsch {
528f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
529f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
530391689abSStefano Zampini   PC             tpc;
531f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
53230b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
533f3fbd535SBarry Smith 
534f3fbd535SBarry Smith   PetscFunctionBegin;
53530b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5369566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
537e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
538298cc208SBarry Smith   for (i = 0; i < levels; i++) {
539e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5409566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5419566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
542e1d8e5deSBarry Smith     }
543e1d8e5deSBarry Smith   }
544e1d8e5deSBarry Smith 
5459566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5469566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5479566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5489566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
549391689abSStefano Zampini   if (!changeu && !changed) {
55030b0564aSStefano Zampini     if (matapp) {
5519566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
55230b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
55330b0564aSStefano Zampini     } else {
5549566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
555f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
55630b0564aSStefano Zampini     }
557391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
55830b0564aSStefano Zampini     if (matapp) {
55930b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
56030b0564aSStefano Zampini         PetscInt  N1, N2;
56130b0564aSStefano Zampini         PetscBool flg;
56230b0564aSStefano Zampini 
5639566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5649566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5659566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
56648a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
56730b0564aSStefano Zampini       }
56830b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5699566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
57030b0564aSStefano Zampini       } else {
5719566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
57230b0564aSStefano Zampini       }
57330b0564aSStefano Zampini     } else {
574391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
575391689abSStefano Zampini         Vec *vec;
576391689abSStefano Zampini 
5779566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
578391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5799566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
580391689abSStefano Zampini       }
5819566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
582391689abSStefano Zampini     }
58330b0564aSStefano Zampini   }
5849371c9d4SSatish Balay   if (matapp) {
5859371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
5869371c9d4SSatish Balay   } else {
5879371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
5889371c9d4SSatish Balay   }
58930b0564aSStefano Zampini 
59030b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
59130b0564aSStefano Zampini      Reset operators if sizes/type do no match */
59230b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
59330b0564aSStefano Zampini     PetscInt  Xc, Bc;
59430b0564aSStefano Zampini     PetscBool flg;
59530b0564aSStefano Zampini 
5969566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
5979566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
5989566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
59930b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6009566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
60130b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
6029566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6039566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6049566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
60530b0564aSStefano Zampini       }
60630b0564aSStefano Zampini     }
60730b0564aSStefano Zampini   }
608391689abSStefano Zampini 
60931567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6109566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6119566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
61248a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6132fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6149566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6152fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6169566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6172fa5cd67SKarl Rupp   } else {
6189566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
619f3fbd535SBarry Smith   }
6209566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
62130b0564aSStefano Zampini   if (!changeu && !changed) {
6229371c9d4SSatish Balay     if (matapp) {
6239371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6249371c9d4SSatish Balay     } else {
6259371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6269371c9d4SSatish Balay     }
62730b0564aSStefano Zampini   }
6283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
629f3fbd535SBarry Smith }
630f3fbd535SBarry Smith 
631d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
632d71ae5a4SJacob Faibussowitsch {
633fcb023d4SJed Brown   PetscFunctionBegin;
6349566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
636fcb023d4SJed Brown }
637fcb023d4SJed Brown 
638d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
639d71ae5a4SJacob Faibussowitsch {
640fcb023d4SJed Brown   PetscFunctionBegin;
6419566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64330b0564aSStefano Zampini }
64430b0564aSStefano Zampini 
645d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
646d71ae5a4SJacob Faibussowitsch {
64730b0564aSStefano Zampini   PetscFunctionBegin;
6489566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
650fcb023d4SJed Brown }
651f3fbd535SBarry Smith 
652d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject)
653d71ae5a4SJacob Faibussowitsch {
654710315b6SLawrence Mitchell   PetscInt            levels, cycles;
655f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
656f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6573d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
658f3fbd535SBarry Smith   PCMGType            mgtype;
659f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6602134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6612b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
662f3fbd535SBarry Smith 
663f3fbd535SBarry Smith   PetscFunctionBegin;
6641d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
665d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6669566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6671a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6689566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
669eb3f98d2SBarry Smith     levels++;
6703aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
671eb3f98d2SBarry Smith   }
6729566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6733aeaf226SBarry Smith   mglevels = mg->levels;
6743aeaf226SBarry Smith 
675f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
6769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
6771baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
6782134b1e4SBarry Smith   gtype = mg->galerkin;
6799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)gtype, (PetscEnum *)&gtype, &flg));
6801baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
6812b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6822b3cbbdaSStefano Zampini   PetscCall(PetscOptionsEnum("-pc_mg_adapt_interp_coarse_space", "Type of adaptive coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw", "PCMGSetAdaptCoarseSpaceType", PCMGCoarseSpaceTypes, (PetscEnum)coarseSpaceType, (PetscEnum *)&coarseSpaceType, &flg));
6832b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
6849566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
6859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
68641b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
6879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
6889566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
689f56b1265SBarry Smith   flg = PETSC_FALSE;
6909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
6911baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
69231567311SBarry Smith   mgtype = mg->am;
6939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
6941baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
69531567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6969566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
6971baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
698f3fbd535SBarry Smith   }
699f3fbd535SBarry Smith   flg = PETSC_FALSE;
7009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
701f3fbd535SBarry Smith   if (flg) {
702f3fbd535SBarry Smith     PetscInt i;
703f3fbd535SBarry Smith     char     eventname[128];
7041a97d7b6SStefano Zampini 
705f3fbd535SBarry Smith     levels = mglevels[0]->levels;
706f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
707a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %d", (int)i));
7089566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
709a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %d", (int)i));
7109566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
711f3fbd535SBarry Smith       if (i) {
712a364092eSJacob Faibussowitsch         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %d", (int)i));
7139566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
714a364092eSJacob Faibussowitsch         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %d", (int)i));
7159566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
716f3fbd535SBarry Smith       }
717f3fbd535SBarry Smith     }
718eec35531SMatthew G Knepley 
719*2611ad71SToby Isaac     if (PetscDefined(USE_LOG)) {
720*2611ad71SToby Isaac       const char sname[] = "MG Apply";
721eec35531SMatthew G Knepley 
722*2611ad71SToby Isaac       PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
723*2611ad71SToby Isaac       if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
724eec35531SMatthew G Knepley     }
725f3fbd535SBarry Smith   }
726d0609cedSBarry Smith   PetscOptionsHeadEnd();
727f3b08a26SMatthew G. Knepley   /* Check option consistency */
7289566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7299566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
73008401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
732f3fbd535SBarry Smith }
733f3fbd535SBarry Smith 
7340a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7350a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7360a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7372b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
738f3fbd535SBarry Smith 
7399804daf3SBarry Smith #include <petscdraw.h>
740d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
741d71ae5a4SJacob Faibussowitsch {
742f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
743f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
744e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
745219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
746f3fbd535SBarry Smith 
747f3fbd535SBarry Smith   PetscFunctionBegin;
7489566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7509566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
751f3fbd535SBarry Smith   if (iascii) {
752e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
75363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
75448a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7552134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7572134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7589566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7592134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7609566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7612134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7629566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7634f66f45eSBarry Smith     } else {
7649566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
765f3fbd535SBarry Smith     }
7661baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
767f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
76863a3b9bcSJacob Faibussowitsch       if (i) {
76963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
770f3fbd535SBarry Smith       } else {
77163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
772f3fbd535SBarry Smith       }
7739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7749566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
776f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
7779566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
778f3fbd535SBarry Smith       } else if (i) {
77963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
7809566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7819566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7829566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
783f3fbd535SBarry Smith       }
78441b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
78563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
7869566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7879566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
7889566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
78941b6fd38SMatthew G. Knepley       }
790f3fbd535SBarry Smith     }
7915b0b0462SBarry Smith   } else if (isbinary) {
7925b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
7939566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
79448a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7955b0b0462SBarry Smith     }
796219b1045SBarry Smith   } else if (isdraw) {
797219b1045SBarry Smith     PetscDraw draw;
798b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
7999566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8009566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8019566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
802219b1045SBarry Smith     bottom = y - th;
803219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
804b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8059566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8069566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8079566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
808b4375e8dSPeter Brune       } else {
809b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8109566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8119566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8129566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8139566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8149566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8159566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
816b4375e8dSPeter Brune       }
8179566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8181cd381d6SBarry Smith       bottom -= th;
819219b1045SBarry Smith     }
8205b0b0462SBarry Smith   }
8213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
822f3fbd535SBarry Smith }
823f3fbd535SBarry Smith 
824af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
825cab2e9ccSBarry Smith 
826f3fbd535SBarry Smith /*
827f3fbd535SBarry Smith     Calls setup for the KSP on each level
828f3fbd535SBarry Smith */
829d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
830d71ae5a4SJacob Faibussowitsch {
831f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
832f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8331a97d7b6SStefano Zampini   PetscInt       i, n;
83498e04984SBarry Smith   PC             cpc;
8353db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
836f3fbd535SBarry Smith   Mat            dA, dB;
837f3fbd535SBarry Smith   Vec            tvec;
838218a07d4SBarry Smith   DM            *dms;
8390a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
84041b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8412b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
842f3fbd535SBarry Smith 
843f3fbd535SBarry Smith   PetscFunctionBegin;
84428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8451a97d7b6SStefano Zampini   n = mglevels[0]->levels;
84601bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8473aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8483aeaf226SBarry Smith     PetscInt levels;
8499566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8503aeaf226SBarry Smith     levels++;
8513aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8529566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8533aeaf226SBarry Smith       n = levels;
8549566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8553aeaf226SBarry Smith       mglevels = mg->levels;
8563aeaf226SBarry Smith     }
8573aeaf226SBarry Smith   }
8589566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc));
8593aeaf226SBarry Smith 
860f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
861f3fbd535SBarry Smith   /* so use those from global PC */
862f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8639566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
86498e04984SBarry Smith   if (opsset) {
86598e04984SBarry Smith     Mat mmat;
8669566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
86798e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
86898e04984SBarry Smith   }
8694a5f07a5SMark F. Adams 
87041b6fd38SMatthew G. Knepley   /* Create CR solvers */
8719566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
87241b6fd38SMatthew G. Knepley   if (doCR) {
87341b6fd38SMatthew G. Knepley     const char *prefix;
87441b6fd38SMatthew G. Knepley 
8759566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
87641b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
87741b6fd38SMatthew G. Knepley       PC   ipc, cr;
87841b6fd38SMatthew G. Knepley       char crprefix[128];
87941b6fd38SMatthew G. Knepley 
8809566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
8813821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
8829566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
8839566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
8849566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
8859566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
8869566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
8879566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
8889566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
8899566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
89041b6fd38SMatthew G. Knepley 
8919566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
8929566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
8939566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
8949566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
8959566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
8969566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
89741b6fd38SMatthew G. Knepley 
8989566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
8999566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
9009566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int)i));
9019566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
90241b6fd38SMatthew G. Knepley     }
90341b6fd38SMatthew G. Knepley   }
90441b6fd38SMatthew G. Knepley 
9054a5f07a5SMark F. Adams   if (!opsset) {
9069566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9074a5f07a5SMark F. Adams     if (use_amat) {
9089566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "Using outer operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n"));
9099566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
91069858f1bSStefano Zampini     } else {
9119566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "Using matrix (pmat) operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n"));
9129566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9134a5f07a5SMark F. Adams     }
9144a5f07a5SMark F. Adams   }
915f3fbd535SBarry Smith 
9169c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9179c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9189c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9192b3cbbdaSStefano Zampini       break;
9209c7ffb39SBarry Smith     }
9219c7ffb39SBarry Smith   }
9222134b1e4SBarry Smith 
9239566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9242134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9252b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9262134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9272134b1e4SBarry Smith   }
9282134b1e4SBarry Smith 
9292b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9302b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9312b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9322b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9332b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9342b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9352b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9362b3cbbdaSStefano Zampini     }
9372b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9382b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9392b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9402b3cbbdaSStefano Zampini     }
9412b3cbbdaSStefano Zampini   }
9422b3cbbdaSStefano Zampini 
9439c7ffb39SBarry Smith   /*
9449c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9452b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9469c7ffb39SBarry Smith   */
94732fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
94832fe681dSStefano Zampini     /* first see if we can compute a coarse space */
94932fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
95032fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
95132fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
95232fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
95332fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
95432fe681dSStefano Zampini         }
95532fe681dSStefano Zampini       }
95632fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9572e499ae9SBarry Smith       Mat p;
95873250ac0SBarry Smith       Vec rscale;
9599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
960218a07d4SBarry Smith       dms[n - 1] = pc->dm;
961ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9629566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
963218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
964942e3340SBarry Smith         DMKSP     kdm;
965eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9669566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9679566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
968c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9699566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9709566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
971c27ee7a3SPatrick Farrell         }
97241b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9739566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
9749566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
97541b6fd38SMatthew G. Knepley         }
9769566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
977d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
978d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
9790298fd71SBarry Smith         kdm->ops->computerhs = NULL;
9800298fd71SBarry Smith         kdm->rhsctx          = NULL;
98124c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
9829566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
9839566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
9849566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
9859566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
9869566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
987218a07d4SBarry Smith         }
9889566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
9893ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
9909566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
9919566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
9929566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
9933ad4599aSBarry Smith         }
9949566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
995eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
9969566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
9979566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
9989566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
999eab52d2bSLawrence Mitchell         }
100024c3aa18SBarry Smith       }
10012d2b81a6SBarry Smith 
10029566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10039566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1004ce4cda84SJed Brown     }
100532fe681dSStefano Zampini   }
1006cab2e9ccSBarry Smith 
10072134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10082134b1e4SBarry Smith     Mat       A, B;
10092134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10102134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10112134b1e4SBarry Smith 
10122b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10132b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10142134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1015f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10167827d75bSBarry Smith       PetscCheck(mglevels[i + 1]->restrct || mglevels[i + 1]->interpolate, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must provide interpolation or restriction for each MG level except level 0");
101748a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
101848a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
101948a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
102048a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
102148a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10222134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10232134b1e4SBarry Smith       if (!doA && dAeqdB) {
10249566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10252134b1e4SBarry Smith         A = B;
10262134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10279566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10289566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1029b9367914SBarry Smith       }
10302134b1e4SBarry Smith       if (!doB && dAeqdB) {
10319566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10322134b1e4SBarry Smith         B = A;
10332134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10349566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10359566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10367d537d92SJed Brown       }
10372134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10389566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10399566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10409566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10412134b1e4SBarry Smith       }
10422134b1e4SBarry Smith       dA = A;
1043f3fbd535SBarry Smith       dB = B;
1044f3fbd535SBarry Smith     }
1045f3fbd535SBarry Smith   }
1046f3b08a26SMatthew G. Knepley 
1047f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10482b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1049f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
105048a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10512b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1052f3b08a26SMatthew G. Knepley     }
105348a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1054f3b08a26SMatthew G. Knepley   }
1055f3b08a26SMatthew G. Knepley 
10562134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1057caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1058ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1059caa4e7f2SJed Brown       Mat Restrict, Inject;
1060caa4e7f2SJed Brown       Vec rscale;
10619566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10629566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10639566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10649566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10659566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10669566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1067caa4e7f2SJed Brown     }
1068caa4e7f2SJed Brown   }
1069f3fbd535SBarry Smith 
1070f3fbd535SBarry Smith   if (!pc->setupcalled) {
107148a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1072f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
107348a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
107448a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1075f3fbd535SBarry Smith     }
10763ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
1077f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
10789566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
10799566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1080f3fbd535SBarry Smith     }
1081f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1082f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1083f3fbd535SBarry Smith         Vec *vec;
10849566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
10859566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
10869566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
10879566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1088f3fbd535SBarry Smith       }
1089f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
10909566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10919566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
10929566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1093f3fbd535SBarry Smith       }
1094f3fbd535SBarry Smith       if (!mglevels[i]->x) {
10959566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10969566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
10979566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1098f3fbd535SBarry Smith       }
109941b6fd38SMatthew G. Knepley       if (doCR) {
11009566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11019566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11029566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
110341b6fd38SMatthew G. Knepley       }
1104f3fbd535SBarry Smith     }
1105f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1106f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1107f3fbd535SBarry Smith       Vec *vec;
11089566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11099566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11109566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11119566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1112f3fbd535SBarry Smith     }
111341b6fd38SMatthew G. Knepley     if (doCR) {
11149566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11159566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11169566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
111741b6fd38SMatthew G. Knepley     }
1118f3fbd535SBarry Smith   }
1119f3fbd535SBarry Smith 
112098e04984SBarry Smith   if (pc->dm) {
112198e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
112298e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
112398e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
112498e04984SBarry Smith     }
112598e04984SBarry Smith   }
112608549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
112708549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
112808549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1129f3fbd535SBarry Smith 
1130f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11312a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1132f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11339566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1134f3fbd535SBarry Smith     }
11359566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11369566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11379566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1138d4645a75SStefano Zampini     if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11399566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1140d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1141d42688cbSBarry Smith       Mat mat;
11429566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11439566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1144d42688cbSBarry Smith     }
1145fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1146fcb023d4SJed Brown       Mat mat;
11479566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11489566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1149fcb023d4SJed Brown     }
1150f3fbd535SBarry Smith   }
1151f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1152f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1153f3fbd535SBarry Smith       Mat downmat, downpmat;
1154f3fbd535SBarry Smith 
1155f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11569566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1157f3fbd535SBarry Smith       if (!opsset) {
11589566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11599566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1160f3fbd535SBarry Smith       }
1161f3fbd535SBarry Smith 
11629566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11639566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11649566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1165d4645a75SStefano Zampini       if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
11669566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1167f3fbd535SBarry Smith     }
116841b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
116941b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
117041b6fd38SMatthew G. Knepley 
117141b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
11729566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
117341b6fd38SMatthew G. Knepley       if (!opsset) {
11749566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11759566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
117641b6fd38SMatthew G. Knepley       }
117741b6fd38SMatthew G. Knepley 
11789566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11799566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11809566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1181d4645a75SStefano Zampini       if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
11829566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
118341b6fd38SMatthew G. Knepley     }
1184f3fbd535SBarry Smith   }
1185f3fbd535SBarry Smith 
11869566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
11879566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1188d4645a75SStefano Zampini   if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11899566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1190f3fbd535SBarry Smith 
1191f3fbd535SBarry Smith     /*
1192f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1193e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1194f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1195f3fbd535SBarry Smith 
1196f3fbd535SBarry Smith    Only support one or the other at the same time.
1197f3fbd535SBarry Smith   */
1198f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
11999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1200ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1201f3fbd535SBarry Smith   dump = PETSC_FALSE;
1202f3fbd535SBarry Smith #endif
12039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1204ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1205f3fbd535SBarry Smith 
1206f3fbd535SBarry Smith   if (viewer) {
120748a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1208f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12099566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12109566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1211f3fbd535SBarry Smith     }
1212f3fbd535SBarry Smith   }
12133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1214f3fbd535SBarry Smith }
1215f3fbd535SBarry Smith 
1216f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
1217f3fbd535SBarry Smith 
1218d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1219d71ae5a4SJacob Faibussowitsch {
122097d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
122197d33e41SMatthew G. Knepley 
122297d33e41SMatthew G. Knepley   PetscFunctionBegin;
122397d33e41SMatthew G. Knepley   *levels = mg->nlevels;
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122597d33e41SMatthew G. Knepley }
122697d33e41SMatthew G. Knepley 
12274b9ad928SBarry Smith /*@
1228f1580f4eSBarry Smith   PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12294b9ad928SBarry Smith 
12304b9ad928SBarry Smith   Not Collective
12314b9ad928SBarry Smith 
12324b9ad928SBarry Smith   Input Parameter:
12334b9ad928SBarry Smith . pc - the preconditioner context
12344b9ad928SBarry Smith 
1235feefa0e1SJacob Faibussowitsch   Output Parameter:
12364b9ad928SBarry Smith . levels - the number of levels
12374b9ad928SBarry Smith 
12384b9ad928SBarry Smith   Level: advanced
12394b9ad928SBarry Smith 
1240f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetLevels()`
12414b9ad928SBarry Smith @*/
1242d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1243d71ae5a4SJacob Faibussowitsch {
12444b9ad928SBarry Smith   PetscFunctionBegin;
12450700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12464f572ea9SToby Isaac   PetscAssertPointer(levels, 2);
124797d33e41SMatthew G. Knepley   *levels = 0;
1248cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12504b9ad928SBarry Smith }
12514b9ad928SBarry Smith 
12524b9ad928SBarry Smith /*@
1253f1580f4eSBarry Smith   PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1254e7d4b4cbSMark Adams 
1255e7d4b4cbSMark Adams   Input Parameter:
1256e7d4b4cbSMark Adams . pc - the preconditioner context
1257e7d4b4cbSMark Adams 
125890db8557SMark Adams   Output Parameters:
125990db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
126090db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1261e7d4b4cbSMark Adams 
1262e7d4b4cbSMark Adams   Level: advanced
1263e7d4b4cbSMark Adams 
1264f1580f4eSBarry Smith   Note:
1265f1580f4eSBarry Smith   This is often call the operator complexity in multigrid literature
1266f1580f4eSBarry Smith 
1267f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1268e7d4b4cbSMark Adams @*/
1269d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1270d71ae5a4SJacob Faibussowitsch {
1271e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1272e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1273e7d4b4cbSMark Adams   PetscInt       lev, N;
1274e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1275e7d4b4cbSMark Adams   MatInfo        info;
1276e7d4b4cbSMark Adams 
1277e7d4b4cbSMark Adams   PetscFunctionBegin;
127890db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12794f572ea9SToby Isaac   if (gc) PetscAssertPointer(gc, 2);
12804f572ea9SToby Isaac   if (oc) PetscAssertPointer(oc, 3);
1281e7d4b4cbSMark Adams   if (!pc->setupcalled) {
128290db8557SMark Adams     if (gc) *gc = 0;
128390db8557SMark Adams     if (oc) *oc = 0;
12843ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1285e7d4b4cbSMark Adams   }
1286e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1287e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1288e7d4b4cbSMark Adams     Mat dB;
12899566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
12909566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
12919566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1292e7d4b4cbSMark Adams     sgc += N;
1293e7d4b4cbSMark Adams     soc += info.nz_used;
12949371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
12959371c9d4SSatish Balay       nnz0 = info.nz_used;
12969371c9d4SSatish Balay       n0   = N;
12979371c9d4SSatish Balay     }
1298e7d4b4cbSMark Adams   }
12990fdf79fbSJacob Faibussowitsch   PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13000fdf79fbSJacob Faibussowitsch   *gc = (PetscReal)(sgc / n0);
130190db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1303e7d4b4cbSMark Adams }
1304e7d4b4cbSMark Adams 
1305e7d4b4cbSMark Adams /*@
130697177400SBarry Smith   PCMGSetType - Determines the form of multigrid to use:
13074b9ad928SBarry Smith   multiplicative, additive, full, or the Kaskade algorithm.
13084b9ad928SBarry Smith 
1309c3339decSBarry Smith   Logically Collective
13104b9ad928SBarry Smith 
13114b9ad928SBarry Smith   Input Parameters:
13124b9ad928SBarry Smith + pc   - the preconditioner context
1313f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13144b9ad928SBarry Smith 
13154b9ad928SBarry Smith   Options Database Key:
131620f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13174b9ad928SBarry Smith 
13184b9ad928SBarry Smith   Level: advanced
13194b9ad928SBarry Smith 
1320f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13214b9ad928SBarry Smith @*/
1322d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1323d71ae5a4SJacob Faibussowitsch {
1324f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13254b9ad928SBarry Smith 
13264b9ad928SBarry Smith   PetscFunctionBegin;
13270700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1328c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
132931567311SBarry Smith   mg->am = form;
13309dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1331c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
13323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1333c60c7ad4SBarry Smith }
1334c60c7ad4SBarry Smith 
1335c60c7ad4SBarry Smith /*@
1336f1580f4eSBarry Smith   PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1337c60c7ad4SBarry Smith 
1338c3339decSBarry Smith   Logically Collective
1339c60c7ad4SBarry Smith 
1340c60c7ad4SBarry Smith   Input Parameter:
1341c60c7ad4SBarry Smith . pc - the preconditioner context
1342c60c7ad4SBarry Smith 
1343c60c7ad4SBarry Smith   Output Parameter:
1344f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1345c60c7ad4SBarry Smith 
1346c60c7ad4SBarry Smith   Level: advanced
1347c60c7ad4SBarry Smith 
1348f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1349c60c7ad4SBarry Smith @*/
1350d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1351d71ae5a4SJacob Faibussowitsch {
1352c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1353c60c7ad4SBarry Smith 
1354c60c7ad4SBarry Smith   PetscFunctionBegin;
1355c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1356c60c7ad4SBarry Smith   *type = mg->am;
13573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13584b9ad928SBarry Smith }
13594b9ad928SBarry Smith 
13604b9ad928SBarry Smith /*@
1361f1580f4eSBarry Smith   PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
13624b9ad928SBarry Smith   complicated cycling.
13634b9ad928SBarry Smith 
1364c3339decSBarry Smith   Logically Collective
13654b9ad928SBarry Smith 
13664b9ad928SBarry Smith   Input Parameters:
1367c2be2410SBarry Smith + pc - the multigrid context
1368f1580f4eSBarry Smith - n  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
13694b9ad928SBarry Smith 
13704b9ad928SBarry Smith   Options Database Key:
1371c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
13724b9ad928SBarry Smith 
13734b9ad928SBarry Smith   Level: advanced
13744b9ad928SBarry Smith 
1375f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
13764b9ad928SBarry Smith @*/
1377d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1378d71ae5a4SJacob Faibussowitsch {
1379f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1380f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
138179416396SBarry Smith   PetscInt       i, levels;
13824b9ad928SBarry Smith 
13834b9ad928SBarry Smith   PetscFunctionBegin;
13840700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
138569fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
138628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1387f3fbd535SBarry Smith   levels = mglevels[0]->levels;
13882fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
13893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13904b9ad928SBarry Smith }
13914b9ad928SBarry Smith 
13928cc2d5dfSBarry Smith /*@
13938cc2d5dfSBarry Smith   PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1394f1580f4eSBarry Smith   of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
13958cc2d5dfSBarry Smith 
1396c3339decSBarry Smith   Logically Collective
13978cc2d5dfSBarry Smith 
13988cc2d5dfSBarry Smith   Input Parameters:
13998cc2d5dfSBarry Smith + pc - the multigrid context
14008cc2d5dfSBarry Smith - n  - number of cycles (default is 1)
14018cc2d5dfSBarry Smith 
14028cc2d5dfSBarry Smith   Options Database Key:
1403147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14048cc2d5dfSBarry Smith 
14058cc2d5dfSBarry Smith   Level: advanced
14068cc2d5dfSBarry Smith 
1407f1580f4eSBarry Smith   Note:
1408f1580f4eSBarry Smith   This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14098cc2d5dfSBarry Smith 
1410f1580f4eSBarry Smith .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14118cc2d5dfSBarry Smith @*/
1412d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1413d71ae5a4SJacob Faibussowitsch {
1414f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14158cc2d5dfSBarry Smith 
14168cc2d5dfSBarry Smith   PetscFunctionBegin;
14170700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1418c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14192a21e185SBarry Smith   mg->cyclesperpcapply = n;
14203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14218cc2d5dfSBarry Smith }
14228cc2d5dfSBarry Smith 
1423d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1424d71ae5a4SJacob Faibussowitsch {
1425fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1426fb15c04eSBarry Smith 
1427fb15c04eSBarry Smith   PetscFunctionBegin;
14282134b1e4SBarry Smith   mg->galerkin = use;
14293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1430fb15c04eSBarry Smith }
1431fb15c04eSBarry Smith 
1432c2be2410SBarry Smith /*@
143397177400SBarry Smith   PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
143482b87d87SMatthew G. Knepley   finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1435c2be2410SBarry Smith 
1436c3339decSBarry Smith   Logically Collective
1437c2be2410SBarry Smith 
1438c2be2410SBarry Smith   Input Parameters:
1439c91913d3SJed Brown + pc  - the multigrid context
1440f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1441c2be2410SBarry Smith 
1442c2be2410SBarry Smith   Options Database Key:
1443147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1444c2be2410SBarry Smith 
1445c2be2410SBarry Smith   Level: intermediate
1446c2be2410SBarry Smith 
1447f1580f4eSBarry Smith   Note:
1448f1580f4eSBarry Smith   Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1449f1580f4eSBarry Smith   use the `PCMG` construction of the coarser grids.
14501c1aac46SBarry Smith 
1451f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1452c2be2410SBarry Smith @*/
1453d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1454d71ae5a4SJacob Faibussowitsch {
1455c2be2410SBarry Smith   PetscFunctionBegin;
14560700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1457cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
14583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1459c2be2410SBarry Smith }
1460c2be2410SBarry Smith 
14613fc8bf9cSBarry Smith /*@
1462f1580f4eSBarry Smith   PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
14633fc8bf9cSBarry Smith 
14643fc8bf9cSBarry Smith   Not Collective
14653fc8bf9cSBarry Smith 
14663fc8bf9cSBarry Smith   Input Parameter:
14673fc8bf9cSBarry Smith . pc - the multigrid context
14683fc8bf9cSBarry Smith 
14693fc8bf9cSBarry Smith   Output Parameter:
1470f1580f4eSBarry Smith . galerkin - one of `PC_MG_GALERKIN_BOTH`,`PC_MG_GALERKIN_PMAT`,`PC_MG_GALERKIN_MAT`, `PC_MG_GALERKIN_NONE`, or `PC_MG_GALERKIN_EXTERNAL`
14713fc8bf9cSBarry Smith 
14723fc8bf9cSBarry Smith   Level: intermediate
14733fc8bf9cSBarry Smith 
1474f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
14753fc8bf9cSBarry Smith @*/
1476d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1477d71ae5a4SJacob Faibussowitsch {
1478f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14793fc8bf9cSBarry Smith 
14803fc8bf9cSBarry Smith   PetscFunctionBegin;
14810700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14822134b1e4SBarry Smith   *galerkin = mg->galerkin;
14833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14843fc8bf9cSBarry Smith }
14853fc8bf9cSBarry Smith 
1486d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1487d71ae5a4SJacob Faibussowitsch {
1488f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1489f3b08a26SMatthew G. Knepley 
1490f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1491f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
14923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1493f3b08a26SMatthew G. Knepley }
1494f3b08a26SMatthew G. Knepley 
1495d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1496d71ae5a4SJacob Faibussowitsch {
1497f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1498f3b08a26SMatthew G. Knepley 
1499f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1500f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
15013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1502f3b08a26SMatthew G. Knepley }
1503f3b08a26SMatthew G. Knepley 
1504d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1505d71ae5a4SJacob Faibussowitsch {
15062b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15072b3cbbdaSStefano Zampini 
15082b3cbbdaSStefano Zampini   PetscFunctionBegin;
15092b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15102b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
15113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15122b3cbbdaSStefano Zampini }
15132b3cbbdaSStefano Zampini 
1514d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1515d71ae5a4SJacob Faibussowitsch {
15162b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15172b3cbbdaSStefano Zampini 
15182b3cbbdaSStefano Zampini   PetscFunctionBegin;
15192b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15212b3cbbdaSStefano Zampini }
15222b3cbbdaSStefano Zampini 
1523d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1524d71ae5a4SJacob Faibussowitsch {
152541b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
152641b6fd38SMatthew G. Knepley 
152741b6fd38SMatthew G. Knepley   PetscFunctionBegin;
152841b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
15293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153041b6fd38SMatthew G. Knepley }
153141b6fd38SMatthew G. Knepley 
1532d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1533d71ae5a4SJacob Faibussowitsch {
153441b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
153541b6fd38SMatthew G. Knepley 
153641b6fd38SMatthew G. Knepley   PetscFunctionBegin;
153741b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
15383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153941b6fd38SMatthew G. Knepley }
154041b6fd38SMatthew G. Knepley 
15412b3cbbdaSStefano Zampini /*@C
15422b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15432b3cbbdaSStefano Zampini 
15442b3cbbdaSStefano Zampini   Adapts or creates the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated.
15452b3cbbdaSStefano Zampini 
1546c3339decSBarry Smith   Logically Collective
15472b3cbbdaSStefano Zampini 
15482b3cbbdaSStefano Zampini   Input Parameters:
15492b3cbbdaSStefano Zampini + pc    - the multigrid context
15502b3cbbdaSStefano Zampini - ctype - the type of coarse space
15512b3cbbdaSStefano Zampini 
15522b3cbbdaSStefano Zampini   Options Database Keys:
15532b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
15542b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw
15552b3cbbdaSStefano Zampini 
15562b3cbbdaSStefano Zampini   Level: intermediate
15572b3cbbdaSStefano Zampini 
1558f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
15592b3cbbdaSStefano Zampini @*/
1560d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1561d71ae5a4SJacob Faibussowitsch {
15622b3cbbdaSStefano Zampini   PetscFunctionBegin;
15632b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15642b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
15652b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
15663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15672b3cbbdaSStefano Zampini }
15682b3cbbdaSStefano Zampini 
15692b3cbbdaSStefano Zampini /*@C
15702b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
15712b3cbbdaSStefano Zampini 
15722b3cbbdaSStefano Zampini   Not Collective
15732b3cbbdaSStefano Zampini 
15742b3cbbdaSStefano Zampini   Input Parameter:
15752b3cbbdaSStefano Zampini . pc - the multigrid context
15762b3cbbdaSStefano Zampini 
15772b3cbbdaSStefano Zampini   Output Parameter:
15782b3cbbdaSStefano Zampini . ctype - the type of coarse space
15792b3cbbdaSStefano Zampini 
15802b3cbbdaSStefano Zampini   Level: intermediate
15812b3cbbdaSStefano Zampini 
1582f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
15832b3cbbdaSStefano Zampini @*/
1584d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1585d71ae5a4SJacob Faibussowitsch {
15862b3cbbdaSStefano Zampini   PetscFunctionBegin;
15872b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15884f572ea9SToby Isaac   PetscAssertPointer(ctype, 2);
15892b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
15903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15912b3cbbdaSStefano Zampini }
15922b3cbbdaSStefano Zampini 
15932b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1594f3b08a26SMatthew G. Knepley /*@
1595f3b08a26SMatthew G. Knepley   PCMGSetAdaptInterpolation - Adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated.
1596f3b08a26SMatthew G. Knepley 
1597c3339decSBarry Smith   Logically Collective
1598f3b08a26SMatthew G. Knepley 
1599f3b08a26SMatthew G. Knepley   Input Parameters:
1600f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1601f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1602f3b08a26SMatthew G. Knepley 
1603f3b08a26SMatthew G. Knepley   Options Database Keys:
1604f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1605f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1606f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1607f3b08a26SMatthew G. Knepley 
1608f3b08a26SMatthew G. Knepley   Level: intermediate
1609f3b08a26SMatthew G. Knepley 
1610f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1611f3b08a26SMatthew G. Knepley @*/
1612d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1613d71ae5a4SJacob Faibussowitsch {
1614f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1615f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1616cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1618f3b08a26SMatthew G. Knepley }
1619f3b08a26SMatthew G. Knepley 
1620f3b08a26SMatthew G. Knepley /*@
1621f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1622f1580f4eSBarry Smith   and thus accurately interpolated.
1623f3b08a26SMatthew G. Knepley 
162420f4b53cSBarry Smith   Not Collective
1625f3b08a26SMatthew G. Knepley 
1626f3b08a26SMatthew G. Knepley   Input Parameter:
1627f3b08a26SMatthew G. Knepley . pc - the multigrid context
1628f3b08a26SMatthew G. Knepley 
1629f3b08a26SMatthew G. Knepley   Output Parameter:
1630f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1631f3b08a26SMatthew G. Knepley 
1632f3b08a26SMatthew G. Knepley   Level: intermediate
1633f3b08a26SMatthew G. Knepley 
1634f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1635f3b08a26SMatthew G. Knepley @*/
1636d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1637d71ae5a4SJacob Faibussowitsch {
1638f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1639f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16404f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
1641cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
16423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1643f3b08a26SMatthew G. Knepley }
1644f3b08a26SMatthew G. Knepley 
16454b9ad928SBarry Smith /*@
164641b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
164741b6fd38SMatthew G. Knepley 
1648c3339decSBarry Smith   Logically Collective
164941b6fd38SMatthew G. Knepley 
165041b6fd38SMatthew G. Knepley   Input Parameters:
165141b6fd38SMatthew G. Knepley + pc - the multigrid context
165241b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
165341b6fd38SMatthew G. Knepley 
1654f1580f4eSBarry Smith   Options Database Key:
165541b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
165641b6fd38SMatthew G. Knepley 
165741b6fd38SMatthew G. Knepley   Level: intermediate
165841b6fd38SMatthew G. Knepley 
1659f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
166041b6fd38SMatthew G. Knepley @*/
1661d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1662d71ae5a4SJacob Faibussowitsch {
166341b6fd38SMatthew G. Knepley   PetscFunctionBegin;
166441b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1665cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
16663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166741b6fd38SMatthew G. Knepley }
166841b6fd38SMatthew G. Knepley 
166941b6fd38SMatthew G. Knepley /*@
167041b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
167141b6fd38SMatthew G. Knepley 
167220f4b53cSBarry Smith   Not Collective
167341b6fd38SMatthew G. Knepley 
167441b6fd38SMatthew G. Knepley   Input Parameter:
167541b6fd38SMatthew G. Knepley . pc - the multigrid context
167641b6fd38SMatthew G. Knepley 
167741b6fd38SMatthew G. Knepley   Output Parameter:
167841b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
167941b6fd38SMatthew G. Knepley 
168041b6fd38SMatthew G. Knepley   Level: intermediate
168141b6fd38SMatthew G. Knepley 
1682f1580f4eSBarry Smith .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
168341b6fd38SMatthew G. Knepley @*/
1684d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1685d71ae5a4SJacob Faibussowitsch {
168641b6fd38SMatthew G. Knepley   PetscFunctionBegin;
168741b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16884f572ea9SToby Isaac   PetscAssertPointer(cr, 2);
1689cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
16903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
169141b6fd38SMatthew G. Knepley }
169241b6fd38SMatthew G. Knepley 
169341b6fd38SMatthew G. Knepley /*@
169406792cafSBarry Smith   PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1695f1580f4eSBarry Smith   on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1696710315b6SLawrence Mitchell   pre- and post-smoothing steps.
169706792cafSBarry Smith 
1698c3339decSBarry Smith   Logically Collective
169906792cafSBarry Smith 
170006792cafSBarry Smith   Input Parameters:
1701feefa0e1SJacob Faibussowitsch + pc - the multigrid context
170206792cafSBarry Smith - n  - the number of smoothing steps
170306792cafSBarry Smith 
170406792cafSBarry Smith   Options Database Key:
1705a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
170606792cafSBarry Smith 
170706792cafSBarry Smith   Level: advanced
170806792cafSBarry Smith 
1709f1580f4eSBarry Smith   Note:
1710f1580f4eSBarry Smith   This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid.
171106792cafSBarry Smith 
1712f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetDistinctSmoothUp()`
171306792cafSBarry Smith @*/
1714d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1715d71ae5a4SJacob Faibussowitsch {
171606792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
171706792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
171806792cafSBarry Smith   PetscInt       i, levels;
171906792cafSBarry Smith 
172006792cafSBarry Smith   PetscFunctionBegin;
172106792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
172206792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
172328b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
172406792cafSBarry Smith   levels = mglevels[0]->levels;
172506792cafSBarry Smith 
172606792cafSBarry Smith   for (i = 1; i < levels; i++) {
17279566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
17289566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
172906792cafSBarry Smith     mg->default_smoothu = n;
173006792cafSBarry Smith     mg->default_smoothd = n;
173106792cafSBarry Smith   }
17323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
173306792cafSBarry Smith }
173406792cafSBarry Smith 
1735f442ab6aSBarry Smith /*@
1736f1580f4eSBarry Smith   PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1737710315b6SLawrence Mitchell   and adds the suffix _up to the options name
1738f442ab6aSBarry Smith 
1739c3339decSBarry Smith   Logically Collective
1740f442ab6aSBarry Smith 
1741f1580f4eSBarry Smith   Input Parameter:
1742f442ab6aSBarry Smith . pc - the preconditioner context
1743f442ab6aSBarry Smith 
1744f442ab6aSBarry Smith   Options Database Key:
1745147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1746f442ab6aSBarry Smith 
1747f442ab6aSBarry Smith   Level: advanced
1748f442ab6aSBarry Smith 
1749f1580f4eSBarry Smith   Note:
1750f1580f4eSBarry Smith   This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid.
1751f442ab6aSBarry Smith 
1752f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetNumberSmooth()`
1753f442ab6aSBarry Smith @*/
1754d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1755d71ae5a4SJacob Faibussowitsch {
1756f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1757f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1758f442ab6aSBarry Smith   PetscInt       i, levels;
1759f442ab6aSBarry Smith   KSP            subksp;
1760f442ab6aSBarry Smith 
1761f442ab6aSBarry Smith   PetscFunctionBegin;
1762f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
176328b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1764f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1765f442ab6aSBarry Smith 
1766f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1767710315b6SLawrence Mitchell     const char *prefix = NULL;
1768f442ab6aSBarry Smith     /* make sure smoother up and down are different */
17699566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
17709566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
17719566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
17729566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1773f442ab6aSBarry Smith   }
17743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1775f442ab6aSBarry Smith }
1776f442ab6aSBarry Smith 
177707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
1778d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1779d71ae5a4SJacob Faibussowitsch {
178007a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
178107a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
178207a4832bSFande Kong   Mat           *mat;
178307a4832bSFande Kong   PetscInt       l;
178407a4832bSFande Kong 
178507a4832bSFande Kong   PetscFunctionBegin;
178628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
17879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
178807a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
178907a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
17909566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
179107a4832bSFande Kong   }
179207a4832bSFande Kong   *num_levels     = mg->nlevels;
179307a4832bSFande Kong   *interpolations = mat;
17943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
179507a4832bSFande Kong }
179607a4832bSFande Kong 
179707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
1798d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1799d71ae5a4SJacob Faibussowitsch {
180007a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
180107a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
180207a4832bSFande Kong   PetscInt       l;
180307a4832bSFande Kong   Mat           *mat;
180407a4832bSFande Kong 
180507a4832bSFande Kong   PetscFunctionBegin;
180628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
180807a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
18099566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &(mat[l])));
18109566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
181107a4832bSFande Kong   }
181207a4832bSFande Kong   *num_levels      = mg->nlevels;
181307a4832bSFande Kong   *coarseOperators = mat;
18143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
181507a4832bSFande Kong }
181607a4832bSFande Kong 
1817f3b08a26SMatthew G. Knepley /*@C
1818f1580f4eSBarry Smith   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1819f3b08a26SMatthew G. Knepley 
182020f4b53cSBarry Smith   Not Collective
1821f3b08a26SMatthew G. Knepley 
1822f3b08a26SMatthew G. Knepley   Input Parameters:
1823f3b08a26SMatthew G. Knepley + name     - name of the constructor
1824f3b08a26SMatthew G. Knepley - function - constructor routine
1825f3b08a26SMatthew G. Knepley 
182620f4b53cSBarry Smith   Calling sequence of `function`:
182720f4b53cSBarry Smith $  PetscErrorCode my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
182820f4b53cSBarry Smith +  pc        - The `PC` object
1829f1580f4eSBarry Smith .  l         - The multigrid level, 0 is the coarse level
183020f4b53cSBarry Smith .  dm        - The `DM` for this level
1831f1580f4eSBarry Smith .  smooth    - The level smoother
1832f1580f4eSBarry Smith .  Nc        - The size of the coarse space
1833f1580f4eSBarry Smith .  initGuess - Basis for an initial guess for the space
1834f1580f4eSBarry Smith -  coarseSp  - A basis for the computed coarse space
1835f3b08a26SMatthew G. Knepley 
1836f3b08a26SMatthew G. Knepley   Level: advanced
1837f3b08a26SMatthew G. Knepley 
1838feefa0e1SJacob Faibussowitsch   Developer Notes:
1839f1580f4eSBarry Smith   How come this is not used by `PCGAMG`?
1840f1580f4eSBarry Smith 
1841f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1842f3b08a26SMatthew G. Knepley @*/
1843d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *))
1844d71ae5a4SJacob Faibussowitsch {
1845f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18469566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18479566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
18483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1849f3b08a26SMatthew G. Knepley }
1850f3b08a26SMatthew G. Knepley 
1851f3b08a26SMatthew G. Knepley /*@C
1852f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1853f3b08a26SMatthew G. Knepley 
185420f4b53cSBarry Smith   Not Collective
1855f3b08a26SMatthew G. Knepley 
1856f3b08a26SMatthew G. Knepley   Input Parameter:
1857f3b08a26SMatthew G. Knepley . name - name of the constructor
1858f3b08a26SMatthew G. Knepley 
1859f3b08a26SMatthew G. Knepley   Output Parameter:
1860f3b08a26SMatthew G. Knepley . function - constructor routine
1861f3b08a26SMatthew G. Knepley 
1862f3b08a26SMatthew G. Knepley   Level: advanced
1863f3b08a26SMatthew G. Knepley 
1864f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1865f3b08a26SMatthew G. Knepley @*/
1866d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *))
1867d71ae5a4SJacob Faibussowitsch {
1868f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18699566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
18703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1871f3b08a26SMatthew G. Knepley }
1872f3b08a26SMatthew G. Knepley 
18733b09bd56SBarry Smith /*MC
1874ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
18753b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
18763b09bd56SBarry Smith 
18773b09bd56SBarry Smith    Options Database Keys:
18783b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
1879391689abSStefano Zampini .  -pc_mg_cycle_type <v,w> - provide the cycle desired
18808c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
18813b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
1882710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
18832134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
18848cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
18858cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1886e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
18878cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
18888cf6037eSBarry Smith                         to the binary output file called binaryoutput
18893b09bd56SBarry Smith 
189020f4b53cSBarry Smith    Level: intermediate
189120f4b53cSBarry Smith 
189295452b02SPatrick Sanan    Notes:
1893f1580f4eSBarry Smith     If one uses a Krylov method such `KSPGMRES` or `KSPCG` as the smoother then one must use `KSPFGMRES`, `KSPGCR`, or `KSPRICHARDSON` as the outer Krylov method
18943b09bd56SBarry Smith 
18958cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
18968cf6037eSBarry Smith 
1897f1580f4eSBarry Smith        When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
189823067569SBarry Smith        is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
189923067569SBarry Smith        (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
190023067569SBarry Smith        residual is computed at the end of each cycle.
190123067569SBarry Smith 
1902db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1903db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1904db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1905db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1906f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1907f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19083b09bd56SBarry Smith M*/
19093b09bd56SBarry Smith 
1910d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1911d71ae5a4SJacob Faibussowitsch {
1912f3fbd535SBarry Smith   PC_MG *mg;
1913f3fbd535SBarry Smith 
19144b9ad928SBarry Smith   PetscFunctionBegin;
19154dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
19163ec1f749SStefano Zampini   pc->data               = mg;
1917f3fbd535SBarry Smith   mg->nlevels            = -1;
191810eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19192134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1920f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1921f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1922f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1923f3fbd535SBarry Smith 
192437a44384SMark Adams   pc->useAmat = PETSC_TRUE;
192537a44384SMark Adams 
19264b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1927fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
192830b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
19294b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1930a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
19314b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
19324b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
19334b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1934fb15c04eSBarry Smith 
19359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
19369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
19379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
19452b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
19462b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
19473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19484b9ad928SBarry Smith }
1949