xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
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 
159371c9d4SSatish Balay PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason) {
1631567311SBarry Smith   PC_MG        *mg = (PC_MG *)pc->data;
1731567311SBarry Smith   PC_MG_Levels *mgc, *mglevels = *mglevelsin;
1831567311SBarry Smith   PetscInt      cycles = (mglevels->level == 1) ? 1 : (PetscInt)mglevels->cycles;
194b9ad928SBarry Smith 
204b9ad928SBarry Smith   PetscFunctionBegin;
219566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
22fcb023d4SJed Brown   if (!transpose) {
2330b0564aSStefano Zampini     if (matapp) {
249566063dSJacob Faibussowitsch       PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */
259566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL));
2630b0564aSStefano Zampini     } else {
279566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */
289566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
2930b0564aSStefano Zampini     }
30fcb023d4SJed Brown   } else {
3128b400f6SJacob Faibussowitsch     PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
329566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */
339566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
34fcb023d4SJed Brown   }
359566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
3631567311SBarry Smith   if (mglevels->level) { /* not the coarsest grid */
379566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0));
3848a46eb9SPierre Jolivet     if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R));
39fcb023d4SJed Brown     if (!transpose) {
409566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
419566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
42fcb023d4SJed Brown     } else {
439566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
449566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
45fcb023d4SJed Brown     }
469566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0));
474b9ad928SBarry Smith 
484b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
4931567311SBarry Smith     if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) {
504b9ad928SBarry Smith       PetscReal rnorm;
519566063dSJacob Faibussowitsch       PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm));
524b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
5370441072SBarry Smith         if (rnorm < mg->abstol) {
544d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
559566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol));
564b9ad928SBarry Smith         } else {
574d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
589566063dSJacob 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));
594b9ad928SBarry Smith         }
604b9ad928SBarry Smith         PetscFunctionReturn(0);
614b9ad928SBarry Smith       }
624b9ad928SBarry Smith     }
634b9ad928SBarry Smith 
6431567311SBarry Smith     mgc = *(mglevelsin - 1);
659566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
66fcb023d4SJed Brown     if (!transpose) {
679566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B));
689566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b));
69fcb023d4SJed Brown     } else {
709566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B));
719566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b));
72fcb023d4SJed Brown     }
739566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
7430b0564aSStefano Zampini     if (matapp) {
7530b0564aSStefano Zampini       if (!mgc->X) {
769566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X));
7730b0564aSStefano Zampini       } else {
789566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(mgc->X));
7930b0564aSStefano Zampini       }
8030b0564aSStefano Zampini     } else {
819566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mgc->x));
8230b0564aSStefano Zampini     }
8348a46eb9SPierre Jolivet     while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason));
849566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
85fcb023d4SJed Brown     if (!transpose) {
869566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X));
879566063dSJacob Faibussowitsch       else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x));
88fcb023d4SJed Brown     } else {
899566063dSJacob Faibussowitsch       PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x));
90fcb023d4SJed Brown     }
919566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
929566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
93fcb023d4SJed Brown     if (!transpose) {
9430b0564aSStefano Zampini       if (matapp) {
959566063dSJacob Faibussowitsch         PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */
969566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL));
9730b0564aSStefano Zampini       } else {
989566063dSJacob Faibussowitsch         PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */
999566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
10030b0564aSStefano Zampini       }
101fcb023d4SJed Brown     } else {
10228b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
1039566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */
1049566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
105fcb023d4SJed Brown     }
10641b6fd38SMatthew G. Knepley     if (mglevels->cr) {
10728b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
10841b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1099566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1109566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
1119566063dSJacob Faibussowitsch       PetscCall(KSPSetNoisy_Private(mglevels->crx));
1129566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1139566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11441b6fd38SMatthew G. Knepley     }
1159566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1164b9ad928SBarry Smith   }
1174b9ad928SBarry Smith   PetscFunctionReturn(0);
1184b9ad928SBarry Smith }
1194b9ad928SBarry Smith 
1209371c9d4SSatish Balay 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) {
121f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
122f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
123391689abSStefano Zampini   PC             tpc;
124391689abSStefano Zampini   PetscBool      changeu, changed;
125f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
1264b9ad928SBarry Smith 
1274b9ad928SBarry Smith   PetscFunctionBegin;
128a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
129a762d673SBarry Smith   for (i = 0; i < levels; i++) {
130a762d673SBarry Smith     if (!mglevels[i]->A) {
1319566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1329566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
133a762d673SBarry Smith     }
134a762d673SBarry Smith   }
135391689abSStefano Zampini 
1369566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1379566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1389566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1399566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
140391689abSStefano Zampini   if (!changed && !changeu) {
1419566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels - 1]->b));
142f3fbd535SBarry Smith     mglevels[levels - 1]->b = b;
143391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
144391689abSStefano Zampini     if (!mglevels[levels - 1]->b) {
145391689abSStefano Zampini       Vec *vec;
146391689abSStefano Zampini 
1479566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
148391689abSStefano Zampini       mglevels[levels - 1]->b = *vec;
1499566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
150391689abSStefano Zampini     }
1519566063dSJacob Faibussowitsch     PetscCall(VecCopy(b, mglevels[levels - 1]->b));
152391689abSStefano Zampini   }
153f3fbd535SBarry Smith   mglevels[levels - 1]->x = x;
1544b9ad928SBarry Smith 
15531567311SBarry Smith   mg->rtol   = rtol;
15631567311SBarry Smith   mg->abstol = abstol;
15731567311SBarry Smith   mg->dtol   = dtol;
1584b9ad928SBarry Smith   if (rtol) {
1594b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1604b9ad928SBarry Smith     PetscReal rnorm;
1617319c654SBarry Smith     if (zeroguess) {
1629566063dSJacob Faibussowitsch       PetscCall(VecNorm(b, NORM_2, &rnorm));
1637319c654SBarry Smith     } else {
1649566063dSJacob Faibussowitsch       PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1659566063dSJacob Faibussowitsch       PetscCall(VecNorm(w, NORM_2, &rnorm));
1667319c654SBarry Smith     }
16731567311SBarry Smith     mg->ttol = PetscMax(rtol * rnorm, abstol);
1682fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1692fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1704b9ad928SBarry Smith 
1714d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
172336babb1SJed Brown      stop prematurely due to small residual */
1734d0a8057SBarry Smith   for (i = 1; i < levels; i++) {
1749566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
175f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
17623067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1779566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1789566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
1794b9ad928SBarry Smith     }
1804d0a8057SBarry Smith   }
1814d0a8057SBarry Smith 
1824d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
1834d0a8057SBarry Smith   for (i = 0; i < its; i++) {
1849566063dSJacob Faibussowitsch     PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1854d0a8057SBarry Smith     if (*reason) break;
1864d0a8057SBarry Smith   }
1874d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1884d0a8057SBarry Smith   *outits = i;
189391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1904b9ad928SBarry Smith   PetscFunctionReturn(0);
1914b9ad928SBarry Smith }
1924b9ad928SBarry Smith 
1939371c9d4SSatish Balay PetscErrorCode PCReset_MG(PC pc) {
1943aeaf226SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1953aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1962b3cbbdaSStefano Zampini   PetscInt       i, n;
1973aeaf226SBarry Smith 
1983aeaf226SBarry Smith   PetscFunctionBegin;
1993aeaf226SBarry Smith   if (mglevels) {
2003aeaf226SBarry Smith     n = mglevels[0]->levels;
2013aeaf226SBarry Smith     for (i = 0; i < n - 1; i++) {
2029566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->r));
2039566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->b));
2049566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->x));
2059566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->R));
2069566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->B));
2079566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->X));
2089566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crx));
2099566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crb));
2109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2119566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2129566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2139566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2143aeaf226SBarry Smith     }
2159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crb));
217391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
218391689abSStefano Zampini        changes the rhs during PreSolve */
2199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->b));
2209566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mglevels[n - 1]->B));
2213aeaf226SBarry Smith 
2223aeaf226SBarry Smith     for (i = 0; i < n; i++) {
2232b3cbbdaSStefano Zampini       PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2249566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->A));
22548a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2269566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2279566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2283aeaf226SBarry Smith     }
229f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2303aeaf226SBarry Smith   }
2313aeaf226SBarry Smith   PetscFunctionReturn(0);
2323aeaf226SBarry Smith }
2333aeaf226SBarry Smith 
23441b6fd38SMatthew G. Knepley /* Implementing CR
23541b6fd38SMatthew G. Knepley 
23641b6fd38SMatthew 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
23741b6fd38SMatthew G. Knepley 
23841b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
23941b6fd38SMatthew G. Knepley 
24041b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24141b6fd38SMatthew G. Knepley 
24241b6fd38SMatthew G. Knepley   Inj^T Inj
24341b6fd38SMatthew G. Knepley 
24441b6fd38SMatthew G. Knepley and
24541b6fd38SMatthew G. Knepley 
24641b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
24741b6fd38SMatthew G. Knepley 
24841b6fd38SMatthew G. Knepley since
24941b6fd38SMatthew G. Knepley 
25041b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
25141b6fd38SMatthew G. Knepley 
25241b6fd38SMatthew G. Knepley Brannick suggests
25341b6fd38SMatthew G. Knepley 
25441b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
25541b6fd38SMatthew G. Knepley 
25641b6fd38SMatthew 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
25741b6fd38SMatthew G. Knepley 
25841b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
25941b6fd38SMatthew G. Knepley 
26041b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26141b6fd38SMatthew G. Knepley 
26241b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
26341b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
26441b6fd38SMatthew G. Knepley */
26541b6fd38SMatthew G. Knepley 
26641b6fd38SMatthew G. Knepley typedef struct {
26741b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
26841b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
26941b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27041b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
27141b6fd38SMatthew G. Knepley } CRContext;
27241b6fd38SMatthew G. Knepley 
2739371c9d4SSatish Balay static PetscErrorCode CRSetup_Private(PC pc) {
27441b6fd38SMatthew G. Knepley   CRContext *ctx;
27541b6fd38SMatthew G. Knepley   Mat        It;
27641b6fd38SMatthew G. Knepley 
27741b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2789566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2799566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28028b400f6SJacob Faibussowitsch   PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2819566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2829566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2839566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2849566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S, 1.0));
28541b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
28641b6fd38SMatthew G. Knepley }
28741b6fd38SMatthew G. Knepley 
2889371c9d4SSatish Balay static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y) {
28941b6fd38SMatthew G. Knepley   CRContext *ctx;
29041b6fd38SMatthew G. Knepley 
29141b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2929566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2939566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
29441b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
29541b6fd38SMatthew G. Knepley }
29641b6fd38SMatthew G. Knepley 
2979371c9d4SSatish Balay static PetscErrorCode CRDestroy_Private(PC pc) {
29841b6fd38SMatthew G. Knepley   CRContext *ctx;
29941b6fd38SMatthew G. Knepley 
30041b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3019566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3049566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3059566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
30641b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
30741b6fd38SMatthew G. Knepley }
30841b6fd38SMatthew G. Knepley 
3099371c9d4SSatish Balay static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr) {
31041b6fd38SMatthew G. Knepley   CRContext *ctx;
31141b6fd38SMatthew G. Knepley 
31241b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3139566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3149566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3159566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
31641b6fd38SMatthew G. Knepley   ctx->mg = pc;
31741b6fd38SMatthew G. Knepley   ctx->l  = l;
3189566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3199566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3209566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3219566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3229566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
32341b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
32441b6fd38SMatthew G. Knepley }
32541b6fd38SMatthew G. Knepley 
3269371c9d4SSatish Balay PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms) {
327f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG *)pc->data;
328ce94432eSBarry Smith   MPI_Comm       comm;
3293aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
33010eca3edSLisandro Dalcin   PCMGType       mgtype   = mg->am;
33110167fecSBarry Smith   PetscInt       mgctype  = (PetscInt)PC_MG_CYCLE_V;
332f3fbd535SBarry Smith   PetscInt       i;
333f3fbd535SBarry Smith   PetscMPIInt    size;
334f3fbd535SBarry Smith   const char    *prefix;
335f3fbd535SBarry Smith   PC             ipc;
3363aeaf226SBarry Smith   PetscInt       n;
3374b9ad928SBarry Smith 
3384b9ad928SBarry Smith   PetscFunctionBegin;
3390700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
340548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc, levels, 2);
341548767e0SJed Brown   if (mg->nlevels == levels) PetscFunctionReturn(0);
3429566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3433aeaf226SBarry Smith   if (mglevels) {
34410eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
3453aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
3469566063dSJacob Faibussowitsch     PetscCall(PCReset_MG(pc));
3473aeaf226SBarry Smith     n = mglevels[0]->levels;
3483aeaf226SBarry Smith     for (i = 0; i < n; i++) {
34948a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3509566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3519566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3529566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3533aeaf226SBarry Smith     }
3549566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3553aeaf226SBarry Smith   }
356f3fbd535SBarry Smith 
357f3fbd535SBarry Smith   mg->nlevels = levels;
358f3fbd535SBarry Smith 
3599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels, &mglevels));
360f3fbd535SBarry Smith 
3619566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
362f3fbd535SBarry Smith 
363a9db87a2SMatthew G Knepley   mg->stageApply = 0;
364f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
365*4dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mglevels[i]));
3662fa5cd67SKarl Rupp 
367f3fbd535SBarry Smith     mglevels[i]->level               = i;
368f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
36910eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
370336babb1SJed Brown     mg->default_smoothu              = 2;
371336babb1SJed Brown     mg->default_smoothd              = 2;
37263e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
37363e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
37463e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
37563e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
376f3fbd535SBarry Smith 
377f3fbd535SBarry Smith     if (comms) comm = comms[i];
378d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3799566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3809566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3819566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3829566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3839566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3840ee9a668SBarry Smith       if (i || levels == 1) {
3850ee9a668SBarry Smith         char tprefix[128];
3860ee9a668SBarry Smith 
3879566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
3889566063dSJacob Faibussowitsch         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
3899566063dSJacob Faibussowitsch         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
3909566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
3919566063dSJacob Faibussowitsch         PetscCall(PCSetType(ipc, PCSOR));
3929566063dSJacob Faibussowitsch         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
393f3fbd535SBarry Smith 
3949566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%d_", (int)i));
3959566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
3960ee9a668SBarry Smith       } else {
3979566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
398f3fbd535SBarry Smith 
3999dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4009566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4019566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4029566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
403f3fbd535SBarry Smith         if (size > 1) {
4049566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
405f3fbd535SBarry Smith         } else {
4069566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
407f3fbd535SBarry Smith         }
4089566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
409f3fbd535SBarry Smith       }
410d5a8f7e6SBarry Smith     }
411f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
41231567311SBarry Smith     mg->rtol             = 0.0;
41331567311SBarry Smith     mg->abstol           = 0.0;
41431567311SBarry Smith     mg->dtol             = 0.0;
41531567311SBarry Smith     mg->ttol             = 0.0;
41631567311SBarry Smith     mg->cyclesperpcapply = 1;
417f3fbd535SBarry Smith   }
418f3fbd535SBarry Smith   mg->levels = mglevels;
4199566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4204b9ad928SBarry Smith   PetscFunctionReturn(0);
4214b9ad928SBarry Smith }
4224b9ad928SBarry Smith 
42397d33e41SMatthew G. Knepley /*@C
424f1580f4eSBarry Smith    PCMGSetLevels - Sets the number of levels to use with `PCMG`.
425f1580f4eSBarry Smith    Must be called before any other `PCMG` routine.
42697d33e41SMatthew G. Knepley 
427f1580f4eSBarry Smith    Logically Collective on pc
42897d33e41SMatthew G. Knepley 
42997d33e41SMatthew G. Knepley    Input Parameters:
43097d33e41SMatthew G. Knepley +  pc - the preconditioner context
43197d33e41SMatthew G. Knepley .  levels - the number of levels
43297d33e41SMatthew G. Knepley -  comms - optional communicators for each level; this is to allow solving the coarser problems
433d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
434f1580f4eSBarry Smith            you must pass `MPI_COMM_NULL`. Use comms = NULL to specify that all processes
43505552d4bSJunchao Zhang            should participate in each level of problem.
43697d33e41SMatthew G. Knepley 
43797d33e41SMatthew G. Knepley    Level: intermediate
43897d33e41SMatthew G. Knepley 
43997d33e41SMatthew G. Knepley    Notes:
44097d33e41SMatthew G. Knepley      If the number of levels is one then the multigrid uses the -mg_levels prefix
44197d33e41SMatthew G. Knepley      for setting the level options rather than the -mg_coarse prefix.
44297d33e41SMatthew G. Knepley 
443d5a8f7e6SBarry Smith      You can free the information in comms after this routine is called.
444d5a8f7e6SBarry Smith 
445f1580f4eSBarry Smith      The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
446d5a8f7e6SBarry Smith      are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
447d5a8f7e6SBarry Smith      the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
448d5a8f7e6SBarry Smith      of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
449f1580f4eSBarry Smith      the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
450d5a8f7e6SBarry Smith      in the coarse grid solve.
451d5a8f7e6SBarry Smith 
452f1580f4eSBarry Smith      Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
453d5a8f7e6SBarry Smith      must take special care in providing the restriction and interpolation operation. We recommend
454d5a8f7e6SBarry Smith      providing these as two step operations; first perform a standard restriction or interpolation on
455d5a8f7e6SBarry Smith      the full number of ranks for that level and then use an MPI call to copy the resulting vector
45605552d4bSJunchao Zhang      array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
457d5a8f7e6SBarry Smith      cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
458d5a8f7e6SBarry Smith      recieves or MPI_AlltoAllv() could be used to do the reshuffling of the vector entries.
459d5a8f7e6SBarry Smith 
460f1580f4eSBarry Smith    Fortran Note:
461f1580f4eSBarry Smith      Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of NULL in the C interface. Note `PETSC_NULL_MPI_COMM`
462f1580f4eSBarry Smith      is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
463d5a8f7e6SBarry Smith 
464db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()`
46597d33e41SMatthew G. Knepley @*/
4669371c9d4SSatish Balay PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) {
46797d33e41SMatthew G. Knepley   PetscFunctionBegin;
46897d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
46997d33e41SMatthew G. Knepley   if (comms) PetscValidPointer(comms, 3);
470cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
47197d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
47297d33e41SMatthew G. Knepley }
47397d33e41SMatthew G. Knepley 
4749371c9d4SSatish Balay PetscErrorCode PCDestroy_MG(PC pc) {
475a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
476a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
477a06653b4SBarry Smith   PetscInt       i, n;
478c07bf074SBarry Smith 
479c07bf074SBarry Smith   PetscFunctionBegin;
4809566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
481a06653b4SBarry Smith   if (mglevels) {
482a06653b4SBarry Smith     n = mglevels[0]->levels;
483a06653b4SBarry Smith     for (i = 0; i < n; i++) {
48448a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
4859566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
4869566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
4879566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
488a06653b4SBarry Smith     }
4899566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
490a06653b4SBarry Smith   }
4919566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
4929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
4939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
4942b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
4952b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
4962b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
4972b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
4982b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
4992b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5002b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5012b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5022b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5032b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5042b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
505f3fbd535SBarry Smith   PetscFunctionReturn(0);
506f3fbd535SBarry Smith }
507f3fbd535SBarry Smith 
508f3fbd535SBarry Smith /*
509f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
510f3fbd535SBarry Smith              or full cycle of multigrid.
511f3fbd535SBarry Smith 
512f3fbd535SBarry Smith   Note:
513f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
514f3fbd535SBarry Smith */
5159371c9d4SSatish Balay static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) {
516f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
517f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
518391689abSStefano Zampini   PC             tpc;
519f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
52030b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
521f3fbd535SBarry Smith 
522f3fbd535SBarry Smith   PetscFunctionBegin;
52330b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5249566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
525e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
526298cc208SBarry Smith   for (i = 0; i < levels; i++) {
527e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5289566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5299566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
530e1d8e5deSBarry Smith     }
531e1d8e5deSBarry Smith   }
532e1d8e5deSBarry Smith 
5339566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5349566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5359566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5369566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
537391689abSStefano Zampini   if (!changeu && !changed) {
53830b0564aSStefano Zampini     if (matapp) {
5399566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
54030b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
54130b0564aSStefano Zampini     } else {
5429566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
543f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
54430b0564aSStefano Zampini     }
545391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
54630b0564aSStefano Zampini     if (matapp) {
54730b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
54830b0564aSStefano Zampini         PetscInt  N1, N2;
54930b0564aSStefano Zampini         PetscBool flg;
55030b0564aSStefano Zampini 
5519566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5529566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5539566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
55448a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
55530b0564aSStefano Zampini       }
55630b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5579566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
55830b0564aSStefano Zampini       } else {
5599566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
56030b0564aSStefano Zampini       }
56130b0564aSStefano Zampini     } else {
562391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
563391689abSStefano Zampini         Vec *vec;
564391689abSStefano Zampini 
5659566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
566391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5679566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
568391689abSStefano Zampini       }
5699566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
570391689abSStefano Zampini     }
57130b0564aSStefano Zampini   }
5729371c9d4SSatish Balay   if (matapp) {
5739371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
5749371c9d4SSatish Balay   } else {
5759371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
5769371c9d4SSatish Balay   }
57730b0564aSStefano Zampini 
57830b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
57930b0564aSStefano Zampini      Reset operators if sizes/type do no match */
58030b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
58130b0564aSStefano Zampini     PetscInt  Xc, Bc;
58230b0564aSStefano Zampini     PetscBool flg;
58330b0564aSStefano Zampini 
5849566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
5859566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
5869566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
58730b0564aSStefano Zampini     if (Xc != Bc || !flg) {
5889566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
58930b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
5909566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
5919566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
5929566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
59330b0564aSStefano Zampini       }
59430b0564aSStefano Zampini     }
59530b0564aSStefano Zampini   }
596391689abSStefano Zampini 
59731567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
5989566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
5999566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
60048a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6012fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6029566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6032fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6049566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6052fa5cd67SKarl Rupp   } else {
6069566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
607f3fbd535SBarry Smith   }
6089566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
60930b0564aSStefano Zampini   if (!changeu && !changed) {
6109371c9d4SSatish Balay     if (matapp) {
6119371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6129371c9d4SSatish Balay     } else {
6139371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6149371c9d4SSatish Balay     }
61530b0564aSStefano Zampini   }
616f3fbd535SBarry Smith   PetscFunctionReturn(0);
617f3fbd535SBarry Smith }
618f3fbd535SBarry Smith 
6199371c9d4SSatish Balay static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) {
620fcb023d4SJed Brown   PetscFunctionBegin;
6219566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
622fcb023d4SJed Brown   PetscFunctionReturn(0);
623fcb023d4SJed Brown }
624fcb023d4SJed Brown 
6259371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) {
626fcb023d4SJed Brown   PetscFunctionBegin;
6279566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
62830b0564aSStefano Zampini   PetscFunctionReturn(0);
62930b0564aSStefano Zampini }
63030b0564aSStefano Zampini 
6319371c9d4SSatish Balay static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) {
63230b0564aSStefano Zampini   PetscFunctionBegin;
6339566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
634fcb023d4SJed Brown   PetscFunctionReturn(0);
635fcb023d4SJed Brown }
636f3fbd535SBarry Smith 
6379371c9d4SSatish Balay PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject) {
638710315b6SLawrence Mitchell   PetscInt            levels, cycles;
639f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
640f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6413d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
642f3fbd535SBarry Smith   PCMGType            mgtype;
643f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6442134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6452b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
646f3fbd535SBarry Smith 
647f3fbd535SBarry Smith   PetscFunctionBegin;
6481d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
649d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6511a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6529566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
653eb3f98d2SBarry Smith     levels++;
6543aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
655eb3f98d2SBarry Smith   }
6569566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6573aeaf226SBarry Smith   mglevels = mg->levels;
6583aeaf226SBarry Smith 
659f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
6609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
6611baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
6622134b1e4SBarry Smith   gtype = mg->galerkin;
6639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)gtype, (PetscEnum *)&gtype, &flg));
6641baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
6652b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6662b3cbbdaSStefano 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));
6672b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
6689566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
6699566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
67041b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
6719566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
6729566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
673f56b1265SBarry Smith   flg = PETSC_FALSE;
6749566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
6751baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
67631567311SBarry Smith   mgtype = mg->am;
6779566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
6781baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
67931567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6809566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
6811baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
682f3fbd535SBarry Smith   }
683f3fbd535SBarry Smith   flg = PETSC_FALSE;
6849566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
685f3fbd535SBarry Smith   if (flg) {
686f3fbd535SBarry Smith     PetscInt i;
687f3fbd535SBarry Smith     char     eventname[128];
6881a97d7b6SStefano Zampini 
689f3fbd535SBarry Smith     levels = mglevels[0]->levels;
690f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
691f3fbd535SBarry Smith       sprintf(eventname, "MGSetup Level %d", (int)i);
6929566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
693f3fbd535SBarry Smith       sprintf(eventname, "MGSmooth Level %d", (int)i);
6949566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
695f3fbd535SBarry Smith       if (i) {
696f3fbd535SBarry Smith         sprintf(eventname, "MGResid Level %d", (int)i);
6979566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
698f3fbd535SBarry Smith         sprintf(eventname, "MGInterp Level %d", (int)i);
6999566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
700f3fbd535SBarry Smith       }
701f3fbd535SBarry Smith     }
702eec35531SMatthew G Knepley 
703ec60ca73SSatish Balay #if defined(PETSC_USE_LOG)
704eec35531SMatthew G Knepley     {
705eec35531SMatthew G Knepley       const char   *sname = "MG Apply";
706eec35531SMatthew G Knepley       PetscStageLog stageLog;
707eec35531SMatthew G Knepley       PetscInt      st;
708eec35531SMatthew G Knepley 
7099566063dSJacob Faibussowitsch       PetscCall(PetscLogGetStageLog(&stageLog));
710eec35531SMatthew G Knepley       for (st = 0; st < stageLog->numStages; ++st) {
711eec35531SMatthew G Knepley         PetscBool same;
712eec35531SMatthew G Knepley 
7139566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(stageLog->stageInfo[st].name, sname, &same));
7142fa5cd67SKarl Rupp         if (same) mg->stageApply = st;
715eec35531SMatthew G Knepley       }
71648a46eb9SPierre Jolivet       if (!mg->stageApply) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
717eec35531SMatthew G Knepley     }
718ec60ca73SSatish Balay #endif
719f3fbd535SBarry Smith   }
720d0609cedSBarry Smith   PetscOptionsHeadEnd();
721f3b08a26SMatthew G. Knepley   /* Check option consistency */
7229566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7239566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
72408401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
725f3fbd535SBarry Smith   PetscFunctionReturn(0);
726f3fbd535SBarry Smith }
727f3fbd535SBarry Smith 
7280a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7290a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7300a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7312b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
732f3fbd535SBarry Smith 
7339804daf3SBarry Smith #include <petscdraw.h>
7349371c9d4SSatish Balay PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) {
735f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
736f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
737e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
738219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
739f3fbd535SBarry Smith 
740f3fbd535SBarry Smith   PetscFunctionBegin;
7419566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7429566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
744f3fbd535SBarry Smith   if (iascii) {
745e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
74663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
74748a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7482134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7499566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7502134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7519566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7522134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7539566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7542134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7559566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7564f66f45eSBarry Smith     } else {
7579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
758f3fbd535SBarry Smith     }
7591baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
760f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
76163a3b9bcSJacob Faibussowitsch       if (i) {
76263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
763f3fbd535SBarry Smith       } else {
76463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
765f3fbd535SBarry Smith       }
7669566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7679566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
769f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
7709566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
771f3fbd535SBarry Smith       } else if (i) {
77263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
7739566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7749566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7759566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
776f3fbd535SBarry Smith       }
77741b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
77863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
7799566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7809566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
7819566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
78241b6fd38SMatthew G. Knepley       }
783f3fbd535SBarry Smith     }
7845b0b0462SBarry Smith   } else if (isbinary) {
7855b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
7869566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
78748a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7885b0b0462SBarry Smith     }
789219b1045SBarry Smith   } else if (isdraw) {
790219b1045SBarry Smith     PetscDraw draw;
791b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
7929566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
7939566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
7949566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
795219b1045SBarry Smith     bottom = y - th;
796219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
797b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
7989566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
7999566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8009566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
801b4375e8dSPeter Brune       } else {
802b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8039566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8049566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8059566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8069566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8079566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8089566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
809b4375e8dSPeter Brune       }
8109566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8111cd381d6SBarry Smith       bottom -= th;
812219b1045SBarry Smith     }
8135b0b0462SBarry Smith   }
814f3fbd535SBarry Smith   PetscFunctionReturn(0);
815f3fbd535SBarry Smith }
816f3fbd535SBarry Smith 
817af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
818cab2e9ccSBarry Smith 
819f3fbd535SBarry Smith /*
820f3fbd535SBarry Smith     Calls setup for the KSP on each level
821f3fbd535SBarry Smith */
8229371c9d4SSatish Balay PetscErrorCode PCSetUp_MG(PC pc) {
823f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
824f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8251a97d7b6SStefano Zampini   PetscInt       i, n;
82698e04984SBarry Smith   PC             cpc;
8273db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
828f3fbd535SBarry Smith   Mat            dA, dB;
829f3fbd535SBarry Smith   Vec            tvec;
830218a07d4SBarry Smith   DM            *dms;
8310a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
83241b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8332b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
834f3fbd535SBarry Smith 
835f3fbd535SBarry Smith   PetscFunctionBegin;
83628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8371a97d7b6SStefano Zampini   n = mglevels[0]->levels;
83801bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8393aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8403aeaf226SBarry Smith     PetscInt levels;
8419566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8423aeaf226SBarry Smith     levels++;
8433aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8449566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8453aeaf226SBarry Smith       n = levels;
8469566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8473aeaf226SBarry Smith       mglevels = mg->levels;
8483aeaf226SBarry Smith     }
8493aeaf226SBarry Smith   }
8509566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc));
8513aeaf226SBarry Smith 
852f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
853f3fbd535SBarry Smith   /* so use those from global PC */
854f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8559566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
85698e04984SBarry Smith   if (opsset) {
85798e04984SBarry Smith     Mat mmat;
8589566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
85998e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
86098e04984SBarry Smith   }
8614a5f07a5SMark F. Adams 
86241b6fd38SMatthew G. Knepley   /* Create CR solvers */
8639566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
86441b6fd38SMatthew G. Knepley   if (doCR) {
86541b6fd38SMatthew G. Knepley     const char *prefix;
86641b6fd38SMatthew G. Knepley 
8679566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
86841b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
86941b6fd38SMatthew G. Knepley       PC   ipc, cr;
87041b6fd38SMatthew G. Knepley       char crprefix[128];
87141b6fd38SMatthew G. Knepley 
8729566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
8739566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
8749566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
8759566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
8769566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
8779566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
8789566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
8799566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
8809566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
88141b6fd38SMatthew G. Knepley 
8829566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
8839566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
8849566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
8859566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
8869566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
8879566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
88841b6fd38SMatthew G. Knepley 
8899566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
8909566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
8919566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int)i));
8929566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
89341b6fd38SMatthew G. Knepley     }
89441b6fd38SMatthew G. Knepley   }
89541b6fd38SMatthew G. Knepley 
8964a5f07a5SMark F. Adams   if (!opsset) {
8979566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
8984a5f07a5SMark F. Adams     if (use_amat) {
8999566063dSJacob 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"));
9009566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
90169858f1bSStefano Zampini     } else {
9029566063dSJacob 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"));
9039566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9044a5f07a5SMark F. Adams     }
9054a5f07a5SMark F. Adams   }
906f3fbd535SBarry Smith 
9079c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9089c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9099c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9102b3cbbdaSStefano Zampini       break;
9119c7ffb39SBarry Smith     }
9129c7ffb39SBarry Smith   }
9132134b1e4SBarry Smith 
9149566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9152134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9162b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9172134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9182134b1e4SBarry Smith   }
9192134b1e4SBarry Smith 
9202b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9212b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9222b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9232b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9242b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9252b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9262b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9272b3cbbdaSStefano Zampini     }
9282b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9292b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9302b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9312b3cbbdaSStefano Zampini     }
9322b3cbbdaSStefano Zampini   }
9332b3cbbdaSStefano Zampini 
9349c7ffb39SBarry Smith   /*
9359c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9362b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9379c7ffb39SBarry Smith   */
93832fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
93932fe681dSStefano Zampini     /* first see if we can compute a coarse space */
94032fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
94132fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
94232fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
94332fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
94432fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
94532fe681dSStefano Zampini         }
94632fe681dSStefano Zampini       }
94732fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9482e499ae9SBarry Smith       Mat p;
94973250ac0SBarry Smith       Vec rscale;
9509566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
951218a07d4SBarry Smith       dms[n - 1] = pc->dm;
952ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9539566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
954218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
955942e3340SBarry Smith         DMKSP     kdm;
956eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9579566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9589566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
959c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9609566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9619566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
962c27ee7a3SPatrick Farrell         }
96341b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9649566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
9659566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
96641b6fd38SMatthew G. Knepley         }
9679566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
968d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
969d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
9700298fd71SBarry Smith         kdm->ops->computerhs = NULL;
9710298fd71SBarry Smith         kdm->rhsctx          = NULL;
97224c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
9739566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
9749566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
9759566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
9769566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
9779566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
978218a07d4SBarry Smith         }
9799566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
9803ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
9819566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
9829566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
9839566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
9843ad4599aSBarry Smith         }
9859566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
986eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
9879566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
9889566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
9899566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
990eab52d2bSLawrence Mitchell         }
99124c3aa18SBarry Smith       }
9922d2b81a6SBarry Smith 
9939566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
9949566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
995ce4cda84SJed Brown     }
99632fe681dSStefano Zampini   }
997cab2e9ccSBarry Smith 
9982134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
9992134b1e4SBarry Smith     Mat       A, B;
10002134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10012134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10022134b1e4SBarry Smith 
10032b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10042b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10052134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1006f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10077827d75bSBarry 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");
100848a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
100948a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
101048a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
101148a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
101248a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10132134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10142134b1e4SBarry Smith       if (!doA && dAeqdB) {
10159566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10162134b1e4SBarry Smith         A = B;
10172134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10189566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10199566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1020b9367914SBarry Smith       }
10212134b1e4SBarry Smith       if (!doB && dAeqdB) {
10229566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10232134b1e4SBarry Smith         B = A;
10242134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10259566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10269566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10277d537d92SJed Brown       }
10282134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10299566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10309566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10319566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10322134b1e4SBarry Smith       }
10332134b1e4SBarry Smith       dA = A;
1034f3fbd535SBarry Smith       dB = B;
1035f3fbd535SBarry Smith     }
1036f3fbd535SBarry Smith   }
1037f3b08a26SMatthew G. Knepley 
1038f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10392b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1040f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
104148a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10422b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1043f3b08a26SMatthew G. Knepley     }
104448a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1045f3b08a26SMatthew G. Knepley   }
1046f3b08a26SMatthew G. Knepley 
10472134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1048caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1049ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1050caa4e7f2SJed Brown       Mat Restrict, Inject;
1051caa4e7f2SJed Brown       Vec rscale;
10529566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10539566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10549566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10559566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10569566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10579566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1058caa4e7f2SJed Brown     }
1059caa4e7f2SJed Brown   }
1060f3fbd535SBarry Smith 
1061f3fbd535SBarry Smith   if (!pc->setupcalled) {
106248a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1063f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
106448a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
106548a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1066f3fbd535SBarry Smith     }
10673ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
1068f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
10699566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
10709566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1071f3fbd535SBarry Smith     }
1072f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1073f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1074f3fbd535SBarry Smith         Vec *vec;
10759566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
10769566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
10779566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
10789566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1079f3fbd535SBarry Smith       }
1080f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
10819566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10829566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
10839566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1084f3fbd535SBarry Smith       }
1085f3fbd535SBarry Smith       if (!mglevels[i]->x) {
10869566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10879566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
10889566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1089f3fbd535SBarry Smith       }
109041b6fd38SMatthew G. Knepley       if (doCR) {
10919566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
10929566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
10939566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
109441b6fd38SMatthew G. Knepley       }
1095f3fbd535SBarry Smith     }
1096f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1097f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1098f3fbd535SBarry Smith       Vec *vec;
10999566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11009566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11019566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11029566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1103f3fbd535SBarry Smith     }
110441b6fd38SMatthew G. Knepley     if (doCR) {
11059566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11069566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11079566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
110841b6fd38SMatthew G. Knepley     }
1109f3fbd535SBarry Smith   }
1110f3fbd535SBarry Smith 
111198e04984SBarry Smith   if (pc->dm) {
111298e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
111398e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
111498e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
111598e04984SBarry Smith     }
111698e04984SBarry Smith   }
111708549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
111808549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
111908549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1120f3fbd535SBarry Smith 
1121f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11222a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1123f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11249566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1125f3fbd535SBarry Smith     }
11269566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11279566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11289566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1129ad540459SPierre Jolivet     if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11309566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1131d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1132d42688cbSBarry Smith       Mat mat;
11339566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11349566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1135d42688cbSBarry Smith     }
1136fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1137fcb023d4SJed Brown       Mat mat;
11389566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11399566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1140fcb023d4SJed Brown     }
1141f3fbd535SBarry Smith   }
1142f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1143f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1144f3fbd535SBarry Smith       Mat downmat, downpmat;
1145f3fbd535SBarry Smith 
1146f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11479566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1148f3fbd535SBarry Smith       if (!opsset) {
11499566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11509566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1151f3fbd535SBarry Smith       }
1152f3fbd535SBarry Smith 
11539566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11549566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11559566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1156ad540459SPierre Jolivet       if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11579566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1158f3fbd535SBarry Smith     }
115941b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
116041b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
116141b6fd38SMatthew G. Knepley 
116241b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
11639566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
116441b6fd38SMatthew G. Knepley       if (!opsset) {
11659566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11669566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
116741b6fd38SMatthew G. Knepley       }
116841b6fd38SMatthew G. Knepley 
11699566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11709566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11719566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1172ad540459SPierre Jolivet       if (mglevels[i]->cr->reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11739566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
117441b6fd38SMatthew G. Knepley     }
1175f3fbd535SBarry Smith   }
1176f3fbd535SBarry Smith 
11779566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
11789566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1179ad540459SPierre Jolivet   if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
11809566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1181f3fbd535SBarry Smith 
1182f3fbd535SBarry Smith     /*
1183f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1184e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1185f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1186f3fbd535SBarry Smith 
1187f3fbd535SBarry Smith    Only support one or the other at the same time.
1188f3fbd535SBarry Smith   */
1189f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
11909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1191ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1192f3fbd535SBarry Smith   dump = PETSC_FALSE;
1193f3fbd535SBarry Smith #endif
11949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1195ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1196f3fbd535SBarry Smith 
1197f3fbd535SBarry Smith   if (viewer) {
119848a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1199f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12009566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12019566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1202f3fbd535SBarry Smith     }
1203f3fbd535SBarry Smith   }
1204f3fbd535SBarry Smith   PetscFunctionReturn(0);
1205f3fbd535SBarry Smith }
1206f3fbd535SBarry Smith 
1207f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
1208f3fbd535SBarry Smith 
12099371c9d4SSatish Balay PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) {
121097d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
121197d33e41SMatthew G. Knepley 
121297d33e41SMatthew G. Knepley   PetscFunctionBegin;
121397d33e41SMatthew G. Knepley   *levels = mg->nlevels;
121497d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
121597d33e41SMatthew G. Knepley }
121697d33e41SMatthew G. Knepley 
12174b9ad928SBarry Smith /*@
1218f1580f4eSBarry Smith    PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12194b9ad928SBarry Smith 
12204b9ad928SBarry Smith    Not Collective
12214b9ad928SBarry Smith 
12224b9ad928SBarry Smith    Input Parameter:
12234b9ad928SBarry Smith .  pc - the preconditioner context
12244b9ad928SBarry Smith 
12254b9ad928SBarry Smith    Output parameter:
12264b9ad928SBarry Smith .  levels - the number of levels
12274b9ad928SBarry Smith 
12284b9ad928SBarry Smith    Level: advanced
12294b9ad928SBarry Smith 
1230f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetLevels()`
12314b9ad928SBarry Smith @*/
12329371c9d4SSatish Balay PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) {
12334b9ad928SBarry Smith   PetscFunctionBegin;
12340700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12354482741eSBarry Smith   PetscValidIntPointer(levels, 2);
123697d33e41SMatthew G. Knepley   *levels = 0;
1237cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12384b9ad928SBarry Smith   PetscFunctionReturn(0);
12394b9ad928SBarry Smith }
12404b9ad928SBarry Smith 
12414b9ad928SBarry Smith /*@
1242f1580f4eSBarry Smith    PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1243e7d4b4cbSMark Adams 
1244e7d4b4cbSMark Adams    Input Parameter:
1245e7d4b4cbSMark Adams .  pc - the preconditioner context
1246e7d4b4cbSMark Adams 
124790db8557SMark Adams    Output Parameters:
124890db8557SMark Adams +  gc - grid complexity = sum_i(n_i) / n_0
124990db8557SMark Adams -  oc - operator complexity = sum_i(nnz_i) / nnz_0
1250e7d4b4cbSMark Adams 
1251e7d4b4cbSMark Adams    Level: advanced
1252e7d4b4cbSMark Adams 
1253f1580f4eSBarry Smith    Note:
1254f1580f4eSBarry Smith    This is often call the operator complexity in multigrid literature
1255f1580f4eSBarry Smith 
1256f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1257e7d4b4cbSMark Adams @*/
12589371c9d4SSatish Balay PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc) {
1259e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1260e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1261e7d4b4cbSMark Adams   PetscInt       lev, N;
1262e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1263e7d4b4cbSMark Adams   MatInfo        info;
1264e7d4b4cbSMark Adams 
1265e7d4b4cbSMark Adams   PetscFunctionBegin;
126690db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
126790db8557SMark Adams   if (gc) PetscValidRealPointer(gc, 2);
126890db8557SMark Adams   if (oc) PetscValidRealPointer(oc, 3);
1269e7d4b4cbSMark Adams   if (!pc->setupcalled) {
127090db8557SMark Adams     if (gc) *gc = 0;
127190db8557SMark Adams     if (oc) *oc = 0;
1272e7d4b4cbSMark Adams     PetscFunctionReturn(0);
1273e7d4b4cbSMark Adams   }
1274e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1275e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1276e7d4b4cbSMark Adams     Mat dB;
12779566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
12789566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
12799566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1280e7d4b4cbSMark Adams     sgc += N;
1281e7d4b4cbSMark Adams     soc += info.nz_used;
12829371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
12839371c9d4SSatish Balay       nnz0 = info.nz_used;
12849371c9d4SSatish Balay       n0   = N;
12859371c9d4SSatish Balay     }
1286e7d4b4cbSMark Adams   }
128790db8557SMark Adams   if (n0 > 0 && gc) *gc = (PetscReal)(sgc / n0);
1288e7d4b4cbSMark Adams   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
128990db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
1290e7d4b4cbSMark Adams   PetscFunctionReturn(0);
1291e7d4b4cbSMark Adams }
1292e7d4b4cbSMark Adams 
1293e7d4b4cbSMark Adams /*@
129497177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
12954b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
12964b9ad928SBarry Smith 
1297f1580f4eSBarry Smith    Logically Collective on pc
12984b9ad928SBarry Smith 
12994b9ad928SBarry Smith    Input Parameters:
13004b9ad928SBarry Smith +  pc - the preconditioner context
1301f1580f4eSBarry Smith -  form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13024b9ad928SBarry Smith 
13034b9ad928SBarry Smith    Options Database Key:
13044b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
13054b9ad928SBarry Smith    additive, full, kaskade
13064b9ad928SBarry Smith 
13074b9ad928SBarry Smith    Level: advanced
13084b9ad928SBarry Smith 
1309f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13104b9ad928SBarry Smith @*/
13119371c9d4SSatish Balay PetscErrorCode PCMGSetType(PC pc, PCMGType form) {
1312f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13134b9ad928SBarry Smith 
13144b9ad928SBarry Smith   PetscFunctionBegin;
13150700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1316c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
131731567311SBarry Smith   mg->am = form;
13189dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1319c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
1320c60c7ad4SBarry Smith   PetscFunctionReturn(0);
1321c60c7ad4SBarry Smith }
1322c60c7ad4SBarry Smith 
1323c60c7ad4SBarry Smith /*@
1324f1580f4eSBarry Smith    PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1325c60c7ad4SBarry Smith 
1326f1580f4eSBarry Smith    Logically Collective on pc
1327c60c7ad4SBarry Smith 
1328c60c7ad4SBarry Smith    Input Parameter:
1329c60c7ad4SBarry Smith .  pc - the preconditioner context
1330c60c7ad4SBarry Smith 
1331c60c7ad4SBarry Smith    Output Parameter:
1332f1580f4eSBarry Smith .  type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1333c60c7ad4SBarry Smith 
1334c60c7ad4SBarry Smith    Level: advanced
1335c60c7ad4SBarry Smith 
1336f1580f4eSBarry Smith .seealso: `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1337c60c7ad4SBarry Smith @*/
13389371c9d4SSatish Balay PetscErrorCode PCMGGetType(PC pc, PCMGType *type) {
1339c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1340c60c7ad4SBarry Smith 
1341c60c7ad4SBarry Smith   PetscFunctionBegin;
1342c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1343c60c7ad4SBarry Smith   *type = mg->am;
13444b9ad928SBarry Smith   PetscFunctionReturn(0);
13454b9ad928SBarry Smith }
13464b9ad928SBarry Smith 
13474b9ad928SBarry Smith /*@
1348f1580f4eSBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
13494b9ad928SBarry Smith    complicated cycling.
13504b9ad928SBarry Smith 
1351f1580f4eSBarry Smith    Logically Collective on pc
13524b9ad928SBarry Smith 
13534b9ad928SBarry Smith    Input Parameters:
1354c2be2410SBarry Smith +  pc - the multigrid context
1355f1580f4eSBarry Smith -  n - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
13564b9ad928SBarry Smith 
13574b9ad928SBarry Smith    Options Database Key:
1358c1cbb1deSBarry Smith .  -pc_mg_cycle_type <v,w> - provide the cycle desired
13594b9ad928SBarry Smith 
13604b9ad928SBarry Smith    Level: advanced
13614b9ad928SBarry Smith 
1362f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
13634b9ad928SBarry Smith @*/
13649371c9d4SSatish Balay PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) {
1365f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1366f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
136779416396SBarry Smith   PetscInt       i, levels;
13684b9ad928SBarry Smith 
13694b9ad928SBarry Smith   PetscFunctionBegin;
13700700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
137169fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
137228b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1373f3fbd535SBarry Smith   levels = mglevels[0]->levels;
13742fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
13754b9ad928SBarry Smith   PetscFunctionReturn(0);
13764b9ad928SBarry Smith }
13774b9ad928SBarry Smith 
13788cc2d5dfSBarry Smith /*@
13798cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1380f1580f4eSBarry Smith          of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
13818cc2d5dfSBarry Smith 
1382f1580f4eSBarry Smith    Logically Collective on pc
13838cc2d5dfSBarry Smith 
13848cc2d5dfSBarry Smith    Input Parameters:
13858cc2d5dfSBarry Smith +  pc - the multigrid context
13868cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
13878cc2d5dfSBarry Smith 
13888cc2d5dfSBarry Smith    Options Database Key:
1389147403d9SBarry Smith .  -pc_mg_multiplicative_cycles n - set the number of cycles
13908cc2d5dfSBarry Smith 
13918cc2d5dfSBarry Smith    Level: advanced
13928cc2d5dfSBarry Smith 
1393f1580f4eSBarry Smith    Note:
1394f1580f4eSBarry Smith     This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
13958cc2d5dfSBarry Smith 
1396f1580f4eSBarry Smith .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
13978cc2d5dfSBarry Smith @*/
13989371c9d4SSatish Balay PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) {
1399f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14008cc2d5dfSBarry Smith 
14018cc2d5dfSBarry Smith   PetscFunctionBegin;
14020700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1403c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14042a21e185SBarry Smith   mg->cyclesperpcapply = n;
14058cc2d5dfSBarry Smith   PetscFunctionReturn(0);
14068cc2d5dfSBarry Smith }
14078cc2d5dfSBarry Smith 
14089371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) {
1409fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1410fb15c04eSBarry Smith 
1411fb15c04eSBarry Smith   PetscFunctionBegin;
14122134b1e4SBarry Smith   mg->galerkin = use;
1413fb15c04eSBarry Smith   PetscFunctionReturn(0);
1414fb15c04eSBarry Smith }
1415fb15c04eSBarry Smith 
1416c2be2410SBarry Smith /*@
141797177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
141882b87d87SMatthew G. Knepley       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1419c2be2410SBarry Smith 
1420f1580f4eSBarry Smith    Logically Collective on pc
1421c2be2410SBarry Smith 
1422c2be2410SBarry Smith    Input Parameters:
1423c91913d3SJed Brown +  pc - the multigrid context
1424f1580f4eSBarry Smith -  use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1425c2be2410SBarry Smith 
1426c2be2410SBarry Smith    Options Database Key:
1427147403d9SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1428c2be2410SBarry Smith 
1429c2be2410SBarry Smith    Level: intermediate
1430c2be2410SBarry Smith 
1431f1580f4eSBarry Smith    Note:
1432f1580f4eSBarry Smith    Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1433f1580f4eSBarry Smith    use the `PCMG` construction of the coarser grids.
14341c1aac46SBarry Smith 
1435f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1436c2be2410SBarry Smith @*/
14379371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) {
1438c2be2410SBarry Smith   PetscFunctionBegin;
14390700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1440cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
1441c2be2410SBarry Smith   PetscFunctionReturn(0);
1442c2be2410SBarry Smith }
1443c2be2410SBarry Smith 
14443fc8bf9cSBarry Smith /*@
1445f1580f4eSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
14463fc8bf9cSBarry Smith 
14473fc8bf9cSBarry Smith    Not Collective
14483fc8bf9cSBarry Smith 
14493fc8bf9cSBarry Smith    Input Parameter:
14503fc8bf9cSBarry Smith .  pc - the multigrid context
14513fc8bf9cSBarry Smith 
14523fc8bf9cSBarry Smith    Output Parameter:
1453f1580f4eSBarry 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`
14543fc8bf9cSBarry Smith 
14553fc8bf9cSBarry Smith    Level: intermediate
14563fc8bf9cSBarry Smith 
1457f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
14583fc8bf9cSBarry Smith @*/
14599371c9d4SSatish Balay PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) {
1460f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14613fc8bf9cSBarry Smith 
14623fc8bf9cSBarry Smith   PetscFunctionBegin;
14630700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14642134b1e4SBarry Smith   *galerkin = mg->galerkin;
14653fc8bf9cSBarry Smith   PetscFunctionReturn(0);
14663fc8bf9cSBarry Smith }
14673fc8bf9cSBarry Smith 
14689371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) {
1469f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1470f3b08a26SMatthew G. Knepley 
1471f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1472f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
1473f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1474f3b08a26SMatthew G. Knepley }
1475f3b08a26SMatthew G. Knepley 
14769371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) {
1477f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1478f3b08a26SMatthew G. Knepley 
1479f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1480f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
1481f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1482f3b08a26SMatthew G. Knepley }
1483f3b08a26SMatthew G. Knepley 
14849371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) {
14852b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
14862b3cbbdaSStefano Zampini 
14872b3cbbdaSStefano Zampini   PetscFunctionBegin;
14882b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
14892b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
14902b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
14912b3cbbdaSStefano Zampini }
14922b3cbbdaSStefano Zampini 
14939371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) {
14942b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
14952b3cbbdaSStefano Zampini 
14962b3cbbdaSStefano Zampini   PetscFunctionBegin;
14972b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
14982b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
14992b3cbbdaSStefano Zampini }
15002b3cbbdaSStefano Zampini 
15019371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) {
150241b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
150341b6fd38SMatthew G. Knepley 
150441b6fd38SMatthew G. Knepley   PetscFunctionBegin;
150541b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
150641b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
150741b6fd38SMatthew G. Knepley }
150841b6fd38SMatthew G. Knepley 
15099371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) {
151041b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
151141b6fd38SMatthew G. Knepley 
151241b6fd38SMatthew G. Knepley   PetscFunctionBegin;
151341b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
151441b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
151541b6fd38SMatthew G. Knepley }
151641b6fd38SMatthew G. Knepley 
15172b3cbbdaSStefano Zampini /*@C
15182b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15192b3cbbdaSStefano Zampini 
15202b3cbbdaSStefano 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.
15212b3cbbdaSStefano Zampini 
1522f1580f4eSBarry Smith   Logically Collective on pc
15232b3cbbdaSStefano Zampini 
15242b3cbbdaSStefano Zampini   Input Parameters:
15252b3cbbdaSStefano Zampini + pc    - the multigrid context
15262b3cbbdaSStefano Zampini - ctype - the type of coarse space
15272b3cbbdaSStefano Zampini 
15282b3cbbdaSStefano Zampini   Options Database Keys:
15292b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
15302b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw
15312b3cbbdaSStefano Zampini 
15322b3cbbdaSStefano Zampini   Level: intermediate
15332b3cbbdaSStefano Zampini 
1534f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
15352b3cbbdaSStefano Zampini @*/
15369371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) {
15372b3cbbdaSStefano Zampini   PetscFunctionBegin;
15382b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15392b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
15402b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
15412b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15422b3cbbdaSStefano Zampini }
15432b3cbbdaSStefano Zampini 
15442b3cbbdaSStefano Zampini /*@C
15452b3cbbdaSStefano Zampini    PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
15462b3cbbdaSStefano Zampini 
15472b3cbbdaSStefano Zampini    Not Collective
15482b3cbbdaSStefano Zampini 
15492b3cbbdaSStefano Zampini    Input Parameter:
15502b3cbbdaSStefano Zampini .  pc    - the multigrid context
15512b3cbbdaSStefano Zampini 
15522b3cbbdaSStefano Zampini    Output Parameter:
15532b3cbbdaSStefano Zampini .  ctype - the type of coarse space
15542b3cbbdaSStefano Zampini 
15552b3cbbdaSStefano Zampini   Level: intermediate
15562b3cbbdaSStefano Zampini 
1557f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
15582b3cbbdaSStefano Zampini @*/
15599371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) {
15602b3cbbdaSStefano Zampini   PetscFunctionBegin;
15612b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15622b3cbbdaSStefano Zampini   PetscValidPointer(ctype, 2);
15632b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
15642b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15652b3cbbdaSStefano Zampini }
15662b3cbbdaSStefano Zampini 
15672b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1568f3b08a26SMatthew G. Knepley /*@
1569f3b08a26SMatthew 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.
1570f3b08a26SMatthew G. Knepley 
1571f1580f4eSBarry Smith    Logically Collective on pc
1572f3b08a26SMatthew G. Knepley 
1573f3b08a26SMatthew G. Knepley    Input Parameters:
1574f3b08a26SMatthew G. Knepley +  pc    - the multigrid context
1575f3b08a26SMatthew G. Knepley -  adapt - flag for adaptation of the interpolator
1576f3b08a26SMatthew G. Knepley 
1577f3b08a26SMatthew G. Knepley    Options Database Keys:
1578f3b08a26SMatthew G. Knepley +  -pc_mg_adapt_interp                     - Turn on adaptation
1579f3b08a26SMatthew G. Knepley .  -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1580f3b08a26SMatthew G. Knepley -  -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1581f3b08a26SMatthew G. Knepley 
1582f3b08a26SMatthew G. Knepley   Level: intermediate
1583f3b08a26SMatthew G. Knepley 
1584f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1585f3b08a26SMatthew G. Knepley @*/
15869371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) {
1587f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1588f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1589cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
1590f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1591f3b08a26SMatthew G. Knepley }
1592f3b08a26SMatthew G. Knepley 
1593f3b08a26SMatthew G. Knepley /*@
1594f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1595f1580f4eSBarry Smith   and thus accurately interpolated.
1596f3b08a26SMatthew G. Knepley 
1597f3b08a26SMatthew G. Knepley   Not collective
1598f3b08a26SMatthew G. Knepley 
1599f3b08a26SMatthew G. Knepley   Input Parameter:
1600f3b08a26SMatthew G. Knepley . pc    - the multigrid context
1601f3b08a26SMatthew G. Knepley 
1602f3b08a26SMatthew G. Knepley   Output Parameter:
1603f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1604f3b08a26SMatthew G. Knepley 
1605f3b08a26SMatthew G. Knepley   Level: intermediate
1606f3b08a26SMatthew G. Knepley 
1607f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1608f3b08a26SMatthew G. Knepley @*/
16099371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) {
1610f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1611f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1612dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(adapt, 2);
1613cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
1614f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1615f3b08a26SMatthew G. Knepley }
1616f3b08a26SMatthew G. Knepley 
16174b9ad928SBarry Smith /*@
161841b6fd38SMatthew G. Knepley    PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
161941b6fd38SMatthew G. Knepley 
1620f1580f4eSBarry Smith    Logically Collective on pc
162141b6fd38SMatthew G. Knepley 
162241b6fd38SMatthew G. Knepley    Input Parameters:
162341b6fd38SMatthew G. Knepley +  pc - the multigrid context
162441b6fd38SMatthew G. Knepley -  cr - flag for compatible relaxation
162541b6fd38SMatthew G. Knepley 
1626f1580f4eSBarry Smith    Options Database Key:
162741b6fd38SMatthew G. Knepley .  -pc_mg_adapt_cr - Turn on compatible relaxation
162841b6fd38SMatthew G. Knepley 
162941b6fd38SMatthew G. Knepley    Level: intermediate
163041b6fd38SMatthew G. Knepley 
1631f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
163241b6fd38SMatthew G. Knepley @*/
16339371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) {
163441b6fd38SMatthew G. Knepley   PetscFunctionBegin;
163541b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1636cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
163741b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
163841b6fd38SMatthew G. Knepley }
163941b6fd38SMatthew G. Knepley 
164041b6fd38SMatthew G. Knepley /*@
164141b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
164241b6fd38SMatthew G. Knepley 
164341b6fd38SMatthew G. Knepley   Not collective
164441b6fd38SMatthew G. Knepley 
164541b6fd38SMatthew G. Knepley   Input Parameter:
164641b6fd38SMatthew G. Knepley . pc    - the multigrid context
164741b6fd38SMatthew G. Knepley 
164841b6fd38SMatthew G. Knepley   Output Parameter:
164941b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
165041b6fd38SMatthew G. Knepley 
165141b6fd38SMatthew G. Knepley   Level: intermediate
165241b6fd38SMatthew G. Knepley 
1653f1580f4eSBarry Smith .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
165441b6fd38SMatthew G. Knepley @*/
16559371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) {
165641b6fd38SMatthew G. Knepley   PetscFunctionBegin;
165741b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1658dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(cr, 2);
1659cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
166041b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
166141b6fd38SMatthew G. Knepley }
166241b6fd38SMatthew G. Knepley 
166341b6fd38SMatthew G. Knepley /*@
166406792cafSBarry Smith    PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1665f1580f4eSBarry Smith    on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1666710315b6SLawrence Mitchell    pre- and post-smoothing steps.
166706792cafSBarry Smith 
1668f1580f4eSBarry Smith    Logically Collective on pc
166906792cafSBarry Smith 
167006792cafSBarry Smith    Input Parameters:
167106792cafSBarry Smith +  mg - the multigrid context
167206792cafSBarry Smith -  n - the number of smoothing steps
167306792cafSBarry Smith 
167406792cafSBarry Smith    Options Database Key:
1675a2b725a8SWilliam Gropp .  -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
167606792cafSBarry Smith 
167706792cafSBarry Smith    Level: advanced
167806792cafSBarry Smith 
1679f1580f4eSBarry Smith    Note:
1680f1580f4eSBarry 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.
168106792cafSBarry Smith 
1682f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetDistinctSmoothUp()`
168306792cafSBarry Smith @*/
16849371c9d4SSatish Balay PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) {
168506792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
168606792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
168706792cafSBarry Smith   PetscInt       i, levels;
168806792cafSBarry Smith 
168906792cafSBarry Smith   PetscFunctionBegin;
169006792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
169106792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
169228b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
169306792cafSBarry Smith   levels = mglevels[0]->levels;
169406792cafSBarry Smith 
169506792cafSBarry Smith   for (i = 1; i < levels; i++) {
16969566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
16979566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
169806792cafSBarry Smith     mg->default_smoothu = n;
169906792cafSBarry Smith     mg->default_smoothd = n;
170006792cafSBarry Smith   }
170106792cafSBarry Smith   PetscFunctionReturn(0);
170206792cafSBarry Smith }
170306792cafSBarry Smith 
1704f442ab6aSBarry Smith /*@
1705f1580f4eSBarry Smith    PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1706710315b6SLawrence Mitchell        and adds the suffix _up to the options name
1707f442ab6aSBarry Smith 
1708f1580f4eSBarry Smith    Logically Collective on pc
1709f442ab6aSBarry Smith 
1710f1580f4eSBarry Smith    Input Parameter:
1711f442ab6aSBarry Smith .  pc - the preconditioner context
1712f442ab6aSBarry Smith 
1713f442ab6aSBarry Smith    Options Database Key:
1714147403d9SBarry Smith .  -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1715f442ab6aSBarry Smith 
1716f442ab6aSBarry Smith    Level: advanced
1717f442ab6aSBarry Smith 
1718f1580f4eSBarry Smith    Note:
1719f1580f4eSBarry 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.
1720f442ab6aSBarry Smith 
1721f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGSetNumberSmooth()`
1722f442ab6aSBarry Smith @*/
17239371c9d4SSatish Balay PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) {
1724f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1725f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1726f442ab6aSBarry Smith   PetscInt       i, levels;
1727f442ab6aSBarry Smith   KSP            subksp;
1728f442ab6aSBarry Smith 
1729f442ab6aSBarry Smith   PetscFunctionBegin;
1730f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
173128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1732f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1733f442ab6aSBarry Smith 
1734f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1735710315b6SLawrence Mitchell     const char *prefix = NULL;
1736f442ab6aSBarry Smith     /* make sure smoother up and down are different */
17379566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
17389566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
17399566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
17409566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1741f442ab6aSBarry Smith   }
1742f442ab6aSBarry Smith   PetscFunctionReturn(0);
1743f442ab6aSBarry Smith }
1744f442ab6aSBarry Smith 
174507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
17469371c9d4SSatish Balay PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) {
174707a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
174807a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
174907a4832bSFande Kong   Mat           *mat;
175007a4832bSFande Kong   PetscInt       l;
175107a4832bSFande Kong 
175207a4832bSFande Kong   PetscFunctionBegin;
175328b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
17549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
175507a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
175607a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
17579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
175807a4832bSFande Kong   }
175907a4832bSFande Kong   *num_levels     = mg->nlevels;
176007a4832bSFande Kong   *interpolations = mat;
176107a4832bSFande Kong   PetscFunctionReturn(0);
176207a4832bSFande Kong }
176307a4832bSFande Kong 
176407a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
17659371c9d4SSatish Balay PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) {
176607a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
176707a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
176807a4832bSFande Kong   PetscInt       l;
176907a4832bSFande Kong   Mat           *mat;
177007a4832bSFande Kong 
177107a4832bSFande Kong   PetscFunctionBegin;
177228b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
17739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
177407a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
17759566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &(mat[l])));
17769566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
177707a4832bSFande Kong   }
177807a4832bSFande Kong   *num_levels      = mg->nlevels;
177907a4832bSFande Kong   *coarseOperators = mat;
178007a4832bSFande Kong   PetscFunctionReturn(0);
178107a4832bSFande Kong }
178207a4832bSFande Kong 
1783f3b08a26SMatthew G. Knepley /*@C
1784f1580f4eSBarry Smith    PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1785f3b08a26SMatthew G. Knepley 
1786f3b08a26SMatthew G. Knepley    Not collective
1787f3b08a26SMatthew G. Knepley 
1788f3b08a26SMatthew G. Knepley    Input Parameters:
1789f3b08a26SMatthew G. Knepley +  name     - name of the constructor
1790f3b08a26SMatthew G. Knepley -  function - constructor routine
1791f3b08a26SMatthew G. Knepley 
1792f3b08a26SMatthew G. Knepley    Calling sequence for the routine:
17932b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
1794f1580f4eSBarry Smith +  pc        - The PC object
1795f1580f4eSBarry Smith .  l         - The multigrid level, 0 is the coarse level
1796f1580f4eSBarry Smith .  dm        - The DM for this level
1797f1580f4eSBarry Smith .  smooth    - The level smoother
1798f1580f4eSBarry Smith .  Nc        - The size of the coarse space
1799f1580f4eSBarry Smith .  initGuess - Basis for an initial guess for the space
1800f1580f4eSBarry Smith -  coarseSp  - A basis for the computed coarse space
1801f3b08a26SMatthew G. Knepley 
1802f3b08a26SMatthew G. Knepley   Level: advanced
1803f3b08a26SMatthew G. Knepley 
1804f1580f4eSBarry Smith   Developer Note:
1805f1580f4eSBarry Smith   How come this is not used by `PCGAMG`?
1806f1580f4eSBarry Smith 
1807f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1808f3b08a26SMatthew G. Knepley @*/
18099371c9d4SSatish Balay PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) {
1810f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18119566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18129566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
1813f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1814f3b08a26SMatthew G. Knepley }
1815f3b08a26SMatthew G. Knepley 
1816f3b08a26SMatthew G. Knepley /*@C
1817f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1818f3b08a26SMatthew G. Knepley 
1819f3b08a26SMatthew G. Knepley   Not collective
1820f3b08a26SMatthew G. Knepley 
1821f3b08a26SMatthew G. Knepley   Input Parameter:
1822f3b08a26SMatthew G. Knepley . name     - name of the constructor
1823f3b08a26SMatthew G. Knepley 
1824f3b08a26SMatthew G. Knepley   Output Parameter:
1825f3b08a26SMatthew G. Knepley . function - constructor routine
1826f3b08a26SMatthew G. Knepley 
1827f3b08a26SMatthew G. Knepley   Level: advanced
1828f3b08a26SMatthew G. Knepley 
1829f1580f4eSBarry Smith .seealso: `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1830f3b08a26SMatthew G. Knepley @*/
18319371c9d4SSatish Balay PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) {
1832f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18339566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
1834f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1835f3b08a26SMatthew G. Knepley }
1836f3b08a26SMatthew G. Knepley 
18373b09bd56SBarry Smith /*MC
1838ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
18393b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
18403b09bd56SBarry Smith 
18413b09bd56SBarry Smith    Options Database Keys:
18423b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
1843391689abSStefano Zampini .  -pc_mg_cycle_type <v,w> - provide the cycle desired
18448c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
18453b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
1846710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
18472134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
18488cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
18498cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1850e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
18518cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
18528cf6037eSBarry Smith                         to the binary output file called binaryoutput
18533b09bd56SBarry Smith 
185495452b02SPatrick Sanan    Notes:
1855f1580f4eSBarry 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
18563b09bd56SBarry Smith 
18578cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
18588cf6037eSBarry Smith 
1859f1580f4eSBarry Smith        When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
186023067569SBarry Smith        is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
186123067569SBarry Smith        (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
186223067569SBarry Smith        residual is computed at the end of each cycle.
186323067569SBarry Smith 
18643b09bd56SBarry Smith    Level: intermediate
18653b09bd56SBarry Smith 
1866db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1867db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1868db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1869db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1870f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1871f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
18723b09bd56SBarry Smith M*/
18733b09bd56SBarry Smith 
18749371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) {
1875f3fbd535SBarry Smith   PC_MG *mg;
1876f3fbd535SBarry Smith 
18774b9ad928SBarry Smith   PetscFunctionBegin;
1878*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
18793ec1f749SStefano Zampini   pc->data               = mg;
1880f3fbd535SBarry Smith   mg->nlevels            = -1;
188110eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
18822134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1883f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1884f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1885f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1886f3fbd535SBarry Smith 
188737a44384SMark Adams   pc->useAmat = PETSC_TRUE;
188837a44384SMark Adams 
18894b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1890fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
189130b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
18924b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1893a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
18944b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
18954b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
18964b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1897fb15c04eSBarry Smith 
18989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
18999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
19009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
19082b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
19092b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
19104b9ad928SBarry Smith   PetscFunctionReturn(0);
19114b9ad928SBarry Smith }
1912