xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision e87b5d96567786df49b4af65cff3120eb2cdf5c2)
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) {
10720654ebbSStefano Zampini       Mat crA;
10820654ebbSStefano Zampini 
10928b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
11041b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1119566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1129566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
11320654ebbSStefano Zampini       PetscCall(KSPGetOperators(mglevels->cr, &crA, NULL));
11420654ebbSStefano Zampini       PetscCall(KSPSetNoisy_Private(crA, mglevels->crx));
1159566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1169566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11741b6fd38SMatthew G. Knepley     }
1189566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1194b9ad928SBarry Smith   }
1203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1214b9ad928SBarry Smith }
1224b9ad928SBarry Smith 
123d71ae5a4SJacob 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)
124d71ae5a4SJacob Faibussowitsch {
125f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
126f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
127391689abSStefano Zampini   PC             tpc;
128391689abSStefano Zampini   PetscBool      changeu, changed;
129f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
1304b9ad928SBarry Smith 
1314b9ad928SBarry Smith   PetscFunctionBegin;
132a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
133a762d673SBarry Smith   for (i = 0; i < levels; i++) {
134a762d673SBarry Smith     if (!mglevels[i]->A) {
1359566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1369566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
137a762d673SBarry Smith     }
138a762d673SBarry Smith   }
139391689abSStefano Zampini 
1409566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1419566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1429566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1439566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
144391689abSStefano Zampini   if (!changed && !changeu) {
1459566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels - 1]->b));
146f3fbd535SBarry Smith     mglevels[levels - 1]->b = b;
147391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
148391689abSStefano Zampini     if (!mglevels[levels - 1]->b) {
149391689abSStefano Zampini       Vec *vec;
150391689abSStefano Zampini 
1519566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
152391689abSStefano Zampini       mglevels[levels - 1]->b = *vec;
1539566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
154391689abSStefano Zampini     }
1559566063dSJacob Faibussowitsch     PetscCall(VecCopy(b, mglevels[levels - 1]->b));
156391689abSStefano Zampini   }
157f3fbd535SBarry Smith   mglevels[levels - 1]->x = x;
1584b9ad928SBarry Smith 
15931567311SBarry Smith   mg->rtol   = rtol;
16031567311SBarry Smith   mg->abstol = abstol;
16131567311SBarry Smith   mg->dtol   = dtol;
1624b9ad928SBarry Smith   if (rtol) {
1634b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1644b9ad928SBarry Smith     PetscReal rnorm;
1657319c654SBarry Smith     if (zeroguess) {
1669566063dSJacob Faibussowitsch       PetscCall(VecNorm(b, NORM_2, &rnorm));
1677319c654SBarry Smith     } else {
1689566063dSJacob Faibussowitsch       PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1699566063dSJacob Faibussowitsch       PetscCall(VecNorm(w, NORM_2, &rnorm));
1707319c654SBarry Smith     }
17131567311SBarry Smith     mg->ttol = PetscMax(rtol * rnorm, abstol);
1722fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1732fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1744b9ad928SBarry Smith 
1754d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
176336babb1SJed Brown      stop prematurely due to small residual */
1774d0a8057SBarry Smith   for (i = 1; i < levels; i++) {
178fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
179f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
18023067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1819566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
182fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
1834b9ad928SBarry Smith     }
1844d0a8057SBarry Smith   }
1854d0a8057SBarry Smith 
186dd460d27SBarry Smith   *reason = PCRICHARDSON_NOT_SET;
1874d0a8057SBarry Smith   for (i = 0; i < its; i++) {
1889566063dSJacob Faibussowitsch     PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1894d0a8057SBarry Smith     if (*reason) break;
1904d0a8057SBarry Smith   }
191dd460d27SBarry Smith   if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS;
1924d0a8057SBarry Smith   *outits = i;
193391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1954b9ad928SBarry Smith }
1964b9ad928SBarry Smith 
197d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc)
198d71ae5a4SJacob Faibussowitsch {
1993aeaf226SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
2003aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
2012b3cbbdaSStefano Zampini   PetscInt       i, n;
2023aeaf226SBarry Smith 
2033aeaf226SBarry Smith   PetscFunctionBegin;
2043aeaf226SBarry Smith   if (mglevels) {
2053aeaf226SBarry Smith     n = mglevels[0]->levels;
2063aeaf226SBarry Smith     for (i = 0; i < n - 1; i++) {
2079566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->r));
2089566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->b));
2099566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->x));
2109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->R));
2119566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->B));
2129566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->X));
2139566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crx));
2149566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crb));
2159566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2169566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2179566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2189566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2193aeaf226SBarry Smith     }
2209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2219566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crb));
222391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
223391689abSStefano Zampini        changes the rhs during PreSolve */
2249566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->b));
2259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mglevels[n - 1]->B));
2263aeaf226SBarry Smith 
2273aeaf226SBarry Smith     for (i = 0; i < n; i++) {
2282b3cbbdaSStefano Zampini       PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2299566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->A));
23048a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2319566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2329566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2333aeaf226SBarry Smith     }
234f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2353aeaf226SBarry Smith   }
2363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2373aeaf226SBarry Smith }
2383aeaf226SBarry Smith 
23941b6fd38SMatthew G. Knepley /* Implementing CR
24041b6fd38SMatthew G. Knepley 
24141b6fd38SMatthew 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
24241b6fd38SMatthew G. Knepley 
24341b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
24441b6fd38SMatthew G. Knepley 
24541b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24641b6fd38SMatthew G. Knepley 
24741b6fd38SMatthew G. Knepley   Inj^T Inj
24841b6fd38SMatthew G. Knepley 
24941b6fd38SMatthew G. Knepley and
25041b6fd38SMatthew G. Knepley 
25141b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
25241b6fd38SMatthew G. Knepley 
25341b6fd38SMatthew G. Knepley since
25441b6fd38SMatthew G. Knepley 
25541b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
25641b6fd38SMatthew G. Knepley 
25741b6fd38SMatthew G. Knepley Brannick suggests
25841b6fd38SMatthew G. Knepley 
25941b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
26041b6fd38SMatthew G. Knepley 
26141b6fd38SMatthew 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
26241b6fd38SMatthew G. Knepley 
26341b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
26441b6fd38SMatthew G. Knepley 
26541b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26641b6fd38SMatthew G. Knepley 
26741b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
26841b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
26941b6fd38SMatthew G. Knepley */
27041b6fd38SMatthew G. Knepley 
27141b6fd38SMatthew G. Knepley typedef struct {
27241b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
27341b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
27441b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27541b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
27641b6fd38SMatthew G. Knepley } CRContext;
27741b6fd38SMatthew G. Knepley 
278d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc)
279d71ae5a4SJacob Faibussowitsch {
28041b6fd38SMatthew G. Knepley   CRContext *ctx;
28141b6fd38SMatthew G. Knepley   Mat        It;
28241b6fd38SMatthew G. Knepley 
28341b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2849566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2859566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28628b400f6SJacob Faibussowitsch   PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2879566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2889566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2899566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2909566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S, 1.0));
2913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29241b6fd38SMatthew G. Knepley }
29341b6fd38SMatthew G. Knepley 
294d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
295d71ae5a4SJacob Faibussowitsch {
29641b6fd38SMatthew G. Knepley   CRContext *ctx;
29741b6fd38SMatthew G. Knepley 
29841b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2999566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3009566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
3013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30241b6fd38SMatthew G. Knepley }
30341b6fd38SMatthew G. Knepley 
304d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc)
305d71ae5a4SJacob Faibussowitsch {
30641b6fd38SMatthew G. Knepley   CRContext *ctx;
30741b6fd38SMatthew G. Knepley 
30841b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3099566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3129566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3139566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
3143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31541b6fd38SMatthew G. Knepley }
31641b6fd38SMatthew G. Knepley 
317d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
318d71ae5a4SJacob Faibussowitsch {
31941b6fd38SMatthew G. Knepley   CRContext *ctx;
32041b6fd38SMatthew G. Knepley 
32141b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3229566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3239566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3249566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
32541b6fd38SMatthew G. Knepley   ctx->mg = pc;
32641b6fd38SMatthew G. Knepley   ctx->l  = l;
3279566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3289566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3299566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3309566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3319566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
3323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33341b6fd38SMatthew G. Knepley }
33441b6fd38SMatthew G. Knepley 
3358f4fb22eSMark Adams PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *);
3368f4fb22eSMark Adams 
337d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms)
338d71ae5a4SJacob Faibussowitsch {
339f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG *)pc->data;
340ce94432eSBarry Smith   MPI_Comm       comm;
3413aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
34210eca3edSLisandro Dalcin   PCMGType       mgtype   = mg->am;
34310167fecSBarry Smith   PetscInt       mgctype  = (PetscInt)PC_MG_CYCLE_V;
344f3fbd535SBarry Smith   PetscInt       i;
345f3fbd535SBarry Smith   PetscMPIInt    size;
346f3fbd535SBarry Smith   const char    *prefix;
347f3fbd535SBarry Smith   PC             ipc;
3483aeaf226SBarry Smith   PetscInt       n;
3494b9ad928SBarry Smith 
3504b9ad928SBarry Smith   PetscFunctionBegin;
3510700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
352548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc, levels, 2);
3533ba16761SJacob Faibussowitsch   if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS);
3549566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3553aeaf226SBarry Smith   if (mglevels) {
35610eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
3573aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
3589566063dSJacob Faibussowitsch     PetscCall(PCReset_MG(pc));
3593aeaf226SBarry Smith     n = mglevels[0]->levels;
3603aeaf226SBarry Smith     for (i = 0; i < n; i++) {
36148a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3629566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3639566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3649566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3653aeaf226SBarry Smith     }
3669566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3673aeaf226SBarry Smith   }
368f3fbd535SBarry Smith 
369f3fbd535SBarry Smith   mg->nlevels = levels;
370f3fbd535SBarry Smith 
3719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels, &mglevels));
372f3fbd535SBarry Smith 
3739566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
374f3fbd535SBarry Smith 
375a9db87a2SMatthew G Knepley   mg->stageApply = 0;
376f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
3774dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mglevels[i]));
3782fa5cd67SKarl Rupp 
379f3fbd535SBarry Smith     mglevels[i]->level               = i;
380f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
38110eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
382336babb1SJed Brown     mg->default_smoothu              = 2;
383336babb1SJed Brown     mg->default_smoothd              = 2;
38463e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
38563e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
38663e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
38763e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
388f3fbd535SBarry Smith 
389f3fbd535SBarry Smith     if (comms) comm = comms[i];
390d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3919566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3923821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel));
3939566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3949566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3959566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3969566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3978f4fb22eSMark Adams       if (i == 0 && levels > 1) { // coarse grid
3989566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
399f3fbd535SBarry Smith 
4009dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4019566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4029566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4039566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
404f3fbd535SBarry Smith         if (size > 1) {
4059566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
406f3fbd535SBarry Smith         } else {
4079566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
408f3fbd535SBarry Smith         }
4099566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
4108f4fb22eSMark Adams       } else {
4118f4fb22eSMark Adams         char tprefix[128];
4128f4fb22eSMark Adams 
4138f4fb22eSMark Adams         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
4148f4fb22eSMark Adams         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
4158f4fb22eSMark Adams         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
4168f4fb22eSMark Adams         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
4178f4fb22eSMark Adams         PetscCall(PCSetType(ipc, PCSOR));
418fb842aefSJose E. Roman         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
4198f4fb22eSMark Adams 
4208f4fb22eSMark Adams         if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_'
4218f4fb22eSMark Adams           PetscBool set;
4228f4fb22eSMark Adams           PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set));
4238f4fb22eSMark Adams           if (set) {
4248f4fb22eSMark Adams             if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix));
4258f4fb22eSMark Adams             else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_"));
4268f4fb22eSMark Adams             PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix));
4278f4fb22eSMark Adams           } else {
428835f2295SStefano Zampini             PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4298f4fb22eSMark Adams             PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4308f4fb22eSMark Adams           }
4318f4fb22eSMark Adams         } else {
432835f2295SStefano Zampini           PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4338f4fb22eSMark Adams           PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4348f4fb22eSMark Adams         }
435f3fbd535SBarry Smith       }
436d5a8f7e6SBarry Smith     }
437f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
43831567311SBarry Smith     mg->rtol             = 0.0;
43931567311SBarry Smith     mg->abstol           = 0.0;
44031567311SBarry Smith     mg->dtol             = 0.0;
44131567311SBarry Smith     mg->ttol             = 0.0;
44231567311SBarry Smith     mg->cyclesperpcapply = 1;
443f3fbd535SBarry Smith   }
444f3fbd535SBarry Smith   mg->levels = mglevels;
4459566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4474b9ad928SBarry Smith }
4484b9ad928SBarry Smith 
44997d33e41SMatthew G. Knepley /*@C
450f1580f4eSBarry Smith   PCMGSetLevels - Sets the number of levels to use with `PCMG`.
451f1580f4eSBarry Smith   Must be called before any other `PCMG` routine.
45297d33e41SMatthew G. Knepley 
453c3339decSBarry Smith   Logically Collective
45497d33e41SMatthew G. Knepley 
45597d33e41SMatthew G. Knepley   Input Parameters:
45697d33e41SMatthew G. Knepley + pc     - the preconditioner context
45797d33e41SMatthew G. Knepley . levels - the number of levels
45897d33e41SMatthew G. Knepley - comms  - optional communicators for each level; this is to allow solving the coarser problems
459d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
46020f4b53cSBarry Smith            you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes
46105552d4bSJunchao Zhang            should participate in each level of problem.
46297d33e41SMatthew G. Knepley 
46397d33e41SMatthew G. Knepley   Level: intermediate
46497d33e41SMatthew G. Knepley 
46597d33e41SMatthew G. Knepley   Notes:
46620f4b53cSBarry Smith   If the number of levels is one then the multigrid uses the `-mg_levels` prefix
4678f4fb22eSMark Adams   for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix.
46897d33e41SMatthew G. Knepley 
469d5a8f7e6SBarry Smith   You can free the information in comms after this routine is called.
470d5a8f7e6SBarry Smith 
471f1580f4eSBarry Smith   The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
472d5a8f7e6SBarry Smith   are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
473d5a8f7e6SBarry Smith   the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
474d5a8f7e6SBarry Smith   of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
475f1580f4eSBarry Smith   the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
476d5a8f7e6SBarry Smith   in the coarse grid solve.
477d5a8f7e6SBarry Smith 
478f1580f4eSBarry Smith   Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
479d5a8f7e6SBarry Smith   must take special care in providing the restriction and interpolation operation. We recommend
480d5a8f7e6SBarry Smith   providing these as two step operations; first perform a standard restriction or interpolation on
481d5a8f7e6SBarry Smith   the full number of ranks for that level and then use an MPI call to copy the resulting vector
48205552d4bSJunchao Zhang   array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
483d5a8f7e6SBarry Smith   cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
48420f4b53cSBarry Smith   receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries.
485d5a8f7e6SBarry Smith 
486feefa0e1SJacob Faibussowitsch   Fortran Notes:
48720f4b53cSBarry Smith   Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM`
488f1580f4eSBarry Smith   is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
489d5a8f7e6SBarry Smith 
490562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()`
49197d33e41SMatthew G. Knepley @*/
492d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms)
493d71ae5a4SJacob Faibussowitsch {
49497d33e41SMatthew G. Knepley   PetscFunctionBegin;
49597d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4964f572ea9SToby Isaac   if (comms) PetscAssertPointer(comms, 3);
497cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
4983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49997d33e41SMatthew G. Knepley }
50097d33e41SMatthew G. Knepley 
501d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc)
502d71ae5a4SJacob Faibussowitsch {
503a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
504a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
505a06653b4SBarry Smith   PetscInt       i, n;
506c07bf074SBarry Smith 
507c07bf074SBarry Smith   PetscFunctionBegin;
5089566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
509a06653b4SBarry Smith   if (mglevels) {
510a06653b4SBarry Smith     n = mglevels[0]->levels;
511a06653b4SBarry Smith     for (i = 0; i < n; i++) {
51248a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
5139566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
5149566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
5159566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
516a06653b4SBarry Smith     }
5179566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
518a06653b4SBarry Smith   }
5199566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5222b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
5232b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5242b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5252b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5262b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5272b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5282b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5292b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5302b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5312b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5322b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
534f3fbd535SBarry Smith }
535f3fbd535SBarry Smith 
536f3fbd535SBarry Smith /*
537f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
538f3fbd535SBarry Smith              or full cycle of multigrid.
539f3fbd535SBarry Smith 
540f3fbd535SBarry Smith   Note:
541f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
542f3fbd535SBarry Smith */
543d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
544d71ae5a4SJacob Faibussowitsch {
545f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
546f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
547391689abSStefano Zampini   PC             tpc;
548f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
54930b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
550f3fbd535SBarry Smith 
551f3fbd535SBarry Smith   PetscFunctionBegin;
55230b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5539566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
554e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
555298cc208SBarry Smith   for (i = 0; i < levels; i++) {
556e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5579566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5589566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
559e1d8e5deSBarry Smith     }
560e1d8e5deSBarry Smith   }
561e1d8e5deSBarry Smith 
5629566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5639566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5649566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5659566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
566391689abSStefano Zampini   if (!changeu && !changed) {
56730b0564aSStefano Zampini     if (matapp) {
5689566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
56930b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
57030b0564aSStefano Zampini     } else {
5719566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
572f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
57330b0564aSStefano Zampini     }
574391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
57530b0564aSStefano Zampini     if (matapp) {
57630b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
57730b0564aSStefano Zampini         PetscInt  N1, N2;
57830b0564aSStefano Zampini         PetscBool flg;
57930b0564aSStefano Zampini 
5809566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5819566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5829566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
58348a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
58430b0564aSStefano Zampini       }
58530b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5869566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
58730b0564aSStefano Zampini       } else {
5889566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
58930b0564aSStefano Zampini       }
59030b0564aSStefano Zampini     } else {
591391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
592391689abSStefano Zampini         Vec *vec;
593391689abSStefano Zampini 
5949566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
595391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5969566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
597391689abSStefano Zampini       }
5989566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
599391689abSStefano Zampini     }
60030b0564aSStefano Zampini   }
6019371c9d4SSatish Balay   if (matapp) {
6029371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
6039371c9d4SSatish Balay   } else {
6049371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
6059371c9d4SSatish Balay   }
60630b0564aSStefano Zampini 
60730b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
60830b0564aSStefano Zampini      Reset operators if sizes/type do no match */
60930b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
61030b0564aSStefano Zampini     PetscInt  Xc, Bc;
61130b0564aSStefano Zampini     PetscBool flg;
61230b0564aSStefano Zampini 
6139566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
6149566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
6159566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
61630b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6179566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
61830b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
6199566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6209566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6219566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
62230b0564aSStefano Zampini       }
62330b0564aSStefano Zampini     }
62430b0564aSStefano Zampini   }
625391689abSStefano Zampini 
62631567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6279566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6289566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
62948a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6302fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6319566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6322fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6339566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6342fa5cd67SKarl Rupp   } else {
6359566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
636f3fbd535SBarry Smith   }
6379566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
63830b0564aSStefano Zampini   if (!changeu && !changed) {
6399371c9d4SSatish Balay     if (matapp) {
6409371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6419371c9d4SSatish Balay     } else {
6429371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6439371c9d4SSatish Balay     }
64430b0564aSStefano Zampini   }
6453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
646f3fbd535SBarry Smith }
647f3fbd535SBarry Smith 
648d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
649d71ae5a4SJacob Faibussowitsch {
650fcb023d4SJed Brown   PetscFunctionBegin;
6519566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
653fcb023d4SJed Brown }
654fcb023d4SJed Brown 
655d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
656d71ae5a4SJacob Faibussowitsch {
657fcb023d4SJed Brown   PetscFunctionBegin;
6589566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66030b0564aSStefano Zampini }
66130b0564aSStefano Zampini 
662d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
663d71ae5a4SJacob Faibussowitsch {
66430b0564aSStefano Zampini   PetscFunctionBegin;
6659566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
667fcb023d4SJed Brown }
668f3fbd535SBarry Smith 
669ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject)
670d71ae5a4SJacob Faibussowitsch {
671710315b6SLawrence Mitchell   PetscInt            levels, cycles;
672f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
673f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6743d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
675f3fbd535SBarry Smith   PCMGType            mgtype;
676f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6772134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6782b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
679f3fbd535SBarry Smith 
680f3fbd535SBarry Smith   PetscFunctionBegin;
6811d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
682d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6841a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6859566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
686eb3f98d2SBarry Smith     levels++;
6873aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
688eb3f98d2SBarry Smith   }
6899566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6903aeaf226SBarry Smith   mglevels = mg->levels;
6913aeaf226SBarry Smith 
692f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
6939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
6941baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
6952b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6962b3cbbdaSStefano 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));
6972b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
6989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
6999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
70041b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
7019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
7029566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
703f56b1265SBarry Smith   flg = PETSC_FALSE;
7049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
7051baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
7065544a5bcSStefano Zampini   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)&gtype, &flg));
7075544a5bcSStefano Zampini   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
70831567311SBarry Smith   mgtype = mg->am;
7099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
7101baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
71131567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
7129566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
7131baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
714f3fbd535SBarry Smith   }
715f3fbd535SBarry Smith   flg = PETSC_FALSE;
7169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
717f3fbd535SBarry Smith   if (flg) {
718f3fbd535SBarry Smith     PetscInt i;
719f3fbd535SBarry Smith     char     eventname[128];
7201a97d7b6SStefano Zampini 
721f3fbd535SBarry Smith     levels = mglevels[0]->levels;
722f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
723835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i));
7249566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
725835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i));
7269566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
727f3fbd535SBarry Smith       if (i) {
728835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i));
7299566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
730835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i));
7319566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
732f3fbd535SBarry Smith       }
733f3fbd535SBarry Smith     }
734eec35531SMatthew G Knepley 
7352611ad71SToby Isaac     if (PetscDefined(USE_LOG)) {
7362611ad71SToby Isaac       const char sname[] = "MG Apply";
737eec35531SMatthew G Knepley 
7382611ad71SToby Isaac       PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
7392611ad71SToby Isaac       if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
740eec35531SMatthew G Knepley     }
741f3fbd535SBarry Smith   }
742d0609cedSBarry Smith   PetscOptionsHeadEnd();
743f3b08a26SMatthew G. Knepley   /* Check option consistency */
7449566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7459566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
74608401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
748f3fbd535SBarry Smith }
749f3fbd535SBarry Smith 
7500a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7510a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7520a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7532b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
754f3fbd535SBarry Smith 
7559804daf3SBarry Smith #include <petscdraw.h>
756d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
757d71ae5a4SJacob Faibussowitsch {
758f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
759f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
760e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
761219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
762f3fbd535SBarry Smith 
763f3fbd535SBarry Smith   PetscFunctionBegin;
7649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
767f3fbd535SBarry Smith   if (iascii) {
768e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
76963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
77048a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7712134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7729566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7732134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7749566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7752134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7769566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7772134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7789566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7794f66f45eSBarry Smith     } else {
7809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
781f3fbd535SBarry Smith     }
7821baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
783f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
78463a3b9bcSJacob Faibussowitsch       if (i) {
78563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
786f3fbd535SBarry Smith       } else {
78763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
788f3fbd535SBarry Smith       }
7899566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7909566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
792f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
7939566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
794f3fbd535SBarry Smith       } else if (i) {
79563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
7969566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
7979566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
7989566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
799f3fbd535SBarry Smith       }
80041b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
80163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
8029566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8039566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
8049566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
80541b6fd38SMatthew G. Knepley       }
806f3fbd535SBarry Smith     }
8075b0b0462SBarry Smith   } else if (isbinary) {
8085b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
8099566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
81048a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8115b0b0462SBarry Smith     }
812219b1045SBarry Smith   } else if (isdraw) {
813219b1045SBarry Smith     PetscDraw draw;
814b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
8159566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8169566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8179566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
818219b1045SBarry Smith     bottom = y - th;
819219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
820b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8219566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8229566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8239566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
824b4375e8dSPeter Brune       } else {
825b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8269566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8279566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8289566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8299566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8309566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8319566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
832b4375e8dSPeter Brune       }
8339566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8341cd381d6SBarry Smith       bottom -= th;
835219b1045SBarry Smith     }
8365b0b0462SBarry Smith   }
8373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
838f3fbd535SBarry Smith }
839f3fbd535SBarry Smith 
840af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
841cab2e9ccSBarry Smith 
842f3fbd535SBarry Smith /*
843f3fbd535SBarry Smith     Calls setup for the KSP on each level
844f3fbd535SBarry Smith */
845d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
846d71ae5a4SJacob Faibussowitsch {
847f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
848f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8491a97d7b6SStefano Zampini   PetscInt       i, n;
85098e04984SBarry Smith   PC             cpc;
8513db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
852f3fbd535SBarry Smith   Mat            dA, dB;
853f3fbd535SBarry Smith   Vec            tvec;
854218a07d4SBarry Smith   DM            *dms;
8550a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
85641b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8572b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
858f3fbd535SBarry Smith 
859f3fbd535SBarry Smith   PetscFunctionBegin;
86028b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8611a97d7b6SStefano Zampini   n = mglevels[0]->levels;
86201bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8633aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8643aeaf226SBarry Smith     PetscInt levels;
8659566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8663aeaf226SBarry Smith     levels++;
8673aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8689566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8693aeaf226SBarry Smith       n = levels;
8709566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8713aeaf226SBarry Smith       mglevels = mg->levels;
8723aeaf226SBarry Smith     }
8733aeaf226SBarry Smith   }
8749566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd, &cpc));
8753aeaf226SBarry Smith 
876f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
877f3fbd535SBarry Smith   /* so use those from global PC */
878f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8799566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
88098e04984SBarry Smith   if (opsset) {
88198e04984SBarry Smith     Mat mmat;
8829566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
88398e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
88498e04984SBarry Smith   }
8854a5f07a5SMark F. Adams 
88641b6fd38SMatthew G. Knepley   /* Create CR solvers */
8879566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
88841b6fd38SMatthew G. Knepley   if (doCR) {
88941b6fd38SMatthew G. Knepley     const char *prefix;
89041b6fd38SMatthew G. Knepley 
8919566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
89241b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
89341b6fd38SMatthew G. Knepley       PC   ipc, cr;
89441b6fd38SMatthew G. Knepley       char crprefix[128];
89541b6fd38SMatthew G. Knepley 
8969566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
8973821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
8989566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
8999566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
9009566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
9019566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
9029566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9039566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9049566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9059566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
90641b6fd38SMatthew G. Knepley 
9079566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
9089566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9099566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9109566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
9119566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
9129566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
91341b6fd38SMatthew G. Knepley 
914fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
9159566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
916835f2295SStefano Zampini       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i));
9179566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
91841b6fd38SMatthew G. Knepley     }
91941b6fd38SMatthew G. Knepley   }
92041b6fd38SMatthew G. Knepley 
9214a5f07a5SMark F. Adams   if (!opsset) {
9229566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9234a5f07a5SMark F. Adams     if (use_amat) {
9249566063dSJacob 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"));
9259566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
92669858f1bSStefano Zampini     } else {
9279566063dSJacob 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"));
9289566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9294a5f07a5SMark F. Adams     }
9304a5f07a5SMark F. Adams   }
931f3fbd535SBarry Smith 
9329c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9339c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9349c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9352b3cbbdaSStefano Zampini       break;
9369c7ffb39SBarry Smith     }
9379c7ffb39SBarry Smith   }
9382134b1e4SBarry Smith 
9399566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9402134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9412b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9422134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9432134b1e4SBarry Smith   }
9442134b1e4SBarry Smith 
9452b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9462b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9472b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9482b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9492b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9502b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9512b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9522b3cbbdaSStefano Zampini     }
9532b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9542b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9552b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9562b3cbbdaSStefano Zampini     }
9572b3cbbdaSStefano Zampini   }
9582b3cbbdaSStefano Zampini 
9599c7ffb39SBarry Smith   /*
9609c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9612b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9629c7ffb39SBarry Smith   */
96332fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
96432fe681dSStefano Zampini     /* first see if we can compute a coarse space */
96532fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
96632fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
96732fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
96832fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
96932fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
97032fe681dSStefano Zampini         }
97132fe681dSStefano Zampini       }
97232fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9732e499ae9SBarry Smith       Mat p;
97473250ac0SBarry Smith       Vec rscale;
9759566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
976218a07d4SBarry Smith       dms[n - 1] = pc->dm;
977ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9789566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
979218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
980942e3340SBarry Smith         DMKSP     kdm;
981eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9829566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9839566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
984c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9859566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9869566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
987c27ee7a3SPatrick Farrell         }
98841b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9899566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
9909566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
99141b6fd38SMatthew G. Knepley         }
9929566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
993d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
994d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
9950298fd71SBarry Smith         kdm->ops->computerhs = NULL;
9960298fd71SBarry Smith         kdm->rhsctx          = NULL;
99724c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
9989566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
9999566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
10009566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
10019566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
10029566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1003218a07d4SBarry Smith         }
10049566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
10053ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
10069566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
10079566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
10089566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
10093ad4599aSBarry Smith         }
10109566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
1011eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
10129566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
10139566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
10149566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1015eab52d2bSLawrence Mitchell         }
101624c3aa18SBarry Smith       }
10172d2b81a6SBarry Smith 
10189566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10199566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1020ce4cda84SJed Brown     }
102132fe681dSStefano Zampini   }
1022cab2e9ccSBarry Smith 
10232134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10242134b1e4SBarry Smith     Mat       A, B;
10252134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10262134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10272134b1e4SBarry Smith 
10282b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10292b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10302134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1031f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10327827d75bSBarry 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");
103348a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
103448a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
103548a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
103648a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
103748a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10382134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10392134b1e4SBarry Smith       if (!doA && dAeqdB) {
10409566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10412134b1e4SBarry Smith         A = B;
10422134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10439566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10449566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1045b9367914SBarry Smith       }
10462134b1e4SBarry Smith       if (!doB && dAeqdB) {
10479566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10482134b1e4SBarry Smith         B = A;
10492134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10509566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10519566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10527d537d92SJed Brown       }
10532134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10549566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10559566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10569566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10572134b1e4SBarry Smith       }
10582134b1e4SBarry Smith       dA = A;
1059f3fbd535SBarry Smith       dB = B;
1060f3fbd535SBarry Smith     }
1061f3fbd535SBarry Smith   }
1062f3b08a26SMatthew G. Knepley 
1063f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10642b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1065f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
106648a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10672b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1068f3b08a26SMatthew G. Knepley     }
106948a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1070f3b08a26SMatthew G. Knepley   }
1071f3b08a26SMatthew G. Knepley 
10722134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1073caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1074ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1075caa4e7f2SJed Brown       Mat Restrict, Inject;
1076caa4e7f2SJed Brown       Vec rscale;
10779566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10789566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10799566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10809566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10819566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10829566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1083caa4e7f2SJed Brown     }
1084caa4e7f2SJed Brown   }
1085f3fbd535SBarry Smith 
1086f3fbd535SBarry Smith   if (!pc->setupcalled) {
108748a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1088f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
108948a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
109048a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1091f3fbd535SBarry Smith     }
109215229ffcSPierre Jolivet     /* insure that if either interpolation or restriction is set the other one is set */
1093f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
10949566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
10959566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1096f3fbd535SBarry Smith     }
1097f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1098f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1099f3fbd535SBarry Smith         Vec *vec;
11009566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
11019566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
11029566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
11039566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1104f3fbd535SBarry Smith       }
1105f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
11069566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11079566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
11089566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1109f3fbd535SBarry Smith       }
1110f3fbd535SBarry Smith       if (!mglevels[i]->x) {
11119566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11129566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
11139566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1114f3fbd535SBarry Smith       }
111541b6fd38SMatthew G. Knepley       if (doCR) {
11169566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11179566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11189566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
111941b6fd38SMatthew G. Knepley       }
1120f3fbd535SBarry Smith     }
1121f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1122f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1123f3fbd535SBarry Smith       Vec *vec;
11249566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11259566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11269566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11279566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1128f3fbd535SBarry Smith     }
112941b6fd38SMatthew G. Knepley     if (doCR) {
11309566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11319566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11329566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
113341b6fd38SMatthew G. Knepley     }
1134f3fbd535SBarry Smith   }
1135f3fbd535SBarry Smith 
113698e04984SBarry Smith   if (pc->dm) {
113798e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
113898e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
113998e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
114098e04984SBarry Smith     }
114198e04984SBarry Smith   }
114208549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
114308549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
114408549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1145f3fbd535SBarry Smith 
1146f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11472a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1148f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11499566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1150f3fbd535SBarry Smith     }
11519566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11529566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11539566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1154d4645a75SStefano Zampini     if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11559566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1156d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1157d42688cbSBarry Smith       Mat mat;
11589566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11599566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1160d42688cbSBarry Smith     }
1161fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1162fcb023d4SJed Brown       Mat mat;
11639566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11649566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1165fcb023d4SJed Brown     }
1166f3fbd535SBarry Smith   }
1167f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1168f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1169f3fbd535SBarry Smith       Mat downmat, downpmat;
1170f3fbd535SBarry Smith 
1171f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11729566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1173f3fbd535SBarry Smith       if (!opsset) {
11749566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11759566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1176f3fbd535SBarry Smith       }
1177f3fbd535SBarry Smith 
11789566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11799566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11809566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1181d4645a75SStefano Zampini       if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
11829566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1183f3fbd535SBarry Smith     }
118441b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
118541b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
118641b6fd38SMatthew G. Knepley 
118741b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
11889566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
118941b6fd38SMatthew G. Knepley       if (!opsset) {
11909566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11919566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
119241b6fd38SMatthew G. Knepley       }
119341b6fd38SMatthew G. Knepley 
11949566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11959566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11969566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1197d4645a75SStefano Zampini       if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
11989566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
119941b6fd38SMatthew G. Knepley     }
1200f3fbd535SBarry Smith   }
1201f3fbd535SBarry Smith 
12029566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
12039566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1204d4645a75SStefano Zampini   if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
12059566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1206f3fbd535SBarry Smith 
1207f3fbd535SBarry Smith   /*
1208f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1209e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1210f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1211f3fbd535SBarry Smith 
1212f3fbd535SBarry Smith    Only support one or the other at the same time.
1213f3fbd535SBarry Smith   */
1214f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1216ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1217f3fbd535SBarry Smith   dump = PETSC_FALSE;
1218f3fbd535SBarry Smith #endif
12199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1220ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1221f3fbd535SBarry Smith 
1222f3fbd535SBarry Smith   if (viewer) {
122348a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1224f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12259566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12269566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1227f3fbd535SBarry Smith     }
1228f3fbd535SBarry Smith   }
12293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1230f3fbd535SBarry Smith }
1231f3fbd535SBarry Smith 
1232d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1233d71ae5a4SJacob Faibussowitsch {
123497d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
123597d33e41SMatthew G. Knepley 
123697d33e41SMatthew G. Knepley   PetscFunctionBegin;
123797d33e41SMatthew G. Knepley   *levels = mg->nlevels;
12383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123997d33e41SMatthew G. Knepley }
124097d33e41SMatthew G. Knepley 
12414b9ad928SBarry Smith /*@
1242f1580f4eSBarry Smith   PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12434b9ad928SBarry Smith 
12444b9ad928SBarry Smith   Not Collective
12454b9ad928SBarry Smith 
12464b9ad928SBarry Smith   Input Parameter:
12474b9ad928SBarry Smith . pc - the preconditioner context
12484b9ad928SBarry Smith 
1249feefa0e1SJacob Faibussowitsch   Output Parameter:
12504b9ad928SBarry Smith . levels - the number of levels
12514b9ad928SBarry Smith 
12524b9ad928SBarry Smith   Level: advanced
12534b9ad928SBarry Smith 
1254562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()`
12554b9ad928SBarry Smith @*/
1256d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1257d71ae5a4SJacob Faibussowitsch {
12584b9ad928SBarry Smith   PetscFunctionBegin;
12590700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12604f572ea9SToby Isaac   PetscAssertPointer(levels, 2);
126197d33e41SMatthew G. Knepley   *levels = 0;
1262cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12644b9ad928SBarry Smith }
12654b9ad928SBarry Smith 
12664b9ad928SBarry Smith /*@
1267f1580f4eSBarry Smith   PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1268e7d4b4cbSMark Adams 
1269e7d4b4cbSMark Adams   Input Parameter:
1270e7d4b4cbSMark Adams . pc - the preconditioner context
1271e7d4b4cbSMark Adams 
127290db8557SMark Adams   Output Parameters:
127390db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
127490db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1275e7d4b4cbSMark Adams 
1276e7d4b4cbSMark Adams   Level: advanced
1277e7d4b4cbSMark Adams 
1278f1580f4eSBarry Smith   Note:
1279f1580f4eSBarry Smith   This is often call the operator complexity in multigrid literature
1280f1580f4eSBarry Smith 
1281562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1282e7d4b4cbSMark Adams @*/
1283d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1284d71ae5a4SJacob Faibussowitsch {
1285e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1286e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1287e7d4b4cbSMark Adams   PetscInt       lev, N;
1288e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1289e7d4b4cbSMark Adams   MatInfo        info;
1290e7d4b4cbSMark Adams 
1291e7d4b4cbSMark Adams   PetscFunctionBegin;
129290db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12934f572ea9SToby Isaac   if (gc) PetscAssertPointer(gc, 2);
12944f572ea9SToby Isaac   if (oc) PetscAssertPointer(oc, 3);
1295e7d4b4cbSMark Adams   if (!pc->setupcalled) {
129690db8557SMark Adams     if (gc) *gc = 0;
129790db8557SMark Adams     if (oc) *oc = 0;
12983ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1299e7d4b4cbSMark Adams   }
1300e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1301e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1302e7d4b4cbSMark Adams     Mat dB;
13039566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
13049566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
13059566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1306e7d4b4cbSMark Adams     sgc += N;
1307e7d4b4cbSMark Adams     soc += info.nz_used;
13089371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
13099371c9d4SSatish Balay       nnz0 = info.nz_used;
13109371c9d4SSatish Balay       n0   = N;
13119371c9d4SSatish Balay     }
1312e7d4b4cbSMark Adams   }
13130fdf79fbSJacob Faibussowitsch   PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13140fdf79fbSJacob Faibussowitsch   *gc = (PetscReal)(sgc / n0);
131590db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1317e7d4b4cbSMark Adams }
1318e7d4b4cbSMark Adams 
1319e7d4b4cbSMark Adams /*@
132004c3f3b8SBarry Smith   PCMGSetType - Determines the form of multigrid to use, either
13214b9ad928SBarry Smith   multiplicative, additive, full, or the Kaskade algorithm.
13224b9ad928SBarry Smith 
1323c3339decSBarry Smith   Logically Collective
13244b9ad928SBarry Smith 
13254b9ad928SBarry Smith   Input Parameters:
13264b9ad928SBarry Smith + pc   - the preconditioner context
1327f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13284b9ad928SBarry Smith 
13294b9ad928SBarry Smith   Options Database Key:
133020f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13314b9ad928SBarry Smith 
13324b9ad928SBarry Smith   Level: advanced
13334b9ad928SBarry Smith 
1334562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13354b9ad928SBarry Smith @*/
1336d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1337d71ae5a4SJacob Faibussowitsch {
1338f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13394b9ad928SBarry Smith 
13404b9ad928SBarry Smith   PetscFunctionBegin;
13410700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1342c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
134331567311SBarry Smith   mg->am = form;
13449dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1345c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
13463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1347c60c7ad4SBarry Smith }
1348c60c7ad4SBarry Smith 
1349c60c7ad4SBarry Smith /*@
1350f1580f4eSBarry Smith   PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1351c60c7ad4SBarry Smith 
1352c3339decSBarry Smith   Logically Collective
1353c60c7ad4SBarry Smith 
1354c60c7ad4SBarry Smith   Input Parameter:
1355c60c7ad4SBarry Smith . pc - the preconditioner context
1356c60c7ad4SBarry Smith 
1357c60c7ad4SBarry Smith   Output Parameter:
1358f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1359c60c7ad4SBarry Smith 
1360c60c7ad4SBarry Smith   Level: advanced
1361c60c7ad4SBarry Smith 
1362562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1363c60c7ad4SBarry Smith @*/
1364d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1365d71ae5a4SJacob Faibussowitsch {
1366c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1367c60c7ad4SBarry Smith 
1368c60c7ad4SBarry Smith   PetscFunctionBegin;
1369c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1370c60c7ad4SBarry Smith   *type = mg->am;
13713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13724b9ad928SBarry Smith }
13734b9ad928SBarry Smith 
13744b9ad928SBarry Smith /*@
1375f1580f4eSBarry Smith   PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
13764b9ad928SBarry Smith   complicated cycling.
13774b9ad928SBarry Smith 
1378c3339decSBarry Smith   Logically Collective
13794b9ad928SBarry Smith 
13804b9ad928SBarry Smith   Input Parameters:
1381c2be2410SBarry Smith + pc - the multigrid context
1382f1580f4eSBarry Smith - n  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
13834b9ad928SBarry Smith 
13844b9ad928SBarry Smith   Options Database Key:
1385c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
13864b9ad928SBarry Smith 
13874b9ad928SBarry Smith   Level: advanced
13884b9ad928SBarry Smith 
1389562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
13904b9ad928SBarry Smith @*/
1391d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1392d71ae5a4SJacob Faibussowitsch {
1393f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1394f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
139579416396SBarry Smith   PetscInt       i, levels;
13964b9ad928SBarry Smith 
13974b9ad928SBarry Smith   PetscFunctionBegin;
13980700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
139969fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
140028b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1401f3fbd535SBarry Smith   levels = mglevels[0]->levels;
14022fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
14033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14044b9ad928SBarry Smith }
14054b9ad928SBarry Smith 
14068cc2d5dfSBarry Smith /*@
14078cc2d5dfSBarry Smith   PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1408f1580f4eSBarry Smith   of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
14098cc2d5dfSBarry Smith 
1410c3339decSBarry Smith   Logically Collective
14118cc2d5dfSBarry Smith 
14128cc2d5dfSBarry Smith   Input Parameters:
14138cc2d5dfSBarry Smith + pc - the multigrid context
14148cc2d5dfSBarry Smith - n  - number of cycles (default is 1)
14158cc2d5dfSBarry Smith 
14168cc2d5dfSBarry Smith   Options Database Key:
1417147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14188cc2d5dfSBarry Smith 
14198cc2d5dfSBarry Smith   Level: advanced
14208cc2d5dfSBarry Smith 
1421f1580f4eSBarry Smith   Note:
1422f1580f4eSBarry Smith   This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14238cc2d5dfSBarry Smith 
1424562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14258cc2d5dfSBarry Smith @*/
1426d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1427d71ae5a4SJacob Faibussowitsch {
1428f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14298cc2d5dfSBarry Smith 
14308cc2d5dfSBarry Smith   PetscFunctionBegin;
14310700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1432c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14332a21e185SBarry Smith   mg->cyclesperpcapply = n;
14343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14358cc2d5dfSBarry Smith }
14368cc2d5dfSBarry Smith 
143766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1438d71ae5a4SJacob Faibussowitsch {
1439fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1440fb15c04eSBarry Smith 
1441fb15c04eSBarry Smith   PetscFunctionBegin;
14422134b1e4SBarry Smith   mg->galerkin = use;
14433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1444fb15c04eSBarry Smith }
1445fb15c04eSBarry Smith 
1446c2be2410SBarry Smith /*@
144797177400SBarry Smith   PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
144882b87d87SMatthew G. Knepley   finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1449c2be2410SBarry Smith 
1450c3339decSBarry Smith   Logically Collective
1451c2be2410SBarry Smith 
1452c2be2410SBarry Smith   Input Parameters:
1453c91913d3SJed Brown + pc  - the multigrid context
1454f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1455c2be2410SBarry Smith 
1456c2be2410SBarry Smith   Options Database Key:
1457147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1458c2be2410SBarry Smith 
1459c2be2410SBarry Smith   Level: intermediate
1460c2be2410SBarry Smith 
1461f1580f4eSBarry Smith   Note:
1462f1580f4eSBarry Smith   Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1463f1580f4eSBarry Smith   use the `PCMG` construction of the coarser grids.
14641c1aac46SBarry Smith 
1465562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1466c2be2410SBarry Smith @*/
1467d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1468d71ae5a4SJacob Faibussowitsch {
1469c2be2410SBarry Smith   PetscFunctionBegin;
14700700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1471cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
14723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1473c2be2410SBarry Smith }
1474c2be2410SBarry Smith 
14753fc8bf9cSBarry Smith /*@
1476f1580f4eSBarry Smith   PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
14773fc8bf9cSBarry Smith 
14783fc8bf9cSBarry Smith   Not Collective
14793fc8bf9cSBarry Smith 
14803fc8bf9cSBarry Smith   Input Parameter:
14813fc8bf9cSBarry Smith . pc - the multigrid context
14823fc8bf9cSBarry Smith 
14833fc8bf9cSBarry Smith   Output Parameter:
1484f1580f4eSBarry 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`
14853fc8bf9cSBarry Smith 
14863fc8bf9cSBarry Smith   Level: intermediate
14873fc8bf9cSBarry Smith 
1488562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
14893fc8bf9cSBarry Smith @*/
1490d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1491d71ae5a4SJacob Faibussowitsch {
1492f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14933fc8bf9cSBarry Smith 
14943fc8bf9cSBarry Smith   PetscFunctionBegin;
14950700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14962134b1e4SBarry Smith   *galerkin = mg->galerkin;
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14983fc8bf9cSBarry Smith }
14993fc8bf9cSBarry Smith 
150066976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1501d71ae5a4SJacob Faibussowitsch {
1502f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1503f3b08a26SMatthew G. Knepley 
1504f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1505f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
15063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1507f3b08a26SMatthew G. Knepley }
1508f3b08a26SMatthew G. Knepley 
150966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1510d71ae5a4SJacob Faibussowitsch {
1511f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1512f3b08a26SMatthew G. Knepley 
1513f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1514f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
15153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1516f3b08a26SMatthew G. Knepley }
1517f3b08a26SMatthew G. Knepley 
151866976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1519d71ae5a4SJacob Faibussowitsch {
15202b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15212b3cbbdaSStefano Zampini 
15222b3cbbdaSStefano Zampini   PetscFunctionBegin;
15232b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15242b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
1525a077d33dSBarry Smith   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
15263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15272b3cbbdaSStefano Zampini }
15282b3cbbdaSStefano Zampini 
152966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1530d71ae5a4SJacob Faibussowitsch {
15312b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15322b3cbbdaSStefano Zampini 
15332b3cbbdaSStefano Zampini   PetscFunctionBegin;
15342b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15362b3cbbdaSStefano Zampini }
15372b3cbbdaSStefano Zampini 
153866976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1539d71ae5a4SJacob Faibussowitsch {
154041b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
154141b6fd38SMatthew G. Knepley 
154241b6fd38SMatthew G. Knepley   PetscFunctionBegin;
154341b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
15443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154541b6fd38SMatthew G. Knepley }
154641b6fd38SMatthew G. Knepley 
154766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1548d71ae5a4SJacob Faibussowitsch {
154941b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
155041b6fd38SMatthew G. Knepley 
155141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
155241b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
15533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155441b6fd38SMatthew G. Knepley }
155541b6fd38SMatthew G. Knepley 
1556cc4c1da9SBarry Smith /*@
15572b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15582b3cbbdaSStefano Zampini 
15592b3cbbdaSStefano 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.
15602b3cbbdaSStefano Zampini 
1561c3339decSBarry Smith   Logically Collective
15622b3cbbdaSStefano Zampini 
15632b3cbbdaSStefano Zampini   Input Parameters:
15642b3cbbdaSStefano Zampini + pc    - the multigrid context
15652b3cbbdaSStefano Zampini - ctype - the type of coarse space
15662b3cbbdaSStefano Zampini 
15672b3cbbdaSStefano Zampini   Options Database Keys:
15682b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
1569a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw`
15702b3cbbdaSStefano Zampini 
15712b3cbbdaSStefano Zampini   Level: intermediate
15722b3cbbdaSStefano Zampini 
1573a077d33dSBarry Smith   Note:
1574a077d33dSBarry Smith   Requires a `DM` with specific functionality be attached to the `PC`.
1575a077d33dSBarry Smith 
1576a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM`
15772b3cbbdaSStefano Zampini @*/
1578d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1579d71ae5a4SJacob Faibussowitsch {
15802b3cbbdaSStefano Zampini   PetscFunctionBegin;
15812b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15822b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
15832b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
15843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15852b3cbbdaSStefano Zampini }
15862b3cbbdaSStefano Zampini 
1587cc4c1da9SBarry Smith /*@
15882b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
15892b3cbbdaSStefano Zampini 
15902b3cbbdaSStefano Zampini   Not Collective
15912b3cbbdaSStefano Zampini 
15922b3cbbdaSStefano Zampini   Input Parameter:
15932b3cbbdaSStefano Zampini . pc - the multigrid context
15942b3cbbdaSStefano Zampini 
15952b3cbbdaSStefano Zampini   Output Parameter:
15962b3cbbdaSStefano Zampini . ctype - the type of coarse space
15972b3cbbdaSStefano Zampini 
15982b3cbbdaSStefano Zampini   Level: intermediate
15992b3cbbdaSStefano Zampini 
1600562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
16012b3cbbdaSStefano Zampini @*/
1602d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1603d71ae5a4SJacob Faibussowitsch {
16042b3cbbdaSStefano Zampini   PetscFunctionBegin;
16052b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16064f572ea9SToby Isaac   PetscAssertPointer(ctype, 2);
16072b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
16083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16092b3cbbdaSStefano Zampini }
16102b3cbbdaSStefano Zampini 
16112b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1612f3b08a26SMatthew G. Knepley /*@
1613f3b08a26SMatthew 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.
1614f3b08a26SMatthew G. Knepley 
1615c3339decSBarry Smith   Logically Collective
1616f3b08a26SMatthew G. Knepley 
1617f3b08a26SMatthew G. Knepley   Input Parameters:
1618f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1619f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1620f3b08a26SMatthew G. Knepley 
1621f3b08a26SMatthew G. Knepley   Options Database Keys:
1622f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1623f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1624f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1625f3b08a26SMatthew G. Knepley 
1626f3b08a26SMatthew G. Knepley   Level: intermediate
1627f3b08a26SMatthew G. Knepley 
1628562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1629f3b08a26SMatthew G. Knepley @*/
1630d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1631d71ae5a4SJacob Faibussowitsch {
1632f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1633f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1634cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1636f3b08a26SMatthew G. Knepley }
1637f3b08a26SMatthew G. Knepley 
1638f3b08a26SMatthew G. Knepley /*@
1639f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1640f1580f4eSBarry Smith   and thus accurately interpolated.
1641f3b08a26SMatthew G. Knepley 
164220f4b53cSBarry Smith   Not Collective
1643f3b08a26SMatthew G. Knepley 
1644f3b08a26SMatthew G. Knepley   Input Parameter:
1645f3b08a26SMatthew G. Knepley . pc - the multigrid context
1646f3b08a26SMatthew G. Knepley 
1647f3b08a26SMatthew G. Knepley   Output Parameter:
1648f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1649f3b08a26SMatthew G. Knepley 
1650f3b08a26SMatthew G. Knepley   Level: intermediate
1651f3b08a26SMatthew G. Knepley 
1652562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1653f3b08a26SMatthew G. Knepley @*/
1654d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1655d71ae5a4SJacob Faibussowitsch {
1656f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1657f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16584f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
1659cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
16603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1661f3b08a26SMatthew G. Knepley }
1662f3b08a26SMatthew G. Knepley 
16634b9ad928SBarry Smith /*@
166441b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
166541b6fd38SMatthew G. Knepley 
1666c3339decSBarry Smith   Logically Collective
166741b6fd38SMatthew G. Knepley 
166841b6fd38SMatthew G. Knepley   Input Parameters:
166941b6fd38SMatthew G. Knepley + pc - the multigrid context
167041b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
167141b6fd38SMatthew G. Knepley 
1672f1580f4eSBarry Smith   Options Database Key:
167341b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
167441b6fd38SMatthew G. Knepley 
167541b6fd38SMatthew G. Knepley   Level: intermediate
167641b6fd38SMatthew G. Knepley 
1677562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
167841b6fd38SMatthew G. Knepley @*/
1679d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1680d71ae5a4SJacob Faibussowitsch {
168141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
168241b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1683cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
16843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168541b6fd38SMatthew G. Knepley }
168641b6fd38SMatthew G. Knepley 
168741b6fd38SMatthew G. Knepley /*@
168841b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
168941b6fd38SMatthew G. Knepley 
169020f4b53cSBarry Smith   Not Collective
169141b6fd38SMatthew G. Knepley 
169241b6fd38SMatthew G. Knepley   Input Parameter:
169341b6fd38SMatthew G. Knepley . pc - the multigrid context
169441b6fd38SMatthew G. Knepley 
169541b6fd38SMatthew G. Knepley   Output Parameter:
169641b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
169741b6fd38SMatthew G. Knepley 
169841b6fd38SMatthew G. Knepley   Level: intermediate
169941b6fd38SMatthew G. Knepley 
1700562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
170141b6fd38SMatthew G. Knepley @*/
1702d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1703d71ae5a4SJacob Faibussowitsch {
170441b6fd38SMatthew G. Knepley   PetscFunctionBegin;
170541b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17064f572ea9SToby Isaac   PetscAssertPointer(cr, 2);
1707cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
17083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
170941b6fd38SMatthew G. Knepley }
171041b6fd38SMatthew G. Knepley 
171141b6fd38SMatthew G. Knepley /*@
171206792cafSBarry Smith   PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1713f1580f4eSBarry Smith   on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1714710315b6SLawrence Mitchell   pre- and post-smoothing steps.
171506792cafSBarry Smith 
1716c3339decSBarry Smith   Logically Collective
171706792cafSBarry Smith 
171806792cafSBarry Smith   Input Parameters:
1719feefa0e1SJacob Faibussowitsch + pc - the multigrid context
172006792cafSBarry Smith - n  - the number of smoothing steps
172106792cafSBarry Smith 
172206792cafSBarry Smith   Options Database Key:
1723a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
172406792cafSBarry Smith 
172506792cafSBarry Smith   Level: advanced
172606792cafSBarry Smith 
1727f1580f4eSBarry Smith   Note:
1728f1580f4eSBarry 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.
172906792cafSBarry Smith 
1730562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()`
173106792cafSBarry Smith @*/
1732d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1733d71ae5a4SJacob Faibussowitsch {
173406792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
173506792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
173606792cafSBarry Smith   PetscInt       i, levels;
173706792cafSBarry Smith 
173806792cafSBarry Smith   PetscFunctionBegin;
173906792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
174006792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
174128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
174206792cafSBarry Smith   levels = mglevels[0]->levels;
174306792cafSBarry Smith 
174406792cafSBarry Smith   for (i = 1; i < levels; i++) {
1745fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
1746fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
174706792cafSBarry Smith     mg->default_smoothu = n;
174806792cafSBarry Smith     mg->default_smoothd = n;
174906792cafSBarry Smith   }
17503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175106792cafSBarry Smith }
175206792cafSBarry Smith 
1753f442ab6aSBarry Smith /*@
1754f1580f4eSBarry Smith   PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1755710315b6SLawrence Mitchell   and adds the suffix _up to the options name
1756f442ab6aSBarry Smith 
1757c3339decSBarry Smith   Logically Collective
1758f442ab6aSBarry Smith 
1759f1580f4eSBarry Smith   Input Parameter:
1760f442ab6aSBarry Smith . pc - the preconditioner context
1761f442ab6aSBarry Smith 
1762f442ab6aSBarry Smith   Options Database Key:
1763147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1764f442ab6aSBarry Smith 
1765f442ab6aSBarry Smith   Level: advanced
1766f442ab6aSBarry Smith 
1767f1580f4eSBarry Smith   Note:
1768f1580f4eSBarry 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.
1769f442ab6aSBarry Smith 
1770562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()`
1771f442ab6aSBarry Smith @*/
1772d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1773d71ae5a4SJacob Faibussowitsch {
1774f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1775f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1776f442ab6aSBarry Smith   PetscInt       i, levels;
1777f442ab6aSBarry Smith   KSP            subksp;
1778f442ab6aSBarry Smith 
1779f442ab6aSBarry Smith   PetscFunctionBegin;
1780f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
178128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1782f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1783f442ab6aSBarry Smith 
1784f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1785710315b6SLawrence Mitchell     const char *prefix = NULL;
1786f442ab6aSBarry Smith     /* make sure smoother up and down are different */
17879566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
17889566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
17899566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
17909566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1791f442ab6aSBarry Smith   }
17923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1793f442ab6aSBarry Smith }
1794f442ab6aSBarry Smith 
179507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
179666976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1797d71ae5a4SJacob Faibussowitsch {
179807a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
179907a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
180007a4832bSFande Kong   Mat           *mat;
180107a4832bSFande Kong   PetscInt       l;
180207a4832bSFande Kong 
180307a4832bSFande Kong   PetscFunctionBegin;
180428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
180607a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
180707a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
18089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
180907a4832bSFande Kong   }
181007a4832bSFande Kong   *num_levels     = mg->nlevels;
181107a4832bSFande Kong   *interpolations = mat;
18123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
181307a4832bSFande Kong }
181407a4832bSFande Kong 
181507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
181666976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1817d71ae5a4SJacob Faibussowitsch {
181807a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
181907a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
182007a4832bSFande Kong   PetscInt       l;
182107a4832bSFande Kong   Mat           *mat;
182207a4832bSFande Kong 
182307a4832bSFande Kong   PetscFunctionBegin;
182428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
182607a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
1827f4f49eeaSPierre Jolivet     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l]));
18289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
182907a4832bSFande Kong   }
183007a4832bSFande Kong   *num_levels      = mg->nlevels;
183107a4832bSFande Kong   *coarseOperators = mat;
18323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183307a4832bSFande Kong }
183407a4832bSFande Kong 
1835f3b08a26SMatthew G. Knepley /*@C
1836f1580f4eSBarry Smith   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1837f3b08a26SMatthew G. Knepley 
1838cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1839f3b08a26SMatthew G. Knepley 
1840f3b08a26SMatthew G. Knepley   Input Parameters:
1841f3b08a26SMatthew G. Knepley + name     - name of the constructor
1842f3b08a26SMatthew G. Knepley - function - constructor routine
1843f3b08a26SMatthew G. Knepley 
184420f4b53cSBarry Smith   Calling sequence of `function`:
184520f4b53cSBarry Smith + pc        - The `PC` object
1846f1580f4eSBarry Smith . l         - The multigrid level, 0 is the coarse level
184720f4b53cSBarry Smith . dm        - The `DM` for this level
1848f1580f4eSBarry Smith . smooth    - The level smoother
1849f1580f4eSBarry Smith . Nc        - The size of the coarse space
1850f1580f4eSBarry Smith . initGuess - Basis for an initial guess for the space
1851f1580f4eSBarry Smith - coarseSp  - A basis for the computed coarse space
1852f3b08a26SMatthew G. Knepley 
1853f3b08a26SMatthew G. Knepley   Level: advanced
1854f3b08a26SMatthew G. Knepley 
1855feefa0e1SJacob Faibussowitsch   Developer Notes:
1856f1580f4eSBarry Smith   How come this is not used by `PCGAMG`?
1857f1580f4eSBarry Smith 
1858562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1859f3b08a26SMatthew G. Knepley @*/
186004c3f3b8SBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp))
1861d71ae5a4SJacob Faibussowitsch {
1862f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18639566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18649566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
18653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1866f3b08a26SMatthew G. Knepley }
1867f3b08a26SMatthew G. Knepley 
1868f3b08a26SMatthew G. Knepley /*@C
1869f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1870f3b08a26SMatthew G. Knepley 
1871cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1872f3b08a26SMatthew G. Knepley 
1873f3b08a26SMatthew G. Knepley   Input Parameter:
1874f3b08a26SMatthew G. Knepley . name - name of the constructor
1875f3b08a26SMatthew G. Knepley 
1876f3b08a26SMatthew G. Knepley   Output Parameter:
1877f3b08a26SMatthew G. Knepley . function - constructor routine
1878f3b08a26SMatthew G. Knepley 
1879f3b08a26SMatthew G. Knepley   Level: advanced
1880f3b08a26SMatthew G. Knepley 
1881562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1882f3b08a26SMatthew G. Knepley @*/
1883d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat *))
1884d71ae5a4SJacob Faibussowitsch {
1885f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18869566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
18873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1888f3b08a26SMatthew G. Knepley }
1889f3b08a26SMatthew G. Knepley 
18903b09bd56SBarry Smith /*MC
1891ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
18923b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
18933b09bd56SBarry Smith 
18943b09bd56SBarry Smith    Options Database Keys:
18953b09bd56SBarry Smith +  -pc_mg_levels <nlevels>                            - number of levels including finest
1896391689abSStefano Zampini .  -pc_mg_cycle_type <v,w>                            - provide the cycle desired
18978c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
18983b09bd56SBarry Smith .  -pc_mg_log                                         - log information about time spent on each level of the solver
1899710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup                           - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
19002134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>               - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
19018cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles                        - number of cycles to use as the preconditioner (defaults to 1)
19028cf6037eSBarry Smith .  -pc_mg_dump_matlab                                  - dumps the matrices for each level and the restriction/interpolation matrices
1903a3b724e8SBarry Smith                                                          to a `PETSCVIEWERSOCKET` for reading from MATLAB.
19048cf6037eSBarry Smith -  -pc_mg_dump_binary                                  -dumps the matrices for each level and the restriction/interpolation matrices
19058cf6037eSBarry Smith                                                         to the binary output file called binaryoutput
19063b09bd56SBarry Smith 
190720f4b53cSBarry Smith    Level: intermediate
190820f4b53cSBarry Smith 
190995452b02SPatrick Sanan    Notes:
191004c3f3b8SBarry Smith    The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard
19118f4fb22eSMark Adams    options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`,
19128f4fb22eSMark Adams    and the finest where `-mg_fine_` can override `-mg_levels_`.  One can set different preconditioners etc on specific levels with the prefix
19138f4fb22eSMark Adams    `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example
191404c3f3b8SBarry Smith .vb
191504c3f3b8SBarry Smith    -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor
191604c3f3b8SBarry Smith .ve
191704c3f3b8SBarry Smith    These options also work for controlling the smoothers etc inside `PCGAMG`
191804c3f3b8SBarry Smith 
1919*e87b5d96SPierre Jolivet    If one uses a Krylov method such `KSPGMRES` or `KSPCG` as the smoother than one must use `KSPFGMRES`, `KSPGCR`, or `KSPRICHARDSON` as the outer Krylov method
19203b09bd56SBarry Smith 
19218cf6037eSBarry Smith    When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19228cf6037eSBarry Smith 
1923f1580f4eSBarry Smith    When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
192423067569SBarry Smith    is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
192523067569SBarry Smith    (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
192623067569SBarry Smith    residual is computed at the end of each cycle.
192723067569SBarry Smith 
192804c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1929db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1930db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1931db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1932f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1933f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19343b09bd56SBarry Smith M*/
19353b09bd56SBarry Smith 
1936d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1937d71ae5a4SJacob Faibussowitsch {
1938f3fbd535SBarry Smith   PC_MG *mg;
1939f3fbd535SBarry Smith 
19404b9ad928SBarry Smith   PetscFunctionBegin;
19414dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
19423ec1f749SStefano Zampini   pc->data               = mg;
1943f3fbd535SBarry Smith   mg->nlevels            = -1;
194410eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19452134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1946f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1947f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1948f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1949f3fbd535SBarry Smith 
195037a44384SMark Adams   pc->useAmat = PETSC_TRUE;
195137a44384SMark Adams 
19524b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1953fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
195430b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
19554b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1956a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
19574b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
19584b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
19594b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1960fb15c04eSBarry Smith 
19619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
19629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
19639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
19712b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
19722b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
19733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19744b9ad928SBarry Smith }
1975