xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 5544a5bc068ab743e489f2e333f3664c6a477a2a)
14b9ad928SBarry Smith /*
24b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
34b9ad928SBarry Smith */
4af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/
541b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h>
61e25c274SJed Brown #include <petscdm.h>
7391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *);
84b9ad928SBarry Smith 
9f3b08a26SMatthew G. Knepley /*
10f3b08a26SMatthew G. Knepley    Contains the list of registered coarse space construction routines
11f3b08a26SMatthew G. Knepley */
12f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL;
13f3b08a26SMatthew G. Knepley 
14d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMCycle_Private(PC pc, PC_MG_Levels **mglevelsin, PetscBool transpose, PetscBool matapp, PCRichardsonConvergedReason *reason)
15d71ae5a4SJacob Faibussowitsch {
1631567311SBarry Smith   PC_MG        *mg = (PC_MG *)pc->data;
1731567311SBarry Smith   PC_MG_Levels *mgc, *mglevels = *mglevelsin;
18835f2295SStefano Zampini   PetscInt      cycles = (mglevels->level == 1) ? 1 : mglevels->cycles;
194b9ad928SBarry Smith 
204b9ad928SBarry Smith   PetscFunctionBegin;
219566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
22fcb023d4SJed Brown   if (!transpose) {
2330b0564aSStefano Zampini     if (matapp) {
249566063dSJacob Faibussowitsch       PetscCall(KSPMatSolve(mglevels->smoothd, mglevels->B, mglevels->X)); /* pre-smooth */
259566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, NULL));
2630b0564aSStefano Zampini     } else {
279566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->smoothd, mglevels->b, mglevels->x)); /* pre-smooth */
289566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
2930b0564aSStefano Zampini     }
30fcb023d4SJed Brown   } else {
3128b400f6SJacob Faibussowitsch     PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
329566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(mglevels->smoothu, mglevels->b, mglevels->x)); /* transpose of post-smooth */
339566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
34fcb023d4SJed Brown   }
359566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
3631567311SBarry Smith   if (mglevels->level) { /* not the coarsest grid */
379566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual, 0, 0, 0, 0));
3848a46eb9SPierre Jolivet     if (matapp && !mglevels->R) PetscCall(MatDuplicate(mglevels->B, MAT_DO_NOT_COPY_VALUES, &mglevels->R));
39fcb023d4SJed Brown     if (!transpose) {
409566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
419566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residual)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
42fcb023d4SJed Brown     } else {
439566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A, mglevels->B, mglevels->X, mglevels->R));
449566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residualtranspose)(mglevels->A, mglevels->b, mglevels->x, mglevels->r));
45fcb023d4SJed Brown     }
469566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual, 0, 0, 0, 0));
474b9ad928SBarry Smith 
484b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
4931567311SBarry Smith     if (mglevels->level == mglevels->levels - 1 && mg->ttol && reason) {
504b9ad928SBarry Smith       PetscReal rnorm;
519566063dSJacob Faibussowitsch       PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm));
524b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
5370441072SBarry Smith         if (rnorm < mg->abstol) {
544d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
559566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol));
564b9ad928SBarry Smith         } else {
574d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
589566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n", (double)rnorm, (double)mg->ttol));
594b9ad928SBarry Smith         }
603ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
614b9ad928SBarry Smith       }
624b9ad928SBarry Smith     }
634b9ad928SBarry Smith 
6431567311SBarry Smith     mgc = *(mglevelsin - 1);
659566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
66fcb023d4SJed Brown     if (!transpose) {
679566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B));
689566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b));
69fcb023d4SJed Brown     } else {
709566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B));
719566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b));
72fcb023d4SJed Brown     }
739566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
7430b0564aSStefano Zampini     if (matapp) {
7530b0564aSStefano Zampini       if (!mgc->X) {
769566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X));
7730b0564aSStefano Zampini       } else {
789566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(mgc->X));
7930b0564aSStefano Zampini       }
8030b0564aSStefano Zampini     } else {
819566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mgc->x));
8230b0564aSStefano Zampini     }
8348a46eb9SPierre Jolivet     while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason));
849566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
85fcb023d4SJed Brown     if (!transpose) {
869566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X));
879566063dSJacob Faibussowitsch       else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x));
88fcb023d4SJed Brown     } else {
899566063dSJacob Faibussowitsch       PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x));
90fcb023d4SJed Brown     }
919566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
929566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
93fcb023d4SJed Brown     if (!transpose) {
9430b0564aSStefano Zampini       if (matapp) {
959566063dSJacob Faibussowitsch         PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */
969566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL));
9730b0564aSStefano Zampini       } else {
989566063dSJacob Faibussowitsch         PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */
999566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
10030b0564aSStefano Zampini       }
101fcb023d4SJed Brown     } else {
10228b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
1039566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */
1049566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
105fcb023d4SJed Brown     }
10641b6fd38SMatthew G. Knepley     if (mglevels->cr) {
10728b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
10841b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1099566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1109566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
1119566063dSJacob Faibussowitsch       PetscCall(KSPSetNoisy_Private(mglevels->crx));
1129566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1139566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11441b6fd38SMatthew G. Knepley     }
1159566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1164b9ad928SBarry Smith   }
1173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1184b9ad928SBarry Smith }
1194b9ad928SBarry Smith 
120d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyRichardson_MG(PC pc, Vec b, Vec x, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt its, PetscBool zeroguess, PetscInt *outits, PCRichardsonConvergedReason *reason)
121d71ae5a4SJacob Faibussowitsch {
122f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
123f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
124391689abSStefano Zampini   PC             tpc;
125391689abSStefano Zampini   PetscBool      changeu, changed;
126f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
1274b9ad928SBarry Smith 
1284b9ad928SBarry Smith   PetscFunctionBegin;
129a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
130a762d673SBarry Smith   for (i = 0; i < levels; i++) {
131a762d673SBarry Smith     if (!mglevels[i]->A) {
1329566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1339566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
134a762d673SBarry Smith     }
135a762d673SBarry Smith   }
136391689abSStefano Zampini 
1379566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1389566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1399566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1409566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
141391689abSStefano Zampini   if (!changed && !changeu) {
1429566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels - 1]->b));
143f3fbd535SBarry Smith     mglevels[levels - 1]->b = b;
144391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
145391689abSStefano Zampini     if (!mglevels[levels - 1]->b) {
146391689abSStefano Zampini       Vec *vec;
147391689abSStefano Zampini 
1489566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
149391689abSStefano Zampini       mglevels[levels - 1]->b = *vec;
1509566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
151391689abSStefano Zampini     }
1529566063dSJacob Faibussowitsch     PetscCall(VecCopy(b, mglevels[levels - 1]->b));
153391689abSStefano Zampini   }
154f3fbd535SBarry Smith   mglevels[levels - 1]->x = x;
1554b9ad928SBarry Smith 
15631567311SBarry Smith   mg->rtol   = rtol;
15731567311SBarry Smith   mg->abstol = abstol;
15831567311SBarry Smith   mg->dtol   = dtol;
1594b9ad928SBarry Smith   if (rtol) {
1604b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1614b9ad928SBarry Smith     PetscReal rnorm;
1627319c654SBarry Smith     if (zeroguess) {
1639566063dSJacob Faibussowitsch       PetscCall(VecNorm(b, NORM_2, &rnorm));
1647319c654SBarry Smith     } else {
1659566063dSJacob Faibussowitsch       PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1669566063dSJacob Faibussowitsch       PetscCall(VecNorm(w, NORM_2, &rnorm));
1677319c654SBarry Smith     }
16831567311SBarry Smith     mg->ttol = PetscMax(rtol * rnorm, abstol);
1692fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1702fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1714b9ad928SBarry Smith 
1724d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
173336babb1SJed Brown      stop prematurely due to small residual */
1744d0a8057SBarry Smith   for (i = 1; i < levels; i++) {
175fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
176f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
17723067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1789566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
179fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
1804b9ad928SBarry Smith     }
1814d0a8057SBarry Smith   }
1824d0a8057SBarry Smith 
183dd460d27SBarry Smith   *reason = PCRICHARDSON_NOT_SET;
1844d0a8057SBarry Smith   for (i = 0; i < its; i++) {
1859566063dSJacob Faibussowitsch     PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1864d0a8057SBarry Smith     if (*reason) break;
1874d0a8057SBarry Smith   }
188dd460d27SBarry Smith   if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS;
1894d0a8057SBarry Smith   *outits = i;
190391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1924b9ad928SBarry Smith }
1934b9ad928SBarry Smith 
194d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc)
195d71ae5a4SJacob Faibussowitsch {
1963aeaf226SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1973aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1982b3cbbdaSStefano Zampini   PetscInt       i, n;
1993aeaf226SBarry Smith 
2003aeaf226SBarry Smith   PetscFunctionBegin;
2013aeaf226SBarry Smith   if (mglevels) {
2023aeaf226SBarry Smith     n = mglevels[0]->levels;
2033aeaf226SBarry Smith     for (i = 0; i < n - 1; i++) {
2049566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->r));
2059566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->b));
2069566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->x));
2079566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->R));
2089566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->B));
2099566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->X));
2109566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crx));
2119566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crb));
2129566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2159566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2163aeaf226SBarry Smith     }
2179566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2189566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crb));
219391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
220391689abSStefano Zampini        changes the rhs during PreSolve */
2219566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->b));
2229566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mglevels[n - 1]->B));
2233aeaf226SBarry Smith 
2243aeaf226SBarry Smith     for (i = 0; i < n; i++) {
2252b3cbbdaSStefano Zampini       PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2269566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->A));
22748a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2289566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2299566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2303aeaf226SBarry Smith     }
231f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2323aeaf226SBarry Smith   }
2333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2343aeaf226SBarry Smith }
2353aeaf226SBarry Smith 
23641b6fd38SMatthew G. Knepley /* Implementing CR
23741b6fd38SMatthew G. Knepley 
23841b6fd38SMatthew 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
23941b6fd38SMatthew G. Knepley 
24041b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
24141b6fd38SMatthew G. Knepley 
24241b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24341b6fd38SMatthew G. Knepley 
24441b6fd38SMatthew G. Knepley   Inj^T Inj
24541b6fd38SMatthew G. Knepley 
24641b6fd38SMatthew G. Knepley and
24741b6fd38SMatthew G. Knepley 
24841b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
24941b6fd38SMatthew G. Knepley 
25041b6fd38SMatthew G. Knepley since
25141b6fd38SMatthew G. Knepley 
25241b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
25341b6fd38SMatthew G. Knepley 
25441b6fd38SMatthew G. Knepley Brannick suggests
25541b6fd38SMatthew G. Knepley 
25641b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
25741b6fd38SMatthew G. Knepley 
25841b6fd38SMatthew 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
25941b6fd38SMatthew G. Knepley 
26041b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
26141b6fd38SMatthew G. Knepley 
26241b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26341b6fd38SMatthew G. Knepley 
26441b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
26541b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
26641b6fd38SMatthew G. Knepley */
26741b6fd38SMatthew G. Knepley 
26841b6fd38SMatthew G. Knepley typedef struct {
26941b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
27041b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
27141b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27241b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
27341b6fd38SMatthew G. Knepley } CRContext;
27441b6fd38SMatthew G. Knepley 
275d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc)
276d71ae5a4SJacob Faibussowitsch {
27741b6fd38SMatthew G. Knepley   CRContext *ctx;
27841b6fd38SMatthew G. Knepley   Mat        It;
27941b6fd38SMatthew G. Knepley 
28041b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2819566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2829566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28328b400f6SJacob Faibussowitsch   PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2849566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2859566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2869566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2879566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S, 1.0));
2883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28941b6fd38SMatthew G. Knepley }
29041b6fd38SMatthew G. Knepley 
291d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
292d71ae5a4SJacob Faibussowitsch {
29341b6fd38SMatthew G. Knepley   CRContext *ctx;
29441b6fd38SMatthew G. Knepley 
29541b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2969566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2979566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
2983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29941b6fd38SMatthew G. Knepley }
30041b6fd38SMatthew G. Knepley 
301d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc)
302d71ae5a4SJacob Faibussowitsch {
30341b6fd38SMatthew G. Knepley   CRContext *ctx;
30441b6fd38SMatthew G. Knepley 
30541b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3069566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3099566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3109566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
3113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31241b6fd38SMatthew G. Knepley }
31341b6fd38SMatthew G. Knepley 
314d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
315d71ae5a4SJacob Faibussowitsch {
31641b6fd38SMatthew G. Knepley   CRContext *ctx;
31741b6fd38SMatthew G. Knepley 
31841b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3199566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3209566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3219566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
32241b6fd38SMatthew G. Knepley   ctx->mg = pc;
32341b6fd38SMatthew G. Knepley   ctx->l  = l;
3249566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3259566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3269566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3279566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3289566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
3293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33041b6fd38SMatthew G. Knepley }
33141b6fd38SMatthew G. Knepley 
3328f4fb22eSMark Adams PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *);
3338f4fb22eSMark Adams 
334d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms)
335d71ae5a4SJacob Faibussowitsch {
336f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG *)pc->data;
337ce94432eSBarry Smith   MPI_Comm       comm;
3383aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
33910eca3edSLisandro Dalcin   PCMGType       mgtype   = mg->am;
34010167fecSBarry Smith   PetscInt       mgctype  = (PetscInt)PC_MG_CYCLE_V;
341f3fbd535SBarry Smith   PetscInt       i;
342f3fbd535SBarry Smith   PetscMPIInt    size;
343f3fbd535SBarry Smith   const char    *prefix;
344f3fbd535SBarry Smith   PC             ipc;
3453aeaf226SBarry Smith   PetscInt       n;
3464b9ad928SBarry Smith 
3474b9ad928SBarry Smith   PetscFunctionBegin;
3480700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
349548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc, levels, 2);
3503ba16761SJacob Faibussowitsch   if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS);
3519566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3523aeaf226SBarry Smith   if (mglevels) {
35310eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
3543aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
3559566063dSJacob Faibussowitsch     PetscCall(PCReset_MG(pc));
3563aeaf226SBarry Smith     n = mglevels[0]->levels;
3573aeaf226SBarry Smith     for (i = 0; i < n; i++) {
35848a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3599566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3609566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3619566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3623aeaf226SBarry Smith     }
3639566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3643aeaf226SBarry Smith   }
365f3fbd535SBarry Smith 
366f3fbd535SBarry Smith   mg->nlevels = levels;
367f3fbd535SBarry Smith 
3689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels, &mglevels));
369f3fbd535SBarry Smith 
3709566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
371f3fbd535SBarry Smith 
372a9db87a2SMatthew G Knepley   mg->stageApply = 0;
373f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
3744dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mglevels[i]));
3752fa5cd67SKarl Rupp 
376f3fbd535SBarry Smith     mglevels[i]->level               = i;
377f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
37810eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
379336babb1SJed Brown     mg->default_smoothu              = 2;
380336babb1SJed Brown     mg->default_smoothd              = 2;
38163e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
38263e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
38363e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
38463e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
385f3fbd535SBarry Smith 
386f3fbd535SBarry Smith     if (comms) comm = comms[i];
387d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3889566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3893821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel));
3909566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3919566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3929566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3939566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3948f4fb22eSMark Adams       if (i == 0 && levels > 1) { // coarse grid
3959566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
396f3fbd535SBarry Smith 
3979dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
3989566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
3999566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4009566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
401f3fbd535SBarry Smith         if (size > 1) {
4029566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
403f3fbd535SBarry Smith         } else {
4049566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
405f3fbd535SBarry Smith         }
4069566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
4078f4fb22eSMark Adams       } else {
4088f4fb22eSMark Adams         char tprefix[128];
4098f4fb22eSMark Adams 
4108f4fb22eSMark Adams         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
4118f4fb22eSMark Adams         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
4128f4fb22eSMark Adams         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
4138f4fb22eSMark Adams         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
4148f4fb22eSMark Adams         PetscCall(PCSetType(ipc, PCSOR));
415fb842aefSJose E. Roman         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
4168f4fb22eSMark Adams 
4178f4fb22eSMark Adams         if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_'
4188f4fb22eSMark Adams           PetscBool set;
4198f4fb22eSMark Adams           PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set));
4208f4fb22eSMark Adams           if (set) {
4218f4fb22eSMark Adams             if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix));
4228f4fb22eSMark Adams             else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_"));
4238f4fb22eSMark Adams             PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix));
4248f4fb22eSMark Adams           } else {
425835f2295SStefano Zampini             PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4268f4fb22eSMark Adams             PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4278f4fb22eSMark Adams           }
4288f4fb22eSMark Adams         } else {
429835f2295SStefano Zampini           PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4308f4fb22eSMark Adams           PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4318f4fb22eSMark Adams         }
432f3fbd535SBarry Smith       }
433d5a8f7e6SBarry Smith     }
434f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
43531567311SBarry Smith     mg->rtol             = 0.0;
43631567311SBarry Smith     mg->abstol           = 0.0;
43731567311SBarry Smith     mg->dtol             = 0.0;
43831567311SBarry Smith     mg->ttol             = 0.0;
43931567311SBarry Smith     mg->cyclesperpcapply = 1;
440f3fbd535SBarry Smith   }
441f3fbd535SBarry Smith   mg->levels = mglevels;
4429566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4444b9ad928SBarry Smith }
4454b9ad928SBarry Smith 
44697d33e41SMatthew G. Knepley /*@C
447f1580f4eSBarry Smith   PCMGSetLevels - Sets the number of levels to use with `PCMG`.
448f1580f4eSBarry Smith   Must be called before any other `PCMG` routine.
44997d33e41SMatthew G. Knepley 
450c3339decSBarry Smith   Logically Collective
45197d33e41SMatthew G. Knepley 
45297d33e41SMatthew G. Knepley   Input Parameters:
45397d33e41SMatthew G. Knepley + pc     - the preconditioner context
45497d33e41SMatthew G. Knepley . levels - the number of levels
45597d33e41SMatthew G. Knepley - comms  - optional communicators for each level; this is to allow solving the coarser problems
456d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
45720f4b53cSBarry Smith            you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes
45805552d4bSJunchao Zhang            should participate in each level of problem.
45997d33e41SMatthew G. Knepley 
46097d33e41SMatthew G. Knepley   Level: intermediate
46197d33e41SMatthew G. Knepley 
46297d33e41SMatthew G. Knepley   Notes:
46320f4b53cSBarry Smith   If the number of levels is one then the multigrid uses the `-mg_levels` prefix
4648f4fb22eSMark Adams   for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix.
46597d33e41SMatthew G. Knepley 
466d5a8f7e6SBarry Smith   You can free the information in comms after this routine is called.
467d5a8f7e6SBarry Smith 
468f1580f4eSBarry Smith   The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
469d5a8f7e6SBarry Smith   are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
470d5a8f7e6SBarry Smith   the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
471d5a8f7e6SBarry Smith   of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
472f1580f4eSBarry Smith   the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
473d5a8f7e6SBarry Smith   in the coarse grid solve.
474d5a8f7e6SBarry Smith 
475f1580f4eSBarry Smith   Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
476d5a8f7e6SBarry Smith   must take special care in providing the restriction and interpolation operation. We recommend
477d5a8f7e6SBarry Smith   providing these as two step operations; first perform a standard restriction or interpolation on
478d5a8f7e6SBarry Smith   the full number of ranks for that level and then use an MPI call to copy the resulting vector
47905552d4bSJunchao Zhang   array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
480d5a8f7e6SBarry Smith   cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
48120f4b53cSBarry Smith   receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries.
482d5a8f7e6SBarry Smith 
483feefa0e1SJacob Faibussowitsch   Fortran Notes:
48420f4b53cSBarry Smith   Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM`
485f1580f4eSBarry Smith   is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
486d5a8f7e6SBarry Smith 
487562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()`
48897d33e41SMatthew G. Knepley @*/
489d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms)
490d71ae5a4SJacob Faibussowitsch {
49197d33e41SMatthew G. Knepley   PetscFunctionBegin;
49297d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4934f572ea9SToby Isaac   if (comms) PetscAssertPointer(comms, 3);
494cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
4953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49697d33e41SMatthew G. Knepley }
49797d33e41SMatthew G. Knepley 
498d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc)
499d71ae5a4SJacob Faibussowitsch {
500a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
501a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
502a06653b4SBarry Smith   PetscInt       i, n;
503c07bf074SBarry Smith 
504c07bf074SBarry Smith   PetscFunctionBegin;
5059566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
506a06653b4SBarry Smith   if (mglevels) {
507a06653b4SBarry Smith     n = mglevels[0]->levels;
508a06653b4SBarry Smith     for (i = 0; i < n; i++) {
50948a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
5109566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
5119566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
5129566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
513a06653b4SBarry Smith     }
5149566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
515a06653b4SBarry Smith   }
5169566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5192b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
5202b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5212b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5222b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5232b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5242b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5252b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5262b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5272b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5282b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5292b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
531f3fbd535SBarry Smith }
532f3fbd535SBarry Smith 
533f3fbd535SBarry Smith /*
534f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
535f3fbd535SBarry Smith              or full cycle of multigrid.
536f3fbd535SBarry Smith 
537f3fbd535SBarry Smith   Note:
538f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
539f3fbd535SBarry Smith */
540d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
541d71ae5a4SJacob Faibussowitsch {
542f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
543f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
544391689abSStefano Zampini   PC             tpc;
545f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
54630b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
547f3fbd535SBarry Smith 
548f3fbd535SBarry Smith   PetscFunctionBegin;
54930b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5509566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
551e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
552298cc208SBarry Smith   for (i = 0; i < levels; i++) {
553e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5549566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5559566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
556e1d8e5deSBarry Smith     }
557e1d8e5deSBarry Smith   }
558e1d8e5deSBarry Smith 
5599566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5609566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5619566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5629566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
563391689abSStefano Zampini   if (!changeu && !changed) {
56430b0564aSStefano Zampini     if (matapp) {
5659566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
56630b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
56730b0564aSStefano Zampini     } else {
5689566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
569f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
57030b0564aSStefano Zampini     }
571391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
57230b0564aSStefano Zampini     if (matapp) {
57330b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
57430b0564aSStefano Zampini         PetscInt  N1, N2;
57530b0564aSStefano Zampini         PetscBool flg;
57630b0564aSStefano Zampini 
5779566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5789566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5799566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
58048a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
58130b0564aSStefano Zampini       }
58230b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5839566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
58430b0564aSStefano Zampini       } else {
5859566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
58630b0564aSStefano Zampini       }
58730b0564aSStefano Zampini     } else {
588391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
589391689abSStefano Zampini         Vec *vec;
590391689abSStefano Zampini 
5919566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
592391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5939566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
594391689abSStefano Zampini       }
5959566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
596391689abSStefano Zampini     }
59730b0564aSStefano Zampini   }
5989371c9d4SSatish Balay   if (matapp) {
5999371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
6009371c9d4SSatish Balay   } else {
6019371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
6029371c9d4SSatish Balay   }
60330b0564aSStefano Zampini 
60430b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
60530b0564aSStefano Zampini      Reset operators if sizes/type do no match */
60630b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
60730b0564aSStefano Zampini     PetscInt  Xc, Bc;
60830b0564aSStefano Zampini     PetscBool flg;
60930b0564aSStefano Zampini 
6109566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
6119566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
6129566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
61330b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
61530b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
6169566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6179566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6189566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
61930b0564aSStefano Zampini       }
62030b0564aSStefano Zampini     }
62130b0564aSStefano Zampini   }
622391689abSStefano Zampini 
62331567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6249566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6259566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
62648a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6272fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6289566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6292fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6309566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6312fa5cd67SKarl Rupp   } else {
6329566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
633f3fbd535SBarry Smith   }
6349566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
63530b0564aSStefano Zampini   if (!changeu && !changed) {
6369371c9d4SSatish Balay     if (matapp) {
6379371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6389371c9d4SSatish Balay     } else {
6399371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6409371c9d4SSatish Balay     }
64130b0564aSStefano Zampini   }
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
643f3fbd535SBarry Smith }
644f3fbd535SBarry Smith 
645d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
646d71ae5a4SJacob Faibussowitsch {
647fcb023d4SJed Brown   PetscFunctionBegin;
6489566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
650fcb023d4SJed Brown }
651fcb023d4SJed Brown 
652d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
653d71ae5a4SJacob Faibussowitsch {
654fcb023d4SJed Brown   PetscFunctionBegin;
6559566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65730b0564aSStefano Zampini }
65830b0564aSStefano Zampini 
659d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
660d71ae5a4SJacob Faibussowitsch {
66130b0564aSStefano Zampini   PetscFunctionBegin;
6629566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
664fcb023d4SJed Brown }
665f3fbd535SBarry Smith 
666d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems *PetscOptionsObject)
667d71ae5a4SJacob Faibussowitsch {
668710315b6SLawrence Mitchell   PetscInt            levels, cycles;
669f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
670f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6713d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
672f3fbd535SBarry Smith   PCMGType            mgtype;
673f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6742134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6752b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
676f3fbd535SBarry Smith 
677f3fbd535SBarry Smith   PetscFunctionBegin;
6781d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
679d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6811a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6829566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
683eb3f98d2SBarry Smith     levels++;
6843aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
685eb3f98d2SBarry Smith   }
6869566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6873aeaf226SBarry Smith   mglevels = mg->levels;
6883aeaf226SBarry Smith 
689f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
6909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
6911baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
6922b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6932b3cbbdaSStefano 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));
6942b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
6959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
6969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
69741b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
6989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
6999566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
700f56b1265SBarry Smith   flg = PETSC_FALSE;
7019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
7021baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
703*5544a5bcSStefano Zampini   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)&gtype, &flg));
704*5544a5bcSStefano Zampini   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
70531567311SBarry Smith   mgtype = mg->am;
7069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
7071baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
70831567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
7099566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
7101baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
711f3fbd535SBarry Smith   }
712f3fbd535SBarry Smith   flg = PETSC_FALSE;
7139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
714f3fbd535SBarry Smith   if (flg) {
715f3fbd535SBarry Smith     PetscInt i;
716f3fbd535SBarry Smith     char     eventname[128];
7171a97d7b6SStefano Zampini 
718f3fbd535SBarry Smith     levels = mglevels[0]->levels;
719f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
720835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i));
7219566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
722835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i));
7239566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
724f3fbd535SBarry Smith       if (i) {
725835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i));
7269566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
727835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i));
7289566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
729f3fbd535SBarry Smith       }
730f3fbd535SBarry Smith     }
731eec35531SMatthew G Knepley 
7322611ad71SToby Isaac     if (PetscDefined(USE_LOG)) {
7332611ad71SToby Isaac       const char sname[] = "MG Apply";
734eec35531SMatthew G Knepley 
7352611ad71SToby Isaac       PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
7362611ad71SToby Isaac       if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
737eec35531SMatthew G Knepley     }
738f3fbd535SBarry Smith   }
739d0609cedSBarry Smith   PetscOptionsHeadEnd();
740f3b08a26SMatthew G. Knepley   /* Check option consistency */
7419566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7429566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
74308401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
745f3fbd535SBarry Smith }
746f3fbd535SBarry Smith 
7470a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7480a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7490a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7502b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
751f3fbd535SBarry Smith 
7529804daf3SBarry Smith #include <petscdraw.h>
753d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
754d71ae5a4SJacob Faibussowitsch {
755f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
756f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
757e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
758219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
759f3fbd535SBarry Smith 
760f3fbd535SBarry Smith   PetscFunctionBegin;
7619566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7639566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
764f3fbd535SBarry Smith   if (iascii) {
765e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
76663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
76748a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7682134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7699566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7702134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7719566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7722134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7739566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7742134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7764f66f45eSBarry Smith     } else {
7779566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
778f3fbd535SBarry Smith     }
7791baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
780f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
78163a3b9bcSJacob Faibussowitsch       if (i) {
78263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
783f3fbd535SBarry Smith       } else {
78463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
785f3fbd535SBarry Smith       }
7869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7879566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
789f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
7909566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
791f3fbd535SBarry Smith       } else if (i) {
79263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
7939566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7949566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7959566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
796f3fbd535SBarry Smith       }
79741b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
79863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
7999566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8009566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
8019566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
80241b6fd38SMatthew G. Knepley       }
803f3fbd535SBarry Smith     }
8045b0b0462SBarry Smith   } else if (isbinary) {
8055b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
8069566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
80748a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8085b0b0462SBarry Smith     }
809219b1045SBarry Smith   } else if (isdraw) {
810219b1045SBarry Smith     PetscDraw draw;
811b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
8129566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8139566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8149566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
815219b1045SBarry Smith     bottom = y - th;
816219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
817b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8189566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8199566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8209566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
821b4375e8dSPeter Brune       } else {
822b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8239566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8249566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8259566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8269566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8279566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8289566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
829b4375e8dSPeter Brune       }
8309566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8311cd381d6SBarry Smith       bottom -= th;
832219b1045SBarry Smith     }
8335b0b0462SBarry Smith   }
8343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
835f3fbd535SBarry Smith }
836f3fbd535SBarry Smith 
837af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
838cab2e9ccSBarry Smith 
839f3fbd535SBarry Smith /*
840f3fbd535SBarry Smith     Calls setup for the KSP on each level
841f3fbd535SBarry Smith */
842d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
843d71ae5a4SJacob Faibussowitsch {
844f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
845f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8461a97d7b6SStefano Zampini   PetscInt       i, n;
84798e04984SBarry Smith   PC             cpc;
8483db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
849f3fbd535SBarry Smith   Mat            dA, dB;
850f3fbd535SBarry Smith   Vec            tvec;
851218a07d4SBarry Smith   DM            *dms;
8520a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
85341b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8542b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
855f3fbd535SBarry Smith 
856f3fbd535SBarry Smith   PetscFunctionBegin;
85728b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8581a97d7b6SStefano Zampini   n = mglevels[0]->levels;
85901bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8603aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8613aeaf226SBarry Smith     PetscInt levels;
8629566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8633aeaf226SBarry Smith     levels++;
8643aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8659566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8663aeaf226SBarry Smith       n = levels;
8679566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8683aeaf226SBarry Smith       mglevels = mg->levels;
8693aeaf226SBarry Smith     }
8703aeaf226SBarry Smith   }
8719566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc));
8723aeaf226SBarry Smith 
873f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
874f3fbd535SBarry Smith   /* so use those from global PC */
875f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8769566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
87798e04984SBarry Smith   if (opsset) {
87898e04984SBarry Smith     Mat mmat;
8799566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
88098e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
88198e04984SBarry Smith   }
8824a5f07a5SMark F. Adams 
88341b6fd38SMatthew G. Knepley   /* Create CR solvers */
8849566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
88541b6fd38SMatthew G. Knepley   if (doCR) {
88641b6fd38SMatthew G. Knepley     const char *prefix;
88741b6fd38SMatthew G. Knepley 
8889566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
88941b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
89041b6fd38SMatthew G. Knepley       PC   ipc, cr;
89141b6fd38SMatthew G. Knepley       char crprefix[128];
89241b6fd38SMatthew G. Knepley 
8939566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
8943821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
8959566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
8969566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
8979566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
8989566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
8999566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9009566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9019566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9029566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
90341b6fd38SMatthew G. Knepley 
9049566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
9059566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9069566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9079566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
9089566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
9099566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
91041b6fd38SMatthew G. Knepley 
911fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
9129566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
913835f2295SStefano Zampini       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i));
9149566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
91541b6fd38SMatthew G. Knepley     }
91641b6fd38SMatthew G. Knepley   }
91741b6fd38SMatthew G. Knepley 
9184a5f07a5SMark F. Adams   if (!opsset) {
9199566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9204a5f07a5SMark F. Adams     if (use_amat) {
9219566063dSJacob 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"));
9229566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
92369858f1bSStefano Zampini     } else {
9249566063dSJacob 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"));
9259566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9264a5f07a5SMark F. Adams     }
9274a5f07a5SMark F. Adams   }
928f3fbd535SBarry Smith 
9299c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9309c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9319c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9322b3cbbdaSStefano Zampini       break;
9339c7ffb39SBarry Smith     }
9349c7ffb39SBarry Smith   }
9352134b1e4SBarry Smith 
9369566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9372134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9382b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9392134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9402134b1e4SBarry Smith   }
9412134b1e4SBarry Smith 
9422b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9432b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9442b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9452b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9462b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9472b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9482b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9492b3cbbdaSStefano Zampini     }
9502b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9512b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9522b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9532b3cbbdaSStefano Zampini     }
9542b3cbbdaSStefano Zampini   }
9552b3cbbdaSStefano Zampini 
9569c7ffb39SBarry Smith   /*
9579c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9582b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9599c7ffb39SBarry Smith   */
96032fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
96132fe681dSStefano Zampini     /* first see if we can compute a coarse space */
96232fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
96332fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
96432fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
96532fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
96632fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
96732fe681dSStefano Zampini         }
96832fe681dSStefano Zampini       }
96932fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9702e499ae9SBarry Smith       Mat p;
97173250ac0SBarry Smith       Vec rscale;
9729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
973218a07d4SBarry Smith       dms[n - 1] = pc->dm;
974ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9759566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
976218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
977942e3340SBarry Smith         DMKSP     kdm;
978eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9799566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9809566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
981c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9829566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9839566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
984c27ee7a3SPatrick Farrell         }
98541b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9869566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
9879566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
98841b6fd38SMatthew G. Knepley         }
9899566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
990d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
991d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
9920298fd71SBarry Smith         kdm->ops->computerhs = NULL;
9930298fd71SBarry Smith         kdm->rhsctx          = NULL;
99424c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
9959566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
9969566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
9979566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
9989566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
9999566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1000218a07d4SBarry Smith         }
10019566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
10023ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
10039566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
10049566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
10059566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
10063ad4599aSBarry Smith         }
10079566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
1008eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
10099566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
10109566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
10119566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1012eab52d2bSLawrence Mitchell         }
101324c3aa18SBarry Smith       }
10142d2b81a6SBarry Smith 
10159566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10169566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1017ce4cda84SJed Brown     }
101832fe681dSStefano Zampini   }
1019cab2e9ccSBarry Smith 
10202134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10212134b1e4SBarry Smith     Mat       A, B;
10222134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10232134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10242134b1e4SBarry Smith 
10252b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10262b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10272134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1028f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10297827d75bSBarry 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");
103048a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
103148a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
103248a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
103348a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
103448a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10352134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10362134b1e4SBarry Smith       if (!doA && dAeqdB) {
10379566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10382134b1e4SBarry Smith         A = B;
10392134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10409566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10419566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1042b9367914SBarry Smith       }
10432134b1e4SBarry Smith       if (!doB && dAeqdB) {
10449566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10452134b1e4SBarry Smith         B = A;
10462134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10479566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10489566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10497d537d92SJed Brown       }
10502134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10519566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10529566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10539566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10542134b1e4SBarry Smith       }
10552134b1e4SBarry Smith       dA = A;
1056f3fbd535SBarry Smith       dB = B;
1057f3fbd535SBarry Smith     }
1058f3fbd535SBarry Smith   }
1059f3b08a26SMatthew G. Knepley 
1060f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10612b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1062f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
106348a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10642b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1065f3b08a26SMatthew G. Knepley     }
106648a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1067f3b08a26SMatthew G. Knepley   }
1068f3b08a26SMatthew G. Knepley 
10692134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1070caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1071ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1072caa4e7f2SJed Brown       Mat Restrict, Inject;
1073caa4e7f2SJed Brown       Vec rscale;
10749566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10759566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10769566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10779566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10789566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10799566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1080caa4e7f2SJed Brown     }
1081caa4e7f2SJed Brown   }
1082f3fbd535SBarry Smith 
1083f3fbd535SBarry Smith   if (!pc->setupcalled) {
108448a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1085f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
108648a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
108748a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1088f3fbd535SBarry Smith     }
108915229ffcSPierre Jolivet     /* insure that if either interpolation or restriction is set the other one is set */
1090f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
10919566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
10929566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1093f3fbd535SBarry Smith     }
1094f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1095f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1096f3fbd535SBarry Smith         Vec *vec;
10979566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
10989566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
10999566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
11009566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1101f3fbd535SBarry Smith       }
1102f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
11039566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11049566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
11059566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1106f3fbd535SBarry Smith       }
1107f3fbd535SBarry Smith       if (!mglevels[i]->x) {
11089566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11099566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
11109566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1111f3fbd535SBarry Smith       }
111241b6fd38SMatthew G. Knepley       if (doCR) {
11139566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11149566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11159566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
111641b6fd38SMatthew G. Knepley       }
1117f3fbd535SBarry Smith     }
1118f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1119f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1120f3fbd535SBarry Smith       Vec *vec;
11219566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11229566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11239566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11249566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1125f3fbd535SBarry Smith     }
112641b6fd38SMatthew G. Knepley     if (doCR) {
11279566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11289566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11299566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
113041b6fd38SMatthew G. Knepley     }
1131f3fbd535SBarry Smith   }
1132f3fbd535SBarry Smith 
113398e04984SBarry Smith   if (pc->dm) {
113498e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
113598e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
113698e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
113798e04984SBarry Smith     }
113898e04984SBarry Smith   }
113908549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
114008549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
114108549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1142f3fbd535SBarry Smith 
1143f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11442a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1145f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11469566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1147f3fbd535SBarry Smith     }
11489566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11499566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11509566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1151d4645a75SStefano Zampini     if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11529566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1153d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1154d42688cbSBarry Smith       Mat mat;
11559566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11569566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1157d42688cbSBarry Smith     }
1158fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1159fcb023d4SJed Brown       Mat mat;
11609566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11619566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1162fcb023d4SJed Brown     }
1163f3fbd535SBarry Smith   }
1164f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1165f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1166f3fbd535SBarry Smith       Mat downmat, downpmat;
1167f3fbd535SBarry Smith 
1168f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11699566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1170f3fbd535SBarry Smith       if (!opsset) {
11719566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11729566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1173f3fbd535SBarry Smith       }
1174f3fbd535SBarry Smith 
11759566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11769566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11779566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1178d4645a75SStefano Zampini       if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
11799566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1180f3fbd535SBarry Smith     }
118141b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
118241b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
118341b6fd38SMatthew G. Knepley 
118441b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
11859566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
118641b6fd38SMatthew G. Knepley       if (!opsset) {
11879566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11889566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
118941b6fd38SMatthew G. Knepley       }
119041b6fd38SMatthew G. Knepley 
11919566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11929566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11939566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1194d4645a75SStefano Zampini       if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
11959566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
119641b6fd38SMatthew G. Knepley     }
1197f3fbd535SBarry Smith   }
1198f3fbd535SBarry Smith 
11999566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
12009566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1201d4645a75SStefano Zampini   if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
12029566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1203f3fbd535SBarry Smith 
1204f3fbd535SBarry Smith   /*
1205f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1206e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1207f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1208f3fbd535SBarry Smith 
1209f3fbd535SBarry Smith    Only support one or the other at the same time.
1210f3fbd535SBarry Smith   */
1211f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1213ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1214f3fbd535SBarry Smith   dump = PETSC_FALSE;
1215f3fbd535SBarry Smith #endif
12169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1217ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1218f3fbd535SBarry Smith 
1219f3fbd535SBarry Smith   if (viewer) {
122048a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1221f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12229566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12239566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1224f3fbd535SBarry Smith     }
1225f3fbd535SBarry Smith   }
12263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1227f3fbd535SBarry Smith }
1228f3fbd535SBarry Smith 
1229d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1230d71ae5a4SJacob Faibussowitsch {
123197d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
123297d33e41SMatthew G. Knepley 
123397d33e41SMatthew G. Knepley   PetscFunctionBegin;
123497d33e41SMatthew G. Knepley   *levels = mg->nlevels;
12353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123697d33e41SMatthew G. Knepley }
123797d33e41SMatthew G. Knepley 
12384b9ad928SBarry Smith /*@
1239f1580f4eSBarry Smith   PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12404b9ad928SBarry Smith 
12414b9ad928SBarry Smith   Not Collective
12424b9ad928SBarry Smith 
12434b9ad928SBarry Smith   Input Parameter:
12444b9ad928SBarry Smith . pc - the preconditioner context
12454b9ad928SBarry Smith 
1246feefa0e1SJacob Faibussowitsch   Output Parameter:
12474b9ad928SBarry Smith . levels - the number of levels
12484b9ad928SBarry Smith 
12494b9ad928SBarry Smith   Level: advanced
12504b9ad928SBarry Smith 
1251562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()`
12524b9ad928SBarry Smith @*/
1253d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1254d71ae5a4SJacob Faibussowitsch {
12554b9ad928SBarry Smith   PetscFunctionBegin;
12560700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12574f572ea9SToby Isaac   PetscAssertPointer(levels, 2);
125897d33e41SMatthew G. Knepley   *levels = 0;
1259cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12614b9ad928SBarry Smith }
12624b9ad928SBarry Smith 
12634b9ad928SBarry Smith /*@
1264f1580f4eSBarry Smith   PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1265e7d4b4cbSMark Adams 
1266e7d4b4cbSMark Adams   Input Parameter:
1267e7d4b4cbSMark Adams . pc - the preconditioner context
1268e7d4b4cbSMark Adams 
126990db8557SMark Adams   Output Parameters:
127090db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
127190db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1272e7d4b4cbSMark Adams 
1273e7d4b4cbSMark Adams   Level: advanced
1274e7d4b4cbSMark Adams 
1275f1580f4eSBarry Smith   Note:
1276f1580f4eSBarry Smith   This is often call the operator complexity in multigrid literature
1277f1580f4eSBarry Smith 
1278562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1279e7d4b4cbSMark Adams @*/
1280d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1281d71ae5a4SJacob Faibussowitsch {
1282e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1283e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1284e7d4b4cbSMark Adams   PetscInt       lev, N;
1285e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1286e7d4b4cbSMark Adams   MatInfo        info;
1287e7d4b4cbSMark Adams 
1288e7d4b4cbSMark Adams   PetscFunctionBegin;
128990db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12904f572ea9SToby Isaac   if (gc) PetscAssertPointer(gc, 2);
12914f572ea9SToby Isaac   if (oc) PetscAssertPointer(oc, 3);
1292e7d4b4cbSMark Adams   if (!pc->setupcalled) {
129390db8557SMark Adams     if (gc) *gc = 0;
129490db8557SMark Adams     if (oc) *oc = 0;
12953ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1296e7d4b4cbSMark Adams   }
1297e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1298e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1299e7d4b4cbSMark Adams     Mat dB;
13009566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
13019566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
13029566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1303e7d4b4cbSMark Adams     sgc += N;
1304e7d4b4cbSMark Adams     soc += info.nz_used;
13059371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
13069371c9d4SSatish Balay       nnz0 = info.nz_used;
13079371c9d4SSatish Balay       n0   = N;
13089371c9d4SSatish Balay     }
1309e7d4b4cbSMark Adams   }
13100fdf79fbSJacob Faibussowitsch   PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13110fdf79fbSJacob Faibussowitsch   *gc = (PetscReal)(sgc / n0);
131290db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1314e7d4b4cbSMark Adams }
1315e7d4b4cbSMark Adams 
1316e7d4b4cbSMark Adams /*@
131704c3f3b8SBarry Smith   PCMGSetType - Determines the form of multigrid to use, either
13184b9ad928SBarry Smith   multiplicative, additive, full, or the Kaskade algorithm.
13194b9ad928SBarry Smith 
1320c3339decSBarry Smith   Logically Collective
13214b9ad928SBarry Smith 
13224b9ad928SBarry Smith   Input Parameters:
13234b9ad928SBarry Smith + pc   - the preconditioner context
1324f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13254b9ad928SBarry Smith 
13264b9ad928SBarry Smith   Options Database Key:
132720f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13284b9ad928SBarry Smith 
13294b9ad928SBarry Smith   Level: advanced
13304b9ad928SBarry Smith 
1331562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13324b9ad928SBarry Smith @*/
1333d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1334d71ae5a4SJacob Faibussowitsch {
1335f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13364b9ad928SBarry Smith 
13374b9ad928SBarry Smith   PetscFunctionBegin;
13380700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1339c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
134031567311SBarry Smith   mg->am = form;
13419dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1342c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
13433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1344c60c7ad4SBarry Smith }
1345c60c7ad4SBarry Smith 
1346c60c7ad4SBarry Smith /*@
1347f1580f4eSBarry Smith   PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1348c60c7ad4SBarry Smith 
1349c3339decSBarry Smith   Logically Collective
1350c60c7ad4SBarry Smith 
1351c60c7ad4SBarry Smith   Input Parameter:
1352c60c7ad4SBarry Smith . pc - the preconditioner context
1353c60c7ad4SBarry Smith 
1354c60c7ad4SBarry Smith   Output Parameter:
1355f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1356c60c7ad4SBarry Smith 
1357c60c7ad4SBarry Smith   Level: advanced
1358c60c7ad4SBarry Smith 
1359562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1360c60c7ad4SBarry Smith @*/
1361d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1362d71ae5a4SJacob Faibussowitsch {
1363c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1364c60c7ad4SBarry Smith 
1365c60c7ad4SBarry Smith   PetscFunctionBegin;
1366c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1367c60c7ad4SBarry Smith   *type = mg->am;
13683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13694b9ad928SBarry Smith }
13704b9ad928SBarry Smith 
13714b9ad928SBarry Smith /*@
1372f1580f4eSBarry Smith   PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
13734b9ad928SBarry Smith   complicated cycling.
13744b9ad928SBarry Smith 
1375c3339decSBarry Smith   Logically Collective
13764b9ad928SBarry Smith 
13774b9ad928SBarry Smith   Input Parameters:
1378c2be2410SBarry Smith + pc - the multigrid context
1379f1580f4eSBarry Smith - n  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
13804b9ad928SBarry Smith 
13814b9ad928SBarry Smith   Options Database Key:
1382c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
13834b9ad928SBarry Smith 
13844b9ad928SBarry Smith   Level: advanced
13854b9ad928SBarry Smith 
1386562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
13874b9ad928SBarry Smith @*/
1388d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1389d71ae5a4SJacob Faibussowitsch {
1390f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1391f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
139279416396SBarry Smith   PetscInt       i, levels;
13934b9ad928SBarry Smith 
13944b9ad928SBarry Smith   PetscFunctionBegin;
13950700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
139669fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
139728b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1398f3fbd535SBarry Smith   levels = mglevels[0]->levels;
13992fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
14003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14014b9ad928SBarry Smith }
14024b9ad928SBarry Smith 
14038cc2d5dfSBarry Smith /*@
14048cc2d5dfSBarry Smith   PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1405f1580f4eSBarry Smith   of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
14068cc2d5dfSBarry Smith 
1407c3339decSBarry Smith   Logically Collective
14088cc2d5dfSBarry Smith 
14098cc2d5dfSBarry Smith   Input Parameters:
14108cc2d5dfSBarry Smith + pc - the multigrid context
14118cc2d5dfSBarry Smith - n  - number of cycles (default is 1)
14128cc2d5dfSBarry Smith 
14138cc2d5dfSBarry Smith   Options Database Key:
1414147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14158cc2d5dfSBarry Smith 
14168cc2d5dfSBarry Smith   Level: advanced
14178cc2d5dfSBarry Smith 
1418f1580f4eSBarry Smith   Note:
1419f1580f4eSBarry Smith   This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14208cc2d5dfSBarry Smith 
1421562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14228cc2d5dfSBarry Smith @*/
1423d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1424d71ae5a4SJacob Faibussowitsch {
1425f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14268cc2d5dfSBarry Smith 
14278cc2d5dfSBarry Smith   PetscFunctionBegin;
14280700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1429c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14302a21e185SBarry Smith   mg->cyclesperpcapply = n;
14313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14328cc2d5dfSBarry Smith }
14338cc2d5dfSBarry Smith 
143466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1435d71ae5a4SJacob Faibussowitsch {
1436fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1437fb15c04eSBarry Smith 
1438fb15c04eSBarry Smith   PetscFunctionBegin;
14392134b1e4SBarry Smith   mg->galerkin = use;
14403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1441fb15c04eSBarry Smith }
1442fb15c04eSBarry Smith 
1443c2be2410SBarry Smith /*@
144497177400SBarry Smith   PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
144582b87d87SMatthew G. Knepley   finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1446c2be2410SBarry Smith 
1447c3339decSBarry Smith   Logically Collective
1448c2be2410SBarry Smith 
1449c2be2410SBarry Smith   Input Parameters:
1450c91913d3SJed Brown + pc  - the multigrid context
1451f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1452c2be2410SBarry Smith 
1453c2be2410SBarry Smith   Options Database Key:
1454147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1455c2be2410SBarry Smith 
1456c2be2410SBarry Smith   Level: intermediate
1457c2be2410SBarry Smith 
1458f1580f4eSBarry Smith   Note:
1459f1580f4eSBarry Smith   Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1460f1580f4eSBarry Smith   use the `PCMG` construction of the coarser grids.
14611c1aac46SBarry Smith 
1462562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1463c2be2410SBarry Smith @*/
1464d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1465d71ae5a4SJacob Faibussowitsch {
1466c2be2410SBarry Smith   PetscFunctionBegin;
14670700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1468cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
14693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1470c2be2410SBarry Smith }
1471c2be2410SBarry Smith 
14723fc8bf9cSBarry Smith /*@
1473f1580f4eSBarry Smith   PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
14743fc8bf9cSBarry Smith 
14753fc8bf9cSBarry Smith   Not Collective
14763fc8bf9cSBarry Smith 
14773fc8bf9cSBarry Smith   Input Parameter:
14783fc8bf9cSBarry Smith . pc - the multigrid context
14793fc8bf9cSBarry Smith 
14803fc8bf9cSBarry Smith   Output Parameter:
1481f1580f4eSBarry 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`
14823fc8bf9cSBarry Smith 
14833fc8bf9cSBarry Smith   Level: intermediate
14843fc8bf9cSBarry Smith 
1485562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
14863fc8bf9cSBarry Smith @*/
1487d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1488d71ae5a4SJacob Faibussowitsch {
1489f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14903fc8bf9cSBarry Smith 
14913fc8bf9cSBarry Smith   PetscFunctionBegin;
14920700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14932134b1e4SBarry Smith   *galerkin = mg->galerkin;
14943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14953fc8bf9cSBarry Smith }
14963fc8bf9cSBarry Smith 
149766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1498d71ae5a4SJacob Faibussowitsch {
1499f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1500f3b08a26SMatthew G. Knepley 
1501f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1502f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
15033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1504f3b08a26SMatthew G. Knepley }
1505f3b08a26SMatthew G. Knepley 
150666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1507d71ae5a4SJacob Faibussowitsch {
1508f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1509f3b08a26SMatthew G. Knepley 
1510f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1511f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
15123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1513f3b08a26SMatthew G. Knepley }
1514f3b08a26SMatthew G. Knepley 
151566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1516d71ae5a4SJacob Faibussowitsch {
15172b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15182b3cbbdaSStefano Zampini 
15192b3cbbdaSStefano Zampini   PetscFunctionBegin;
15202b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15212b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
1522a077d33dSBarry Smith   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
15233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15242b3cbbdaSStefano Zampini }
15252b3cbbdaSStefano Zampini 
152666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1527d71ae5a4SJacob Faibussowitsch {
15282b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15292b3cbbdaSStefano Zampini 
15302b3cbbdaSStefano Zampini   PetscFunctionBegin;
15312b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15332b3cbbdaSStefano Zampini }
15342b3cbbdaSStefano Zampini 
153566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1536d71ae5a4SJacob Faibussowitsch {
153741b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
153841b6fd38SMatthew G. Knepley 
153941b6fd38SMatthew G. Knepley   PetscFunctionBegin;
154041b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
15413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154241b6fd38SMatthew G. Knepley }
154341b6fd38SMatthew G. Knepley 
154466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1545d71ae5a4SJacob Faibussowitsch {
154641b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
154741b6fd38SMatthew G. Knepley 
154841b6fd38SMatthew G. Knepley   PetscFunctionBegin;
154941b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
15503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155141b6fd38SMatthew G. Knepley }
155241b6fd38SMatthew G. Knepley 
1553cc4c1da9SBarry Smith /*@
15542b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15552b3cbbdaSStefano Zampini 
15562b3cbbdaSStefano 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.
15572b3cbbdaSStefano Zampini 
1558c3339decSBarry Smith   Logically Collective
15592b3cbbdaSStefano Zampini 
15602b3cbbdaSStefano Zampini   Input Parameters:
15612b3cbbdaSStefano Zampini + pc    - the multigrid context
15622b3cbbdaSStefano Zampini - ctype - the type of coarse space
15632b3cbbdaSStefano Zampini 
15642b3cbbdaSStefano Zampini   Options Database Keys:
15652b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
1566a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw`
15672b3cbbdaSStefano Zampini 
15682b3cbbdaSStefano Zampini   Level: intermediate
15692b3cbbdaSStefano Zampini 
1570a077d33dSBarry Smith   Note:
1571a077d33dSBarry Smith   Requires a `DM` with specific functionality be attached to the `PC`.
1572a077d33dSBarry Smith 
1573a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM`
15742b3cbbdaSStefano Zampini @*/
1575d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1576d71ae5a4SJacob Faibussowitsch {
15772b3cbbdaSStefano Zampini   PetscFunctionBegin;
15782b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15792b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
15802b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
15813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15822b3cbbdaSStefano Zampini }
15832b3cbbdaSStefano Zampini 
1584cc4c1da9SBarry Smith /*@
15852b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
15862b3cbbdaSStefano Zampini 
15872b3cbbdaSStefano Zampini   Not Collective
15882b3cbbdaSStefano Zampini 
15892b3cbbdaSStefano Zampini   Input Parameter:
15902b3cbbdaSStefano Zampini . pc - the multigrid context
15912b3cbbdaSStefano Zampini 
15922b3cbbdaSStefano Zampini   Output Parameter:
15932b3cbbdaSStefano Zampini . ctype - the type of coarse space
15942b3cbbdaSStefano Zampini 
15952b3cbbdaSStefano Zampini   Level: intermediate
15962b3cbbdaSStefano Zampini 
1597562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
15982b3cbbdaSStefano Zampini @*/
1599d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1600d71ae5a4SJacob Faibussowitsch {
16012b3cbbdaSStefano Zampini   PetscFunctionBegin;
16022b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16034f572ea9SToby Isaac   PetscAssertPointer(ctype, 2);
16042b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
16053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16062b3cbbdaSStefano Zampini }
16072b3cbbdaSStefano Zampini 
16082b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1609f3b08a26SMatthew G. Knepley /*@
1610f3b08a26SMatthew 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.
1611f3b08a26SMatthew G. Knepley 
1612c3339decSBarry Smith   Logically Collective
1613f3b08a26SMatthew G. Knepley 
1614f3b08a26SMatthew G. Knepley   Input Parameters:
1615f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1616f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1617f3b08a26SMatthew G. Knepley 
1618f3b08a26SMatthew G. Knepley   Options Database Keys:
1619f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1620f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1621f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1622f3b08a26SMatthew G. Knepley 
1623f3b08a26SMatthew G. Knepley   Level: intermediate
1624f3b08a26SMatthew G. Knepley 
1625562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1626f3b08a26SMatthew G. Knepley @*/
1627d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1628d71ae5a4SJacob Faibussowitsch {
1629f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1630f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1631cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1633f3b08a26SMatthew G. Knepley }
1634f3b08a26SMatthew G. Knepley 
1635f3b08a26SMatthew G. Knepley /*@
1636f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1637f1580f4eSBarry Smith   and thus accurately interpolated.
1638f3b08a26SMatthew G. Knepley 
163920f4b53cSBarry Smith   Not Collective
1640f3b08a26SMatthew G. Knepley 
1641f3b08a26SMatthew G. Knepley   Input Parameter:
1642f3b08a26SMatthew G. Knepley . pc - the multigrid context
1643f3b08a26SMatthew G. Knepley 
1644f3b08a26SMatthew G. Knepley   Output Parameter:
1645f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1646f3b08a26SMatthew G. Knepley 
1647f3b08a26SMatthew G. Knepley   Level: intermediate
1648f3b08a26SMatthew G. Knepley 
1649562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1650f3b08a26SMatthew G. Knepley @*/
1651d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1652d71ae5a4SJacob Faibussowitsch {
1653f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1654f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16554f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
1656cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
16573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1658f3b08a26SMatthew G. Knepley }
1659f3b08a26SMatthew G. Knepley 
16604b9ad928SBarry Smith /*@
166141b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
166241b6fd38SMatthew G. Knepley 
1663c3339decSBarry Smith   Logically Collective
166441b6fd38SMatthew G. Knepley 
166541b6fd38SMatthew G. Knepley   Input Parameters:
166641b6fd38SMatthew G. Knepley + pc - the multigrid context
166741b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
166841b6fd38SMatthew G. Knepley 
1669f1580f4eSBarry Smith   Options Database Key:
167041b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
167141b6fd38SMatthew G. Knepley 
167241b6fd38SMatthew G. Knepley   Level: intermediate
167341b6fd38SMatthew G. Knepley 
1674562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
167541b6fd38SMatthew G. Knepley @*/
1676d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1677d71ae5a4SJacob Faibussowitsch {
167841b6fd38SMatthew G. Knepley   PetscFunctionBegin;
167941b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1680cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
16813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168241b6fd38SMatthew G. Knepley }
168341b6fd38SMatthew G. Knepley 
168441b6fd38SMatthew G. Knepley /*@
168541b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
168641b6fd38SMatthew G. Knepley 
168720f4b53cSBarry Smith   Not Collective
168841b6fd38SMatthew G. Knepley 
168941b6fd38SMatthew G. Knepley   Input Parameter:
169041b6fd38SMatthew G. Knepley . pc - the multigrid context
169141b6fd38SMatthew G. Knepley 
169241b6fd38SMatthew G. Knepley   Output Parameter:
169341b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
169441b6fd38SMatthew G. Knepley 
169541b6fd38SMatthew G. Knepley   Level: intermediate
169641b6fd38SMatthew G. Knepley 
1697562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
169841b6fd38SMatthew G. Knepley @*/
1699d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1700d71ae5a4SJacob Faibussowitsch {
170141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
170241b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17034f572ea9SToby Isaac   PetscAssertPointer(cr, 2);
1704cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
17053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
170641b6fd38SMatthew G. Knepley }
170741b6fd38SMatthew G. Knepley 
170841b6fd38SMatthew G. Knepley /*@
170906792cafSBarry Smith   PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1710f1580f4eSBarry Smith   on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1711710315b6SLawrence Mitchell   pre- and post-smoothing steps.
171206792cafSBarry Smith 
1713c3339decSBarry Smith   Logically Collective
171406792cafSBarry Smith 
171506792cafSBarry Smith   Input Parameters:
1716feefa0e1SJacob Faibussowitsch + pc - the multigrid context
171706792cafSBarry Smith - n  - the number of smoothing steps
171806792cafSBarry Smith 
171906792cafSBarry Smith   Options Database Key:
1720a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
172106792cafSBarry Smith 
172206792cafSBarry Smith   Level: advanced
172306792cafSBarry Smith 
1724f1580f4eSBarry Smith   Note:
1725f1580f4eSBarry Smith   This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid.
172606792cafSBarry Smith 
1727562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()`
172806792cafSBarry Smith @*/
1729d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1730d71ae5a4SJacob Faibussowitsch {
173106792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
173206792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
173306792cafSBarry Smith   PetscInt       i, levels;
173406792cafSBarry Smith 
173506792cafSBarry Smith   PetscFunctionBegin;
173606792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
173706792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
173828b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
173906792cafSBarry Smith   levels = mglevels[0]->levels;
174006792cafSBarry Smith 
174106792cafSBarry Smith   for (i = 1; i < levels; i++) {
1742fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
1743fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
174406792cafSBarry Smith     mg->default_smoothu = n;
174506792cafSBarry Smith     mg->default_smoothd = n;
174606792cafSBarry Smith   }
17473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
174806792cafSBarry Smith }
174906792cafSBarry Smith 
1750f442ab6aSBarry Smith /*@
1751f1580f4eSBarry Smith   PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1752710315b6SLawrence Mitchell   and adds the suffix _up to the options name
1753f442ab6aSBarry Smith 
1754c3339decSBarry Smith   Logically Collective
1755f442ab6aSBarry Smith 
1756f1580f4eSBarry Smith   Input Parameter:
1757f442ab6aSBarry Smith . pc - the preconditioner context
1758f442ab6aSBarry Smith 
1759f442ab6aSBarry Smith   Options Database Key:
1760147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1761f442ab6aSBarry Smith 
1762f442ab6aSBarry Smith   Level: advanced
1763f442ab6aSBarry Smith 
1764f1580f4eSBarry Smith   Note:
1765f1580f4eSBarry Smith   This does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid.
1766f442ab6aSBarry Smith 
1767562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()`
1768f442ab6aSBarry Smith @*/
1769d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1770d71ae5a4SJacob Faibussowitsch {
1771f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1772f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1773f442ab6aSBarry Smith   PetscInt       i, levels;
1774f442ab6aSBarry Smith   KSP            subksp;
1775f442ab6aSBarry Smith 
1776f442ab6aSBarry Smith   PetscFunctionBegin;
1777f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
177828b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1779f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1780f442ab6aSBarry Smith 
1781f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1782710315b6SLawrence Mitchell     const char *prefix = NULL;
1783f442ab6aSBarry Smith     /* make sure smoother up and down are different */
17849566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
17859566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
17869566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
17879566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1788f442ab6aSBarry Smith   }
17893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1790f442ab6aSBarry Smith }
1791f442ab6aSBarry Smith 
179207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
179366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1794d71ae5a4SJacob Faibussowitsch {
179507a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
179607a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
179707a4832bSFande Kong   Mat           *mat;
179807a4832bSFande Kong   PetscInt       l;
179907a4832bSFande Kong 
180007a4832bSFande Kong   PetscFunctionBegin;
180128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
180307a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
180407a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
18059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
180607a4832bSFande Kong   }
180707a4832bSFande Kong   *num_levels     = mg->nlevels;
180807a4832bSFande Kong   *interpolations = mat;
18093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
181007a4832bSFande Kong }
181107a4832bSFande Kong 
181207a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
181366976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1814d71ae5a4SJacob Faibussowitsch {
181507a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
181607a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
181707a4832bSFande Kong   PetscInt       l;
181807a4832bSFande Kong   Mat           *mat;
181907a4832bSFande Kong 
182007a4832bSFande Kong   PetscFunctionBegin;
182128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
182307a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
1824f4f49eeaSPierre Jolivet     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l]));
18259566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
182607a4832bSFande Kong   }
182707a4832bSFande Kong   *num_levels      = mg->nlevels;
182807a4832bSFande Kong   *coarseOperators = mat;
18293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183007a4832bSFande Kong }
183107a4832bSFande Kong 
1832f3b08a26SMatthew G. Knepley /*@C
1833f1580f4eSBarry Smith   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1834f3b08a26SMatthew G. Knepley 
1835cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1836f3b08a26SMatthew G. Knepley 
1837f3b08a26SMatthew G. Knepley   Input Parameters:
1838f3b08a26SMatthew G. Knepley + name     - name of the constructor
1839f3b08a26SMatthew G. Knepley - function - constructor routine
1840f3b08a26SMatthew G. Knepley 
184120f4b53cSBarry Smith   Calling sequence of `function`:
184220f4b53cSBarry Smith + pc        - The `PC` object
1843f1580f4eSBarry Smith . l         - The multigrid level, 0 is the coarse level
184420f4b53cSBarry Smith . dm        - The `DM` for this level
1845f1580f4eSBarry Smith . smooth    - The level smoother
1846f1580f4eSBarry Smith . Nc        - The size of the coarse space
1847f1580f4eSBarry Smith . initGuess - Basis for an initial guess for the space
1848f1580f4eSBarry Smith - coarseSp  - A basis for the computed coarse space
1849f3b08a26SMatthew G. Knepley 
1850f3b08a26SMatthew G. Knepley   Level: advanced
1851f3b08a26SMatthew G. Knepley 
1852feefa0e1SJacob Faibussowitsch   Developer Notes:
1853f1580f4eSBarry Smith   How come this is not used by `PCGAMG`?
1854f1580f4eSBarry Smith 
1855562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1856f3b08a26SMatthew G. Knepley @*/
185704c3f3b8SBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp))
1858d71ae5a4SJacob Faibussowitsch {
1859f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18609566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18619566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
18623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1863f3b08a26SMatthew G. Knepley }
1864f3b08a26SMatthew G. Knepley 
1865f3b08a26SMatthew G. Knepley /*@C
1866f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1867f3b08a26SMatthew G. Knepley 
1868cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1869f3b08a26SMatthew G. Knepley 
1870f3b08a26SMatthew G. Knepley   Input Parameter:
1871f3b08a26SMatthew G. Knepley . name - name of the constructor
1872f3b08a26SMatthew G. Knepley 
1873f3b08a26SMatthew G. Knepley   Output Parameter:
1874f3b08a26SMatthew G. Knepley . function - constructor routine
1875f3b08a26SMatthew G. Knepley 
1876f3b08a26SMatthew G. Knepley   Level: advanced
1877f3b08a26SMatthew G. Knepley 
1878562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1879f3b08a26SMatthew G. Knepley @*/
1880d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *))
1881d71ae5a4SJacob Faibussowitsch {
1882f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18839566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
18843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1885f3b08a26SMatthew G. Knepley }
1886f3b08a26SMatthew G. Knepley 
18873b09bd56SBarry Smith /*MC
1888ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
18893b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
18903b09bd56SBarry Smith 
18913b09bd56SBarry Smith    Options Database Keys:
18923b09bd56SBarry Smith +  -pc_mg_levels <nlevels>                            - number of levels including finest
1893391689abSStefano Zampini .  -pc_mg_cycle_type <v,w>                            - provide the cycle desired
18948c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
18953b09bd56SBarry Smith .  -pc_mg_log                                         - log information about time spent on each level of the solver
1896710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup                           - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
18972134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>               - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
18988cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles                        - number of cycles to use as the preconditioner (defaults to 1)
18998cf6037eSBarry Smith .  -pc_mg_dump_matlab                                  - dumps the matrices for each level and the restriction/interpolation matrices
1900a3b724e8SBarry Smith                                                          to a `PETSCVIEWERSOCKET` for reading from MATLAB.
19018cf6037eSBarry Smith -  -pc_mg_dump_binary                                  -dumps the matrices for each level and the restriction/interpolation matrices
19028cf6037eSBarry Smith                                                         to the binary output file called binaryoutput
19033b09bd56SBarry Smith 
190420f4b53cSBarry Smith    Level: intermediate
190520f4b53cSBarry Smith 
190695452b02SPatrick Sanan    Notes:
190704c3f3b8SBarry Smith    The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard
19088f4fb22eSMark Adams    options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`,
19098f4fb22eSMark Adams    and the finest where `-mg_fine_` can override `-mg_levels_`.  One can set different preconditioners etc on specific levels with the prefix
19108f4fb22eSMark Adams    `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example
191104c3f3b8SBarry Smith .vb
191204c3f3b8SBarry Smith    -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor
191304c3f3b8SBarry Smith .ve
191404c3f3b8SBarry Smith    These options also work for controlling the smoothers etc inside `PCGAMG`
191504c3f3b8SBarry Smith 
1916f1580f4eSBarry Smith    If one uses a Krylov method such `KSPGMRES` or `KSPCG` as the smoother then one must use `KSPFGMRES`, `KSPGCR`, or `KSPRICHARDSON` as the outer Krylov method
19173b09bd56SBarry Smith 
19188cf6037eSBarry Smith    When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19198cf6037eSBarry Smith 
1920f1580f4eSBarry Smith    When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
192123067569SBarry Smith    is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
192223067569SBarry Smith    (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
192323067569SBarry Smith    residual is computed at the end of each cycle.
192423067569SBarry Smith 
192504c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1926db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1927db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1928db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1929f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1930f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19313b09bd56SBarry Smith M*/
19323b09bd56SBarry Smith 
1933d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1934d71ae5a4SJacob Faibussowitsch {
1935f3fbd535SBarry Smith   PC_MG *mg;
1936f3fbd535SBarry Smith 
19374b9ad928SBarry Smith   PetscFunctionBegin;
19384dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
19393ec1f749SStefano Zampini   pc->data               = mg;
1940f3fbd535SBarry Smith   mg->nlevels            = -1;
194110eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19422134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1943f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1944f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1945f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1946f3fbd535SBarry Smith 
194737a44384SMark Adams   pc->useAmat = PETSC_TRUE;
194837a44384SMark Adams 
19494b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1950fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
195130b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
19524b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1953a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
19544b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
19554b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
19564b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1957fb15c04eSBarry Smith 
19589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
19599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
19609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
19682b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
19692b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
19703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19714b9ad928SBarry Smith }
1972