xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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));
38*48a46eb9SPierre 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     }
83*48a46eb9SPierre 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));
225*48a46eb9SPierre 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++) {
349*48a46eb9SPierre 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));
3609566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectMemory((PetscObject)pc, levels * (sizeof(PC_MG *))));
361f3fbd535SBarry Smith 
3629566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
363f3fbd535SBarry Smith 
364a9db87a2SMatthew G Knepley   mg->stageApply = 0;
365f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
3669566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(pc, &mglevels[i]));
3672fa5cd67SKarl Rupp 
368f3fbd535SBarry Smith     mglevels[i]->level               = i;
369f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
37010eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
371336babb1SJed Brown     mg->default_smoothu              = 2;
372336babb1SJed Brown     mg->default_smoothd              = 2;
37363e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
37463e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
37563e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
37663e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
377f3fbd535SBarry Smith 
378f3fbd535SBarry Smith     if (comms) comm = comms[i];
379d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3809566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3819566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3829566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3839566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3849566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3850ee9a668SBarry Smith       if (i || levels == 1) {
3860ee9a668SBarry Smith         char tprefix[128];
3870ee9a668SBarry Smith 
3889566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
3899566063dSJacob Faibussowitsch         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
3909566063dSJacob Faibussowitsch         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
3919566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
3929566063dSJacob Faibussowitsch         PetscCall(PCSetType(ipc, PCSOR));
3939566063dSJacob Faibussowitsch         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
394f3fbd535SBarry Smith 
3959566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%d_", (int)i));
3969566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
3970ee9a668SBarry Smith       } else {
3989566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
399f3fbd535SBarry Smith 
4009dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4019566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4029566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4039566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
404f3fbd535SBarry Smith         if (size > 1) {
4059566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
406f3fbd535SBarry Smith         } else {
4079566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
408f3fbd535SBarry Smith         }
4099566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
410f3fbd535SBarry Smith       }
4119566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mglevels[i]->smoothd));
412d5a8f7e6SBarry Smith     }
413f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
41431567311SBarry Smith     mg->rtol             = 0.0;
41531567311SBarry Smith     mg->abstol           = 0.0;
41631567311SBarry Smith     mg->dtol             = 0.0;
41731567311SBarry Smith     mg->ttol             = 0.0;
41831567311SBarry Smith     mg->cyclesperpcapply = 1;
419f3fbd535SBarry Smith   }
420f3fbd535SBarry Smith   mg->levels = mglevels;
4219566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4224b9ad928SBarry Smith   PetscFunctionReturn(0);
4234b9ad928SBarry Smith }
4244b9ad928SBarry Smith 
42597d33e41SMatthew G. Knepley /*@C
42697d33e41SMatthew G. Knepley    PCMGSetLevels - Sets the number of levels to use with MG.
42797d33e41SMatthew G. Knepley    Must be called before any other MG routine.
42897d33e41SMatthew G. Knepley 
42997d33e41SMatthew G. Knepley    Logically Collective on PC
43097d33e41SMatthew G. Knepley 
43197d33e41SMatthew G. Knepley    Input Parameters:
43297d33e41SMatthew G. Knepley +  pc - the preconditioner context
43397d33e41SMatthew G. Knepley .  levels - the number of levels
43497d33e41SMatthew G. Knepley -  comms - optional communicators for each level; this is to allow solving the coarser problems
435d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
43605552d4bSJunchao Zhang            you must pass MPI_COMM_NULL. Use comms = NULL to specify that all processes
43705552d4bSJunchao Zhang            should participate in each level of problem.
43897d33e41SMatthew G. Knepley 
43997d33e41SMatthew G. Knepley    Level: intermediate
44097d33e41SMatthew G. Knepley 
44197d33e41SMatthew G. Knepley    Notes:
44297d33e41SMatthew G. Knepley      If the number of levels is one then the multigrid uses the -mg_levels prefix
44397d33e41SMatthew G. Knepley      for setting the level options rather than the -mg_coarse prefix.
44497d33e41SMatthew G. Knepley 
445d5a8f7e6SBarry Smith      You can free the information in comms after this routine is called.
446d5a8f7e6SBarry Smith 
447d5a8f7e6SBarry Smith      The array of MPI communicators must contain MPI_COMM_NULL for those ranks that at each level
448d5a8f7e6SBarry Smith      are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
449d5a8f7e6SBarry Smith      the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
450d5a8f7e6SBarry Smith      of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
451d5a8f7e6SBarry Smith      the first of size 2 and the second of value MPI_COMM_NULL since the rank 1 does not participate
452d5a8f7e6SBarry Smith      in the coarse grid solve.
453d5a8f7e6SBarry Smith 
454d5a8f7e6SBarry Smith      Since each coarser level may have a new MPI_Comm with fewer ranks than the previous, one
455d5a8f7e6SBarry Smith      must take special care in providing the restriction and interpolation operation. We recommend
456d5a8f7e6SBarry Smith      providing these as two step operations; first perform a standard restriction or interpolation on
457d5a8f7e6SBarry Smith      the full number of ranks for that level and then use an MPI call to copy the resulting vector
45805552d4bSJunchao Zhang      array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
459d5a8f7e6SBarry Smith      cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
460d5a8f7e6SBarry Smith      recieves or MPI_AlltoAllv() could be used to do the reshuffling of the vector entries.
461d5a8f7e6SBarry Smith 
46205552d4bSJunchao Zhang    Fortran Notes:
46305552d4bSJunchao Zhang      Use comms = PETSC_NULL_MPI_COMM as the equivalent of NULL in the C interface. Note PETSC_NULL_MPI_COMM
46405552d4bSJunchao Zhang      is not MPI_COMM_NULL. It is more like PETSC_NULL_INTEGER, PETSC_NULL_REAL etc.
465d5a8f7e6SBarry Smith 
466db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()`
46797d33e41SMatthew G. Knepley @*/
4689371c9d4SSatish Balay PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms) {
46997d33e41SMatthew G. Knepley   PetscFunctionBegin;
47097d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
47197d33e41SMatthew G. Knepley   if (comms) PetscValidPointer(comms, 3);
472cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
47397d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
47497d33e41SMatthew G. Knepley }
47597d33e41SMatthew G. Knepley 
4769371c9d4SSatish Balay PetscErrorCode PCDestroy_MG(PC pc) {
477a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
478a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
479a06653b4SBarry Smith   PetscInt       i, n;
480c07bf074SBarry Smith 
481c07bf074SBarry Smith   PetscFunctionBegin;
4829566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
483a06653b4SBarry Smith   if (mglevels) {
484a06653b4SBarry Smith     n = mglevels[0]->levels;
485a06653b4SBarry Smith     for (i = 0; i < n; i++) {
486*48a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
4879566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
4889566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
4899566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
490a06653b4SBarry Smith     }
4919566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
492a06653b4SBarry Smith   }
4939566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
4949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
4959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
4962b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
4972b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
4982b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
4992b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5002b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5012b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5022b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5032b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5042b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5052b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5062b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
507f3fbd535SBarry Smith   PetscFunctionReturn(0);
508f3fbd535SBarry Smith }
509f3fbd535SBarry Smith 
510f3fbd535SBarry Smith /*
511f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
512f3fbd535SBarry Smith              or full cycle of multigrid.
513f3fbd535SBarry Smith 
514f3fbd535SBarry Smith   Note:
515f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
516f3fbd535SBarry Smith */
5179371c9d4SSatish Balay static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose) {
518f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
519f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
520391689abSStefano Zampini   PC             tpc;
521f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
52230b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
523f3fbd535SBarry Smith 
524f3fbd535SBarry Smith   PetscFunctionBegin;
52530b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5269566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
527e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
528298cc208SBarry Smith   for (i = 0; i < levels; i++) {
529e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5309566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5319566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
532e1d8e5deSBarry Smith     }
533e1d8e5deSBarry Smith   }
534e1d8e5deSBarry Smith 
5359566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5369566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5379566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5389566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
539391689abSStefano Zampini   if (!changeu && !changed) {
54030b0564aSStefano Zampini     if (matapp) {
5419566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
54230b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
54330b0564aSStefano Zampini     } else {
5449566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
545f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
54630b0564aSStefano Zampini     }
547391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
54830b0564aSStefano Zampini     if (matapp) {
54930b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
55030b0564aSStefano Zampini         PetscInt  N1, N2;
55130b0564aSStefano Zampini         PetscBool flg;
55230b0564aSStefano Zampini 
5539566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5549566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5559566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
556*48a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
55730b0564aSStefano Zampini       }
55830b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5599566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
56030b0564aSStefano Zampini       } else {
5619566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
56230b0564aSStefano Zampini       }
56330b0564aSStefano Zampini     } else {
564391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
565391689abSStefano Zampini         Vec *vec;
566391689abSStefano Zampini 
5679566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
568391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5699566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
570391689abSStefano Zampini       }
5719566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
572391689abSStefano Zampini     }
57330b0564aSStefano Zampini   }
5749371c9d4SSatish Balay   if (matapp) {
5759371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
5769371c9d4SSatish Balay   } else {
5779371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
5789371c9d4SSatish Balay   }
57930b0564aSStefano Zampini 
58030b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
58130b0564aSStefano Zampini      Reset operators if sizes/type do no match */
58230b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
58330b0564aSStefano Zampini     PetscInt  Xc, Bc;
58430b0564aSStefano Zampini     PetscBool flg;
58530b0564aSStefano Zampini 
5869566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
5879566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
5889566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
58930b0564aSStefano Zampini     if (Xc != Bc || !flg) {
5909566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
59130b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
5929566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
5939566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
5949566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
59530b0564aSStefano Zampini       }
59630b0564aSStefano Zampini     }
59730b0564aSStefano Zampini   }
598391689abSStefano Zampini 
59931567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6009566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6019566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
602*48a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6032fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6049566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6052fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6069566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6072fa5cd67SKarl Rupp   } else {
6089566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
609f3fbd535SBarry Smith   }
6109566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
61130b0564aSStefano Zampini   if (!changeu && !changed) {
6129371c9d4SSatish Balay     if (matapp) {
6139371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6149371c9d4SSatish Balay     } else {
6159371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6169371c9d4SSatish Balay     }
61730b0564aSStefano Zampini   }
618f3fbd535SBarry Smith   PetscFunctionReturn(0);
619f3fbd535SBarry Smith }
620f3fbd535SBarry Smith 
6219371c9d4SSatish Balay static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x) {
622fcb023d4SJed Brown   PetscFunctionBegin;
6239566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
624fcb023d4SJed Brown   PetscFunctionReturn(0);
625fcb023d4SJed Brown }
626fcb023d4SJed Brown 
6279371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x) {
628fcb023d4SJed Brown   PetscFunctionBegin;
6299566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
63030b0564aSStefano Zampini   PetscFunctionReturn(0);
63130b0564aSStefano Zampini }
63230b0564aSStefano Zampini 
6339371c9d4SSatish Balay static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x) {
63430b0564aSStefano Zampini   PetscFunctionBegin;
6359566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
636fcb023d4SJed Brown   PetscFunctionReturn(0);
637fcb023d4SJed Brown }
638f3fbd535SBarry Smith 
6399371c9d4SSatish Balay PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject) {
640710315b6SLawrence Mitchell   PetscInt            levels, cycles;
641f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
642f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6433d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
644f3fbd535SBarry Smith   PCMGType            mgtype;
645f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6462134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6472b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
648f3fbd535SBarry Smith 
649f3fbd535SBarry Smith   PetscFunctionBegin;
6501d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
651d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6531a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6549566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
655eb3f98d2SBarry Smith     levels++;
6563aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
657eb3f98d2SBarry Smith   }
6589566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6593aeaf226SBarry Smith   mglevels = mg->levels;
6603aeaf226SBarry Smith 
661f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
6629566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
6631baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
6642134b1e4SBarry Smith   gtype = mg->galerkin;
6659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)gtype, (PetscEnum *)&gtype, &flg));
6661baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
6672b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6682b3cbbdaSStefano 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));
6692b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
6709566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
6719566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
67241b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
6739566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
6749566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
675f56b1265SBarry Smith   flg = PETSC_FALSE;
6769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
6771baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
67831567311SBarry Smith   mgtype = mg->am;
6799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
6801baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
68131567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6829566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
6831baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
684f3fbd535SBarry Smith   }
685f3fbd535SBarry Smith   flg = PETSC_FALSE;
6869566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
687f3fbd535SBarry Smith   if (flg) {
688f3fbd535SBarry Smith     PetscInt i;
689f3fbd535SBarry Smith     char     eventname[128];
6901a97d7b6SStefano Zampini 
691f3fbd535SBarry Smith     levels = mglevels[0]->levels;
692f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
693f3fbd535SBarry Smith       sprintf(eventname, "MGSetup Level %d", (int)i);
6949566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
695f3fbd535SBarry Smith       sprintf(eventname, "MGSmooth Level %d", (int)i);
6969566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
697f3fbd535SBarry Smith       if (i) {
698f3fbd535SBarry Smith         sprintf(eventname, "MGResid Level %d", (int)i);
6999566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
700f3fbd535SBarry Smith         sprintf(eventname, "MGInterp Level %d", (int)i);
7019566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
702f3fbd535SBarry Smith       }
703f3fbd535SBarry Smith     }
704eec35531SMatthew G Knepley 
705ec60ca73SSatish Balay #if defined(PETSC_USE_LOG)
706eec35531SMatthew G Knepley     {
707eec35531SMatthew G Knepley       const char   *sname = "MG Apply";
708eec35531SMatthew G Knepley       PetscStageLog stageLog;
709eec35531SMatthew G Knepley       PetscInt      st;
710eec35531SMatthew G Knepley 
7119566063dSJacob Faibussowitsch       PetscCall(PetscLogGetStageLog(&stageLog));
712eec35531SMatthew G Knepley       for (st = 0; st < stageLog->numStages; ++st) {
713eec35531SMatthew G Knepley         PetscBool same;
714eec35531SMatthew G Knepley 
7159566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(stageLog->stageInfo[st].name, sname, &same));
7162fa5cd67SKarl Rupp         if (same) mg->stageApply = st;
717eec35531SMatthew G Knepley       }
718*48a46eb9SPierre Jolivet       if (!mg->stageApply) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
719eec35531SMatthew G Knepley     }
720ec60ca73SSatish Balay #endif
721f3fbd535SBarry Smith   }
722d0609cedSBarry Smith   PetscOptionsHeadEnd();
723f3b08a26SMatthew G. Knepley   /* Check option consistency */
7249566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7259566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
72608401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
727f3fbd535SBarry Smith   PetscFunctionReturn(0);
728f3fbd535SBarry Smith }
729f3fbd535SBarry Smith 
7300a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7310a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7320a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7332b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
734f3fbd535SBarry Smith 
7359804daf3SBarry Smith #include <petscdraw.h>
7369371c9d4SSatish Balay PetscErrorCode PCView_MG(PC pc, PetscViewer viewer) {
737f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
738f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
739e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
740219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
741f3fbd535SBarry Smith 
742f3fbd535SBarry Smith   PetscFunctionBegin;
7439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7459566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
746f3fbd535SBarry Smith   if (iascii) {
747e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
74863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
749*48a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7502134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7519566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7522134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7539566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7542134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7559566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7562134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7584f66f45eSBarry Smith     } else {
7599566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
760f3fbd535SBarry Smith     }
7611baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
762f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
76363a3b9bcSJacob Faibussowitsch       if (i) {
76463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
765f3fbd535SBarry Smith       } else {
76663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
767f3fbd535SBarry Smith       }
7689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7699566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7709566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
771f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
7729566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
773f3fbd535SBarry Smith       } else if (i) {
77463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
7759566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7769566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7779566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
778f3fbd535SBarry Smith       }
77941b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
78063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
7819566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7829566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
7839566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
78441b6fd38SMatthew G. Knepley       }
785f3fbd535SBarry Smith     }
7865b0b0462SBarry Smith   } else if (isbinary) {
7875b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
7889566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
789*48a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7905b0b0462SBarry Smith     }
791219b1045SBarry Smith   } else if (isdraw) {
792219b1045SBarry Smith     PetscDraw draw;
793b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
7949566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
7959566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
7969566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
797219b1045SBarry Smith     bottom = y - th;
798219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
799b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8009566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8019566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8029566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
803b4375e8dSPeter Brune       } else {
804b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8059566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8069566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8079566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8089566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8099566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8109566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
811b4375e8dSPeter Brune       }
8129566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8131cd381d6SBarry Smith       bottom -= th;
814219b1045SBarry Smith     }
8155b0b0462SBarry Smith   }
816f3fbd535SBarry Smith   PetscFunctionReturn(0);
817f3fbd535SBarry Smith }
818f3fbd535SBarry Smith 
819af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
820cab2e9ccSBarry Smith 
821f3fbd535SBarry Smith /*
822f3fbd535SBarry Smith     Calls setup for the KSP on each level
823f3fbd535SBarry Smith */
8249371c9d4SSatish Balay PetscErrorCode PCSetUp_MG(PC pc) {
825f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
826f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8271a97d7b6SStefano Zampini   PetscInt       i, n;
82898e04984SBarry Smith   PC             cpc;
8293db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
830f3fbd535SBarry Smith   Mat            dA, dB;
831f3fbd535SBarry Smith   Vec            tvec;
832218a07d4SBarry Smith   DM            *dms;
8330a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
83441b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8352b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
836f3fbd535SBarry Smith 
837f3fbd535SBarry Smith   PetscFunctionBegin;
83828b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8391a97d7b6SStefano Zampini   n = mglevels[0]->levels;
84001bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8413aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8423aeaf226SBarry Smith     PetscInt levels;
8439566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8443aeaf226SBarry Smith     levels++;
8453aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8469566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8473aeaf226SBarry Smith       n = levels;
8489566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8493aeaf226SBarry Smith       mglevels = mg->levels;
8503aeaf226SBarry Smith     }
8513aeaf226SBarry Smith   }
8529566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc));
8533aeaf226SBarry Smith 
854f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
855f3fbd535SBarry Smith   /* so use those from global PC */
856f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8579566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
85898e04984SBarry Smith   if (opsset) {
85998e04984SBarry Smith     Mat mmat;
8609566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
86198e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
86298e04984SBarry Smith   }
8634a5f07a5SMark F. Adams 
86441b6fd38SMatthew G. Knepley   /* Create CR solvers */
8659566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
86641b6fd38SMatthew G. Knepley   if (doCR) {
86741b6fd38SMatthew G. Knepley     const char *prefix;
86841b6fd38SMatthew G. Knepley 
8699566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
87041b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
87141b6fd38SMatthew G. Knepley       PC   ipc, cr;
87241b6fd38SMatthew G. Knepley       char crprefix[128];
87341b6fd38SMatthew G. Knepley 
8749566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
8759566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
8769566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
8779566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
8789566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
8799566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
8809566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
8819566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
8829566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
88341b6fd38SMatthew G. Knepley 
8849566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
8859566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
8869566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
8879566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
8889566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
8899566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
89041b6fd38SMatthew G. Knepley 
8919566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
8929566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
8939566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int)i));
8949566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
8959566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)mglevels[i]->cr));
89641b6fd38SMatthew G. Knepley     }
89741b6fd38SMatthew G. Knepley   }
89841b6fd38SMatthew G. Knepley 
8994a5f07a5SMark F. Adams   if (!opsset) {
9009566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9014a5f07a5SMark F. Adams     if (use_amat) {
9029566063dSJacob 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"));
9039566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
90469858f1bSStefano Zampini     } else {
9059566063dSJacob 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"));
9069566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9074a5f07a5SMark F. Adams     }
9084a5f07a5SMark F. Adams   }
909f3fbd535SBarry Smith 
9109c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9119c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9129c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9132b3cbbdaSStefano Zampini       break;
9149c7ffb39SBarry Smith     }
9159c7ffb39SBarry Smith   }
9162134b1e4SBarry Smith 
9179566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9182134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9192b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9202134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9212134b1e4SBarry Smith   }
9222134b1e4SBarry Smith 
9232b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9242b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9252b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9262b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9272b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9282b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9292b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9302b3cbbdaSStefano Zampini     }
9312b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9322b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9332b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9342b3cbbdaSStefano Zampini     }
9352b3cbbdaSStefano Zampini   }
9362b3cbbdaSStefano Zampini 
9379c7ffb39SBarry Smith   /*
9389c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9392b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9409c7ffb39SBarry Smith   */
94132fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
94232fe681dSStefano Zampini     /* first see if we can compute a coarse space */
94332fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
94432fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
94532fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
94632fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
94732fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
94832fe681dSStefano Zampini         }
94932fe681dSStefano Zampini       }
95032fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9512e499ae9SBarry Smith       Mat p;
95273250ac0SBarry Smith       Vec rscale;
9539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
954218a07d4SBarry Smith       dms[n - 1] = pc->dm;
955ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9569566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
957218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
958942e3340SBarry Smith         DMKSP     kdm;
959eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9609566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9619566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
962c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9639566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9649566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
965c27ee7a3SPatrick Farrell         }
96641b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9679566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
9689566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
96941b6fd38SMatthew G. Knepley         }
9709566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
971d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
972d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
9730298fd71SBarry Smith         kdm->ops->computerhs = NULL;
9740298fd71SBarry Smith         kdm->rhsctx          = NULL;
97524c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
9769566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
9779566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
9789566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
9799566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
9809566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
981218a07d4SBarry Smith         }
9829566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
9833ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
9849566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
9859566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
9869566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
9873ad4599aSBarry Smith         }
9889566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
989eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
9909566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
9919566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
9929566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
993eab52d2bSLawrence Mitchell         }
99424c3aa18SBarry Smith       }
9952d2b81a6SBarry Smith 
9969566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
9979566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
998ce4cda84SJed Brown     }
99932fe681dSStefano Zampini   }
1000cab2e9ccSBarry Smith 
10012134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10022134b1e4SBarry Smith     Mat       A, B;
10032134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10042134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10052134b1e4SBarry Smith 
10062b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10072b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10082134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1009f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10107827d75bSBarry 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");
1011*48a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
1012*48a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
1013*48a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
1014*48a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
1015*48a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10162134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10172134b1e4SBarry Smith       if (!doA && dAeqdB) {
10189566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10192134b1e4SBarry Smith         A = B;
10202134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10219566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10229566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1023b9367914SBarry Smith       }
10242134b1e4SBarry Smith       if (!doB && dAeqdB) {
10259566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10262134b1e4SBarry Smith         B = A;
10272134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10289566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10299566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10307d537d92SJed Brown       }
10312134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10329566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10339566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10349566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10352134b1e4SBarry Smith       }
10362134b1e4SBarry Smith       dA = A;
1037f3fbd535SBarry Smith       dB = B;
1038f3fbd535SBarry Smith     }
1039f3fbd535SBarry Smith   }
1040f3b08a26SMatthew G. Knepley 
1041f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10422b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1043f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
1044*48a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10452b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1046f3b08a26SMatthew G. Knepley     }
1047*48a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1048f3b08a26SMatthew G. Knepley   }
1049f3b08a26SMatthew G. Knepley 
10502134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1051caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1052ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1053caa4e7f2SJed Brown       Mat Restrict, Inject;
1054caa4e7f2SJed Brown       Vec rscale;
10559566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10569566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10579566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10589566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10599566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10609566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1061caa4e7f2SJed Brown     }
1062caa4e7f2SJed Brown   }
1063f3fbd535SBarry Smith 
1064f3fbd535SBarry Smith   if (!pc->setupcalled) {
1065*48a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1066f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
1067*48a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
1068*48a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1069f3fbd535SBarry Smith     }
10703ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
1071f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
10729566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
10739566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1074f3fbd535SBarry Smith     }
1075f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1076f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1077f3fbd535SBarry Smith         Vec *vec;
10789566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
10799566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
10809566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
10819566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1082f3fbd535SBarry Smith       }
1083f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
10849566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10859566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
10869566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1087f3fbd535SBarry Smith       }
1088f3fbd535SBarry Smith       if (!mglevels[i]->x) {
10899566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
10909566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
10919566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1092f3fbd535SBarry Smith       }
109341b6fd38SMatthew G. Knepley       if (doCR) {
10949566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
10959566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
10969566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
109741b6fd38SMatthew G. Knepley       }
1098f3fbd535SBarry Smith     }
1099f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1100f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1101f3fbd535SBarry Smith       Vec *vec;
11029566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11039566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11049566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11059566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1106f3fbd535SBarry Smith     }
110741b6fd38SMatthew G. Knepley     if (doCR) {
11089566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11099566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11109566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
111141b6fd38SMatthew G. Knepley     }
1112f3fbd535SBarry Smith   }
1113f3fbd535SBarry Smith 
111498e04984SBarry Smith   if (pc->dm) {
111598e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
111698e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
111798e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
111898e04984SBarry Smith     }
111998e04984SBarry Smith   }
112008549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
112108549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
112208549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1123f3fbd535SBarry Smith 
1124f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11252a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1126f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11279566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1128f3fbd535SBarry Smith     }
11299566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11309566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11319566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
11329371c9d4SSatish Balay     if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
11339566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1134d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1135d42688cbSBarry Smith       Mat mat;
11369566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11379566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1138d42688cbSBarry Smith     }
1139fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1140fcb023d4SJed Brown       Mat mat;
11419566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11429566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1143fcb023d4SJed Brown     }
1144f3fbd535SBarry Smith   }
1145f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1146f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1147f3fbd535SBarry Smith       Mat downmat, downpmat;
1148f3fbd535SBarry Smith 
1149f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11509566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1151f3fbd535SBarry Smith       if (!opsset) {
11529566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11539566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1154f3fbd535SBarry Smith       }
1155f3fbd535SBarry Smith 
11569566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11579566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11589566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
11599371c9d4SSatish Balay       if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
11609566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1161f3fbd535SBarry Smith     }
116241b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
116341b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
116441b6fd38SMatthew G. Knepley 
116541b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
11669566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
116741b6fd38SMatthew G. Knepley       if (!opsset) {
11689566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11699566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
117041b6fd38SMatthew G. Knepley       }
117141b6fd38SMatthew G. Knepley 
11729566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11739566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11749566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
11759371c9d4SSatish Balay       if (mglevels[i]->cr->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
11769566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
117741b6fd38SMatthew G. Knepley     }
1178f3fbd535SBarry Smith   }
1179f3fbd535SBarry Smith 
11809566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
11819566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
11829371c9d4SSatish Balay   if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) { pc->failedreason = PC_SUBPC_ERROR; }
11839566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1184f3fbd535SBarry Smith 
1185f3fbd535SBarry Smith     /*
1186f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1187e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1188f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1189f3fbd535SBarry Smith 
1190f3fbd535SBarry Smith    Only support one or the other at the same time.
1191f3fbd535SBarry Smith   */
1192f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
11939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1194ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1195f3fbd535SBarry Smith   dump = PETSC_FALSE;
1196f3fbd535SBarry Smith #endif
11979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1198ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1199f3fbd535SBarry Smith 
1200f3fbd535SBarry Smith   if (viewer) {
1201*48a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1202f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12039566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12049566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1205f3fbd535SBarry Smith     }
1206f3fbd535SBarry Smith   }
1207f3fbd535SBarry Smith   PetscFunctionReturn(0);
1208f3fbd535SBarry Smith }
1209f3fbd535SBarry Smith 
1210f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
1211f3fbd535SBarry Smith 
12129371c9d4SSatish Balay PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels) {
121397d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
121497d33e41SMatthew G. Knepley 
121597d33e41SMatthew G. Knepley   PetscFunctionBegin;
121697d33e41SMatthew G. Knepley   *levels = mg->nlevels;
121797d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
121897d33e41SMatthew G. Knepley }
121997d33e41SMatthew G. Knepley 
12204b9ad928SBarry Smith /*@
122197177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
12224b9ad928SBarry Smith 
12234b9ad928SBarry Smith    Not Collective
12244b9ad928SBarry Smith 
12254b9ad928SBarry Smith    Input Parameter:
12264b9ad928SBarry Smith .  pc - the preconditioner context
12274b9ad928SBarry Smith 
12284b9ad928SBarry Smith    Output parameter:
12294b9ad928SBarry Smith .  levels - the number of levels
12304b9ad928SBarry Smith 
12314b9ad928SBarry Smith    Level: advanced
12324b9ad928SBarry Smith 
1233db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
12344b9ad928SBarry Smith @*/
12359371c9d4SSatish Balay PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels) {
12364b9ad928SBarry Smith   PetscFunctionBegin;
12370700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12384482741eSBarry Smith   PetscValidIntPointer(levels, 2);
123997d33e41SMatthew G. Knepley   *levels = 0;
1240cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12414b9ad928SBarry Smith   PetscFunctionReturn(0);
12424b9ad928SBarry Smith }
12434b9ad928SBarry Smith 
12444b9ad928SBarry Smith /*@
1245e7d4b4cbSMark Adams    PCMGGetGridComplexity - compute operator and grid complexity of MG hierarchy
1246e7d4b4cbSMark Adams 
1247e7d4b4cbSMark Adams    Input Parameter:
1248e7d4b4cbSMark Adams .  pc - the preconditioner context
1249e7d4b4cbSMark Adams 
125090db8557SMark Adams    Output Parameters:
125190db8557SMark Adams +  gc - grid complexity = sum_i(n_i) / n_0
125290db8557SMark Adams -  oc - operator complexity = sum_i(nnz_i) / nnz_0
1253e7d4b4cbSMark Adams 
1254e7d4b4cbSMark Adams    Level: advanced
1255e7d4b4cbSMark Adams 
1256db781477SPatrick Sanan .seealso: `PCMGGetLevels()`
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 
1297ad4df100SBarry Smith    Logically Collective on PC
12984b9ad928SBarry Smith 
12994b9ad928SBarry Smith    Input Parameters:
13004b9ad928SBarry Smith +  pc - the preconditioner context
13019dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
13029dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
13034b9ad928SBarry Smith 
13044b9ad928SBarry Smith    Options Database Key:
13054b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
13064b9ad928SBarry Smith    additive, full, kaskade
13074b9ad928SBarry Smith 
13084b9ad928SBarry Smith    Level: advanced
13094b9ad928SBarry Smith 
1310db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
13114b9ad928SBarry Smith @*/
13129371c9d4SSatish Balay PetscErrorCode PCMGSetType(PC pc, PCMGType form) {
1313f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13144b9ad928SBarry Smith 
13154b9ad928SBarry Smith   PetscFunctionBegin;
13160700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1317c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
131831567311SBarry Smith   mg->am = form;
13199dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1320c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
1321c60c7ad4SBarry Smith   PetscFunctionReturn(0);
1322c60c7ad4SBarry Smith }
1323c60c7ad4SBarry Smith 
1324c60c7ad4SBarry Smith /*@
1325c60c7ad4SBarry Smith    PCMGGetType - Determines the form of multigrid to use:
1326c60c7ad4SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
1327c60c7ad4SBarry Smith 
1328c60c7ad4SBarry Smith    Logically Collective on PC
1329c60c7ad4SBarry Smith 
1330c60c7ad4SBarry Smith    Input Parameter:
1331c60c7ad4SBarry Smith .  pc - the preconditioner context
1332c60c7ad4SBarry Smith 
1333c60c7ad4SBarry Smith    Output Parameter:
1334c60c7ad4SBarry Smith .  type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE
1335c60c7ad4SBarry Smith 
1336c60c7ad4SBarry Smith    Level: advanced
1337c60c7ad4SBarry Smith 
1338db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
1339c60c7ad4SBarry Smith @*/
13409371c9d4SSatish Balay PetscErrorCode PCMGGetType(PC pc, PCMGType *type) {
1341c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1342c60c7ad4SBarry Smith 
1343c60c7ad4SBarry Smith   PetscFunctionBegin;
1344c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1345c60c7ad4SBarry Smith   *type = mg->am;
13464b9ad928SBarry Smith   PetscFunctionReturn(0);
13474b9ad928SBarry Smith }
13484b9ad928SBarry Smith 
13494b9ad928SBarry Smith /*@
13500d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
13514b9ad928SBarry Smith    complicated cycling.
13524b9ad928SBarry Smith 
1353ad4df100SBarry Smith    Logically Collective on PC
13544b9ad928SBarry Smith 
13554b9ad928SBarry Smith    Input Parameters:
1356c2be2410SBarry Smith +  pc - the multigrid context
1357c1cbb1deSBarry Smith -  n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W
13584b9ad928SBarry Smith 
13594b9ad928SBarry Smith    Options Database Key:
1360c1cbb1deSBarry Smith .  -pc_mg_cycle_type <v,w> - provide the cycle desired
13614b9ad928SBarry Smith 
13624b9ad928SBarry Smith    Level: advanced
13634b9ad928SBarry Smith 
1364db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()`
13654b9ad928SBarry Smith @*/
13669371c9d4SSatish Balay PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n) {
1367f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1368f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
136979416396SBarry Smith   PetscInt       i, levels;
13704b9ad928SBarry Smith 
13714b9ad928SBarry Smith   PetscFunctionBegin;
13720700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
137369fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
137428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1375f3fbd535SBarry Smith   levels = mglevels[0]->levels;
13762fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
13774b9ad928SBarry Smith   PetscFunctionReturn(0);
13784b9ad928SBarry Smith }
13794b9ad928SBarry Smith 
13808cc2d5dfSBarry Smith /*@
13818cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
13828cc2d5dfSBarry Smith          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
13838cc2d5dfSBarry Smith 
1384ad4df100SBarry Smith    Logically Collective on PC
13858cc2d5dfSBarry Smith 
13868cc2d5dfSBarry Smith    Input Parameters:
13878cc2d5dfSBarry Smith +  pc - the multigrid context
13888cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
13898cc2d5dfSBarry Smith 
13908cc2d5dfSBarry Smith    Options Database Key:
1391147403d9SBarry Smith .  -pc_mg_multiplicative_cycles n - set the number of cycles
13928cc2d5dfSBarry Smith 
13938cc2d5dfSBarry Smith    Level: advanced
13948cc2d5dfSBarry Smith 
139595452b02SPatrick Sanan    Notes:
139695452b02SPatrick Sanan     This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
13978cc2d5dfSBarry Smith 
1398db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`
13998cc2d5dfSBarry Smith @*/
14009371c9d4SSatish Balay PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n) {
1401f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14028cc2d5dfSBarry Smith 
14038cc2d5dfSBarry Smith   PetscFunctionBegin;
14040700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1405c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14062a21e185SBarry Smith   mg->cyclesperpcapply = n;
14078cc2d5dfSBarry Smith   PetscFunctionReturn(0);
14088cc2d5dfSBarry Smith }
14098cc2d5dfSBarry Smith 
14109371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use) {
1411fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1412fb15c04eSBarry Smith 
1413fb15c04eSBarry Smith   PetscFunctionBegin;
14142134b1e4SBarry Smith   mg->galerkin = use;
1415fb15c04eSBarry Smith   PetscFunctionReturn(0);
1416fb15c04eSBarry Smith }
1417fb15c04eSBarry Smith 
1418c2be2410SBarry Smith /*@
141997177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
142082b87d87SMatthew G. Knepley       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1421c2be2410SBarry Smith 
1422ad4df100SBarry Smith    Logically Collective on PC
1423c2be2410SBarry Smith 
1424c2be2410SBarry Smith    Input Parameters:
1425c91913d3SJed Brown +  pc - the multigrid context
14262134b1e4SBarry Smith -  use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE
1427c2be2410SBarry Smith 
1428c2be2410SBarry Smith    Options Database Key:
1429147403d9SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1430c2be2410SBarry Smith 
1431c2be2410SBarry Smith    Level: intermediate
1432c2be2410SBarry Smith 
143395452b02SPatrick Sanan    Notes:
143495452b02SPatrick Sanan     Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not
14351c1aac46SBarry Smith      use the PCMG construction of the coarser grids.
14361c1aac46SBarry Smith 
1437db781477SPatrick Sanan .seealso: `PCMGGetGalerkin()`, `PCMGGalerkinType`
14383fc8bf9cSBarry Smith 
1439c2be2410SBarry Smith @*/
14409371c9d4SSatish Balay PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use) {
1441c2be2410SBarry Smith   PetscFunctionBegin;
14420700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1443cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
1444c2be2410SBarry Smith   PetscFunctionReturn(0);
1445c2be2410SBarry Smith }
1446c2be2410SBarry Smith 
14473fc8bf9cSBarry Smith /*@
14483fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
144982b87d87SMatthew G. Knepley       A_i-1 = r_i * A_i * p_i
14503fc8bf9cSBarry Smith 
14513fc8bf9cSBarry Smith    Not Collective
14523fc8bf9cSBarry Smith 
14533fc8bf9cSBarry Smith    Input Parameter:
14543fc8bf9cSBarry Smith .  pc - the multigrid context
14553fc8bf9cSBarry Smith 
14563fc8bf9cSBarry Smith    Output Parameter:
14572134b1e4SBarry 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
14583fc8bf9cSBarry Smith 
14593fc8bf9cSBarry Smith    Level: intermediate
14603fc8bf9cSBarry Smith 
1461db781477SPatrick Sanan .seealso: `PCMGSetGalerkin()`, `PCMGGalerkinType`
14623fc8bf9cSBarry Smith 
14633fc8bf9cSBarry Smith @*/
14649371c9d4SSatish Balay PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin) {
1465f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14663fc8bf9cSBarry Smith 
14673fc8bf9cSBarry Smith   PetscFunctionBegin;
14680700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14692134b1e4SBarry Smith   *galerkin = mg->galerkin;
14703fc8bf9cSBarry Smith   PetscFunctionReturn(0);
14713fc8bf9cSBarry Smith }
14723fc8bf9cSBarry Smith 
14739371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt) {
1474f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1475f3b08a26SMatthew G. Knepley 
1476f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1477f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
1478f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1479f3b08a26SMatthew G. Knepley }
1480f3b08a26SMatthew G. Knepley 
14819371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt) {
1482f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1483f3b08a26SMatthew G. Knepley 
1484f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1485f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
1486f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1487f3b08a26SMatthew G. Knepley }
1488f3b08a26SMatthew G. Knepley 
14899371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype) {
14902b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
14912b3cbbdaSStefano Zampini 
14922b3cbbdaSStefano Zampini   PetscFunctionBegin;
14932b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
14942b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
14952b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
14962b3cbbdaSStefano Zampini }
14972b3cbbdaSStefano Zampini 
14989371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype) {
14992b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15002b3cbbdaSStefano Zampini 
15012b3cbbdaSStefano Zampini   PetscFunctionBegin;
15022b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15032b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15042b3cbbdaSStefano Zampini }
15052b3cbbdaSStefano Zampini 
15069371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr) {
150741b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
150841b6fd38SMatthew G. Knepley 
150941b6fd38SMatthew G. Knepley   PetscFunctionBegin;
151041b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
151141b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
151241b6fd38SMatthew G. Knepley }
151341b6fd38SMatthew G. Knepley 
15149371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr) {
151541b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
151641b6fd38SMatthew G. Knepley 
151741b6fd38SMatthew G. Knepley   PetscFunctionBegin;
151841b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
151941b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
152041b6fd38SMatthew G. Knepley }
152141b6fd38SMatthew G. Knepley 
15222b3cbbdaSStefano Zampini /*@C
15232b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15242b3cbbdaSStefano Zampini 
15252b3cbbdaSStefano 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.
15262b3cbbdaSStefano Zampini 
15272b3cbbdaSStefano Zampini   Logically Collective on PC
15282b3cbbdaSStefano Zampini 
15292b3cbbdaSStefano Zampini   Input Parameters:
15302b3cbbdaSStefano Zampini + pc    - the multigrid context
15312b3cbbdaSStefano Zampini - ctype - the type of coarse space
15322b3cbbdaSStefano Zampini 
15332b3cbbdaSStefano Zampini   Options Database Keys:
15342b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
15352b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw
15362b3cbbdaSStefano Zampini 
15372b3cbbdaSStefano Zampini   Level: intermediate
15382b3cbbdaSStefano Zampini 
15392b3cbbdaSStefano Zampini .keywords: MG, set, Galerkin
15402b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`
15412b3cbbdaSStefano Zampini @*/
15429371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype) {
15432b3cbbdaSStefano Zampini   PetscFunctionBegin;
15442b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15452b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
15462b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
15472b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15482b3cbbdaSStefano Zampini }
15492b3cbbdaSStefano Zampini 
15502b3cbbdaSStefano Zampini /*@C
15512b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
15522b3cbbdaSStefano Zampini 
15532b3cbbdaSStefano Zampini   Not Collective
15542b3cbbdaSStefano Zampini 
15552b3cbbdaSStefano Zampini   Input Parameter:
15562b3cbbdaSStefano Zampini . pc    - the multigrid context
15572b3cbbdaSStefano Zampini 
15582b3cbbdaSStefano Zampini   Output Parameter:
15592b3cbbdaSStefano Zampini . ctype - the type of coarse space
15602b3cbbdaSStefano Zampini 
15612b3cbbdaSStefano Zampini   Level: intermediate
15622b3cbbdaSStefano Zampini 
15632b3cbbdaSStefano Zampini .keywords: MG, Get, Galerkin
15642b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`
15652b3cbbdaSStefano Zampini @*/
15669371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype) {
15672b3cbbdaSStefano Zampini   PetscFunctionBegin;
15682b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15692b3cbbdaSStefano Zampini   PetscValidPointer(ctype, 2);
15702b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
15712b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15722b3cbbdaSStefano Zampini }
15732b3cbbdaSStefano Zampini 
15742b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1575f3b08a26SMatthew G. Knepley /*@
1576f3b08a26SMatthew 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.
1577f3b08a26SMatthew G. Knepley 
1578f3b08a26SMatthew G. Knepley   Logically Collective on PC
1579f3b08a26SMatthew G. Knepley 
1580f3b08a26SMatthew G. Knepley   Input Parameters:
1581f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1582f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1583f3b08a26SMatthew G. Knepley 
1584f3b08a26SMatthew G. Knepley   Options Database Keys:
1585f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1586f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1587f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1588f3b08a26SMatthew G. Knepley 
1589f3b08a26SMatthew G. Knepley   Level: intermediate
1590f3b08a26SMatthew G. Knepley 
1591f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin
1592db781477SPatrick Sanan .seealso: `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`
1593f3b08a26SMatthew G. Knepley @*/
15949371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt) {
1595f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1596f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1597cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
1598f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1599f3b08a26SMatthew G. Knepley }
1600f3b08a26SMatthew G. Knepley 
1601f3b08a26SMatthew G. Knepley /*@
1602f3b08a26SMatthew G. Knepley   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated.
1603f3b08a26SMatthew G. Knepley 
1604f3b08a26SMatthew G. Knepley   Not collective
1605f3b08a26SMatthew G. Knepley 
1606f3b08a26SMatthew G. Knepley   Input Parameter:
1607f3b08a26SMatthew G. Knepley . pc    - the multigrid context
1608f3b08a26SMatthew G. Knepley 
1609f3b08a26SMatthew G. Knepley   Output Parameter:
1610f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1611f3b08a26SMatthew G. Knepley 
1612f3b08a26SMatthew G. Knepley   Level: intermediate
1613f3b08a26SMatthew G. Knepley 
1614f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin
1615db781477SPatrick Sanan .seealso: `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`
1616f3b08a26SMatthew G. Knepley @*/
16179371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt) {
1618f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1619f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1620dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(adapt, 2);
1621cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
1622f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1623f3b08a26SMatthew G. Knepley }
1624f3b08a26SMatthew G. Knepley 
16254b9ad928SBarry Smith /*@
162641b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
162741b6fd38SMatthew G. Knepley 
162841b6fd38SMatthew G. Knepley   Logically Collective on PC
162941b6fd38SMatthew G. Knepley 
163041b6fd38SMatthew G. Knepley   Input Parameters:
163141b6fd38SMatthew G. Knepley + pc - the multigrid context
163241b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
163341b6fd38SMatthew G. Knepley 
163441b6fd38SMatthew G. Knepley   Options Database Keys:
163541b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
163641b6fd38SMatthew G. Knepley 
163741b6fd38SMatthew G. Knepley   Level: intermediate
163841b6fd38SMatthew G. Knepley 
163941b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin
1640db781477SPatrick Sanan .seealso: `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`
164141b6fd38SMatthew G. Knepley @*/
16429371c9d4SSatish Balay PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr) {
164341b6fd38SMatthew G. Knepley   PetscFunctionBegin;
164441b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1645cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
164641b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
164741b6fd38SMatthew G. Knepley }
164841b6fd38SMatthew G. Knepley 
164941b6fd38SMatthew G. Knepley /*@
165041b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
165141b6fd38SMatthew G. Knepley 
165241b6fd38SMatthew G. Knepley   Not collective
165341b6fd38SMatthew G. Knepley 
165441b6fd38SMatthew G. Knepley   Input Parameter:
165541b6fd38SMatthew G. Knepley . pc    - the multigrid context
165641b6fd38SMatthew G. Knepley 
165741b6fd38SMatthew G. Knepley   Output Parameter:
165841b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
165941b6fd38SMatthew G. Knepley 
166041b6fd38SMatthew G. Knepley   Level: intermediate
166141b6fd38SMatthew G. Knepley 
166241b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin
1663db781477SPatrick Sanan .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`
166441b6fd38SMatthew G. Knepley @*/
16659371c9d4SSatish Balay PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr) {
166641b6fd38SMatthew G. Knepley   PetscFunctionBegin;
166741b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1668dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(cr, 2);
1669cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
167041b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
167141b6fd38SMatthew G. Knepley }
167241b6fd38SMatthew G. Knepley 
167341b6fd38SMatthew G. Knepley /*@
167406792cafSBarry Smith    PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1675710315b6SLawrence Mitchell    on all levels.  Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of
1676710315b6SLawrence Mitchell    pre- and post-smoothing steps.
167706792cafSBarry Smith 
167806792cafSBarry Smith    Logically Collective on PC
167906792cafSBarry Smith 
168006792cafSBarry Smith    Input Parameters:
168106792cafSBarry Smith +  mg - the multigrid context
168206792cafSBarry Smith -  n - the number of smoothing steps
168306792cafSBarry Smith 
168406792cafSBarry Smith    Options Database Key:
1685a2b725a8SWilliam Gropp .  -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
168606792cafSBarry Smith 
168706792cafSBarry Smith    Level: advanced
168806792cafSBarry Smith 
168995452b02SPatrick Sanan    Notes:
169095452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
169106792cafSBarry Smith     there is no separate smooth up on the coarsest grid.
169206792cafSBarry Smith 
1693db781477SPatrick Sanan .seealso: `PCMGSetDistinctSmoothUp()`
169406792cafSBarry Smith @*/
16959371c9d4SSatish Balay PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n) {
169606792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
169706792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
169806792cafSBarry Smith   PetscInt       i, levels;
169906792cafSBarry Smith 
170006792cafSBarry Smith   PetscFunctionBegin;
170106792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
170206792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
170328b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
170406792cafSBarry Smith   levels = mglevels[0]->levels;
170506792cafSBarry Smith 
170606792cafSBarry Smith   for (i = 1; i < levels; i++) {
17079566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
17089566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, n));
170906792cafSBarry Smith     mg->default_smoothu = n;
171006792cafSBarry Smith     mg->default_smoothd = n;
171106792cafSBarry Smith   }
171206792cafSBarry Smith   PetscFunctionReturn(0);
171306792cafSBarry Smith }
171406792cafSBarry Smith 
1715f442ab6aSBarry Smith /*@
17168e5aa403SBarry Smith    PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate KSP from the down (pre) smoother on all levels
1717710315b6SLawrence Mitchell        and adds the suffix _up to the options name
1718f442ab6aSBarry Smith 
1719f442ab6aSBarry Smith    Logically Collective on PC
1720f442ab6aSBarry Smith 
1721f442ab6aSBarry Smith    Input Parameters:
1722f442ab6aSBarry Smith .  pc - the preconditioner context
1723f442ab6aSBarry Smith 
1724f442ab6aSBarry Smith    Options Database Key:
1725147403d9SBarry Smith .  -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1726f442ab6aSBarry Smith 
1727f442ab6aSBarry Smith    Level: advanced
1728f442ab6aSBarry Smith 
172995452b02SPatrick Sanan    Notes:
173095452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
1731f442ab6aSBarry Smith     there is no separate smooth up on the coarsest grid.
1732f442ab6aSBarry Smith 
1733db781477SPatrick Sanan .seealso: `PCMGSetNumberSmooth()`
1734f442ab6aSBarry Smith @*/
17359371c9d4SSatish Balay PetscErrorCode PCMGSetDistinctSmoothUp(PC pc) {
1736f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1737f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1738f442ab6aSBarry Smith   PetscInt       i, levels;
1739f442ab6aSBarry Smith   KSP            subksp;
1740f442ab6aSBarry Smith 
1741f442ab6aSBarry Smith   PetscFunctionBegin;
1742f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
174328b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1744f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1745f442ab6aSBarry Smith 
1746f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1747710315b6SLawrence Mitchell     const char *prefix = NULL;
1748f442ab6aSBarry Smith     /* make sure smoother up and down are different */
17499566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
17509566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
17519566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
17529566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1753f442ab6aSBarry Smith   }
1754f442ab6aSBarry Smith   PetscFunctionReturn(0);
1755f442ab6aSBarry Smith }
1756f442ab6aSBarry Smith 
175707a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
17589371c9d4SSatish Balay PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[]) {
175907a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
176007a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
176107a4832bSFande Kong   Mat           *mat;
176207a4832bSFande Kong   PetscInt       l;
176307a4832bSFande Kong 
176407a4832bSFande Kong   PetscFunctionBegin;
176528b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
17669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
176707a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
176807a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
17699566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
177007a4832bSFande Kong   }
177107a4832bSFande Kong   *num_levels     = mg->nlevels;
177207a4832bSFande Kong   *interpolations = mat;
177307a4832bSFande Kong   PetscFunctionReturn(0);
177407a4832bSFande Kong }
177507a4832bSFande Kong 
177607a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
17779371c9d4SSatish Balay PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[]) {
177807a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
177907a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
178007a4832bSFande Kong   PetscInt       l;
178107a4832bSFande Kong   Mat           *mat;
178207a4832bSFande Kong 
178307a4832bSFande Kong   PetscFunctionBegin;
178428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
17859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
178607a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
17879566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &(mat[l])));
17889566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
178907a4832bSFande Kong   }
179007a4832bSFande Kong   *num_levels      = mg->nlevels;
179107a4832bSFande Kong   *coarseOperators = mat;
179207a4832bSFande Kong   PetscFunctionReturn(0);
179307a4832bSFande Kong }
179407a4832bSFande Kong 
1795f3b08a26SMatthew G. Knepley /*@C
1796f3b08a26SMatthew G. Knepley   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the PCMG package for coarse space construction.
1797f3b08a26SMatthew G. Knepley 
1798f3b08a26SMatthew G. Knepley   Not collective
1799f3b08a26SMatthew G. Knepley 
1800f3b08a26SMatthew G. Knepley   Input Parameters:
1801f3b08a26SMatthew G. Knepley + name     - name of the constructor
1802f3b08a26SMatthew G. Knepley - function - constructor routine
1803f3b08a26SMatthew G. Knepley 
1804f3b08a26SMatthew G. Knepley   Notes:
1805f3b08a26SMatthew G. Knepley   Calling sequence for the routine:
18062b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
1807f3b08a26SMatthew G. Knepley $   pc        - The PC object
1808f3b08a26SMatthew G. Knepley $   l         - The multigrid level, 0 is the coarse level
1809f3b08a26SMatthew G. Knepley $   dm        - The DM for this level
1810f3b08a26SMatthew G. Knepley $   smooth    - The level smoother
1811f3b08a26SMatthew G. Knepley $   Nc        - The size of the coarse space
1812f3b08a26SMatthew G. Knepley $   initGuess - Basis for an initial guess for the space
1813f3b08a26SMatthew G. Knepley $   coarseSp  - A basis for the computed coarse space
1814f3b08a26SMatthew G. Knepley 
1815f3b08a26SMatthew G. Knepley   Level: advanced
1816f3b08a26SMatthew G. Knepley 
1817db781477SPatrick Sanan .seealso: `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1818f3b08a26SMatthew G. Knepley @*/
18199371c9d4SSatish Balay PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) {
1820f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18219566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18229566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
1823f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1824f3b08a26SMatthew G. Knepley }
1825f3b08a26SMatthew G. Knepley 
1826f3b08a26SMatthew G. Knepley /*@C
1827f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1828f3b08a26SMatthew G. Knepley 
1829f3b08a26SMatthew G. Knepley   Not collective
1830f3b08a26SMatthew G. Knepley 
1831f3b08a26SMatthew G. Knepley   Input Parameter:
1832f3b08a26SMatthew G. Knepley . name     - name of the constructor
1833f3b08a26SMatthew G. Knepley 
1834f3b08a26SMatthew G. Knepley   Output Parameter:
1835f3b08a26SMatthew G. Knepley . function - constructor routine
1836f3b08a26SMatthew G. Knepley 
1837f3b08a26SMatthew G. Knepley   Notes:
1838f3b08a26SMatthew G. Knepley   Calling sequence for the routine:
18392b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
1840f3b08a26SMatthew G. Knepley $   pc        - The PC object
1841f3b08a26SMatthew G. Knepley $   l         - The multigrid level, 0 is the coarse level
1842f3b08a26SMatthew G. Knepley $   dm        - The DM for this level
1843f3b08a26SMatthew G. Knepley $   smooth    - The level smoother
1844f3b08a26SMatthew G. Knepley $   Nc        - The size of the coarse space
1845f3b08a26SMatthew G. Knepley $   initGuess - Basis for an initial guess for the space
1846f3b08a26SMatthew G. Knepley $   coarseSp  - A basis for the computed coarse space
1847f3b08a26SMatthew G. Knepley 
1848f3b08a26SMatthew G. Knepley   Level: advanced
1849f3b08a26SMatthew G. Knepley 
1850db781477SPatrick Sanan .seealso: `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1851f3b08a26SMatthew G. Knepley @*/
18529371c9d4SSatish Balay PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *)) {
1853f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18549566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
1855f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1856f3b08a26SMatthew G. Knepley }
1857f3b08a26SMatthew G. Knepley 
18584b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
18594b9ad928SBarry Smith 
18603b09bd56SBarry Smith /*MC
1861ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
18623b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
18633b09bd56SBarry Smith 
18643b09bd56SBarry Smith    Options Database Keys:
18653b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
1866391689abSStefano Zampini .  -pc_mg_cycle_type <v,w> - provide the cycle desired
18678c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
18683b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
1869710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
18702134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
18718cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
18728cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1873e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
18748cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
18758cf6037eSBarry Smith                         to the binary output file called binaryoutput
18763b09bd56SBarry Smith 
187795452b02SPatrick Sanan    Notes:
18780b3c753eSRichard Tran Mills     If one uses a Krylov method such GMRES or CG as the smoother then one must use KSPFGMRES, KSPGCR, or KSPRICHARDSON as the outer Krylov method
18793b09bd56SBarry Smith 
18808cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
18818cf6037eSBarry Smith 
188223067569SBarry Smith        When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
188323067569SBarry Smith        is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
188423067569SBarry Smith        (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
188523067569SBarry Smith        residual is computed at the end of each cycle.
188623067569SBarry Smith 
18873b09bd56SBarry Smith    Level: intermediate
18883b09bd56SBarry Smith 
1889db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1890db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1891db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1892db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1893db781477SPatrick Sanan           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`
18943b09bd56SBarry Smith M*/
18953b09bd56SBarry Smith 
18969371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc) {
1897f3fbd535SBarry Smith   PC_MG *mg;
1898f3fbd535SBarry Smith 
18994b9ad928SBarry Smith   PetscFunctionBegin;
19009566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &mg));
19013ec1f749SStefano Zampini   pc->data               = mg;
1902f3fbd535SBarry Smith   mg->nlevels            = -1;
190310eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19042134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1905f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1906f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1907f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1908f3fbd535SBarry Smith 
190937a44384SMark Adams   pc->useAmat = PETSC_TRUE;
191037a44384SMark Adams 
19114b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1912fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
191330b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
19144b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1915a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
19164b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
19174b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
19184b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1919fb15c04eSBarry Smith 
19209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
19219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
19229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
19302b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
19312b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
19324b9ad928SBarry Smith   PetscFunctionReturn(0);
19334b9ad928SBarry Smith }
1934