xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision bbbcb0814afc1357cc0d1bbd615328195182442c)
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));
523*bbbcb081SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", NULL));
5242b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5252b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5262b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5272b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5282b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5292b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5302b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5312b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5322b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5332b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
535f3fbd535SBarry Smith }
536f3fbd535SBarry Smith 
537f3fbd535SBarry Smith /*
538f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
539f3fbd535SBarry Smith              or full cycle of multigrid.
540f3fbd535SBarry Smith 
541f3fbd535SBarry Smith   Note:
542f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
543f3fbd535SBarry Smith */
544d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
545d71ae5a4SJacob Faibussowitsch {
546f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
547f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
548391689abSStefano Zampini   PC             tpc;
549f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
55030b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
551f3fbd535SBarry Smith 
552f3fbd535SBarry Smith   PetscFunctionBegin;
55330b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5549566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
555e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
556298cc208SBarry Smith   for (i = 0; i < levels; i++) {
557e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5589566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5599566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
560e1d8e5deSBarry Smith     }
561e1d8e5deSBarry Smith   }
562e1d8e5deSBarry Smith 
5639566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5649566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5659566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5669566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
567391689abSStefano Zampini   if (!changeu && !changed) {
56830b0564aSStefano Zampini     if (matapp) {
5699566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
57030b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
57130b0564aSStefano Zampini     } else {
5729566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
573f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
57430b0564aSStefano Zampini     }
575391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
57630b0564aSStefano Zampini     if (matapp) {
57730b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
57830b0564aSStefano Zampini         PetscInt  N1, N2;
57930b0564aSStefano Zampini         PetscBool flg;
58030b0564aSStefano Zampini 
5819566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5829566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5839566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
58448a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
58530b0564aSStefano Zampini       }
58630b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5879566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
58830b0564aSStefano Zampini       } else {
5899566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
59030b0564aSStefano Zampini       }
59130b0564aSStefano Zampini     } else {
592391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
593391689abSStefano Zampini         Vec *vec;
594391689abSStefano Zampini 
5959566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
596391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
5979566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
598391689abSStefano Zampini       }
5999566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
600391689abSStefano Zampini     }
60130b0564aSStefano Zampini   }
6029371c9d4SSatish Balay   if (matapp) {
6039371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
6049371c9d4SSatish Balay   } else {
6059371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
6069371c9d4SSatish Balay   }
60730b0564aSStefano Zampini 
60830b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
60930b0564aSStefano Zampini      Reset operators if sizes/type do no match */
61030b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
61130b0564aSStefano Zampini     PetscInt  Xc, Bc;
61230b0564aSStefano Zampini     PetscBool flg;
61330b0564aSStefano Zampini 
6149566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
6159566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
6169566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
61730b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6189566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
61930b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
6209566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6219566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6229566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
62330b0564aSStefano Zampini       }
62430b0564aSStefano Zampini     }
62530b0564aSStefano Zampini   }
626391689abSStefano Zampini 
62731567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6289566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6299566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
63048a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6312fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6329566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6332fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6349566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6352fa5cd67SKarl Rupp   } else {
6369566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
637f3fbd535SBarry Smith   }
6389566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
63930b0564aSStefano Zampini   if (!changeu && !changed) {
6409371c9d4SSatish Balay     if (matapp) {
6419371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6429371c9d4SSatish Balay     } else {
6439371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6449371c9d4SSatish Balay     }
64530b0564aSStefano Zampini   }
6463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
647f3fbd535SBarry Smith }
648f3fbd535SBarry Smith 
649d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
650d71ae5a4SJacob Faibussowitsch {
651fcb023d4SJed Brown   PetscFunctionBegin;
6529566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
654fcb023d4SJed Brown }
655fcb023d4SJed Brown 
656d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
657d71ae5a4SJacob Faibussowitsch {
658fcb023d4SJed Brown   PetscFunctionBegin;
6599566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66130b0564aSStefano Zampini }
66230b0564aSStefano Zampini 
663d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
664d71ae5a4SJacob Faibussowitsch {
66530b0564aSStefano Zampini   PetscFunctionBegin;
6669566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
668fcb023d4SJed Brown }
669f3fbd535SBarry Smith 
6704dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x)
6714dbf25a8SPierre Jolivet {
6724dbf25a8SPierre Jolivet   PetscFunctionBegin;
6734dbf25a8SPierre Jolivet   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE));
6744dbf25a8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
6754dbf25a8SPierre Jolivet }
6764dbf25a8SPierre Jolivet 
677ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject)
678d71ae5a4SJacob Faibussowitsch {
679710315b6SLawrence Mitchell   PetscInt            levels, cycles;
680f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
681f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6823d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
683f3fbd535SBarry Smith   PCMGType            mgtype;
684f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6852134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6862b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
687f3fbd535SBarry Smith 
688f3fbd535SBarry Smith   PetscFunctionBegin;
6891d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
690d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6921a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6939566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
694eb3f98d2SBarry Smith     levels++;
6953aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
696eb3f98d2SBarry Smith   }
6979566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
6983aeaf226SBarry Smith   mglevels = mg->levels;
6993aeaf226SBarry Smith 
700f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
7019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
7021baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
7032b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
7042b3cbbdaSStefano 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));
7052b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
7069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
7079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
70841b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
7099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
7109566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
711f56b1265SBarry Smith   flg = PETSC_FALSE;
7129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
7131baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
7145544a5bcSStefano Zampini   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)&gtype, &flg));
7155544a5bcSStefano Zampini   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
71631567311SBarry Smith   mgtype = mg->am;
7179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
7181baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
71931567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
7209566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
7211baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
722f3fbd535SBarry Smith   }
723f3fbd535SBarry Smith   flg = PETSC_FALSE;
7249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
725f3fbd535SBarry Smith   if (flg) {
726f3fbd535SBarry Smith     PetscInt i;
727f3fbd535SBarry Smith     char     eventname[128];
7281a97d7b6SStefano Zampini 
729f3fbd535SBarry Smith     levels = mglevels[0]->levels;
730f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
731835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i));
7329566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
733835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i));
7349566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
735f3fbd535SBarry Smith       if (i) {
736835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i));
7379566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
738835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i));
7399566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
740f3fbd535SBarry Smith       }
741f3fbd535SBarry Smith     }
742eec35531SMatthew G Knepley 
7432611ad71SToby Isaac     if (PetscDefined(USE_LOG)) {
7442611ad71SToby Isaac       const char sname[] = "MG Apply";
745eec35531SMatthew G Knepley 
7462611ad71SToby Isaac       PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
7472611ad71SToby Isaac       if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
748eec35531SMatthew G Knepley     }
749f3fbd535SBarry Smith   }
750d0609cedSBarry Smith   PetscOptionsHeadEnd();
751f3b08a26SMatthew G. Knepley   /* Check option consistency */
7529566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7539566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
75408401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
756f3fbd535SBarry Smith }
757f3fbd535SBarry Smith 
7580a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7590a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7600a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7612b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
762f3fbd535SBarry Smith 
7639804daf3SBarry Smith #include <petscdraw.h>
764d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
765d71ae5a4SJacob Faibussowitsch {
766f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
767f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
768e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
769219b1045SBarry Smith   PetscBool      iascii, isbinary, isdraw;
770f3fbd535SBarry Smith 
771f3fbd535SBarry Smith   PetscFunctionBegin;
7729566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
7739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
775f3fbd535SBarry Smith   if (iascii) {
776e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
77763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
77848a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7792134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7809566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7812134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7829566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7832134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7849566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7852134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7869566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7874f66f45eSBarry Smith     } else {
7889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
789f3fbd535SBarry Smith     }
7901baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
791f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
79263a3b9bcSJacob Faibussowitsch       if (i) {
79363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
794f3fbd535SBarry Smith       } else {
79563a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
796f3fbd535SBarry Smith       }
7979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7989566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
7999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
800f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
8019566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
802f3fbd535SBarry Smith       } else if (i) {
80363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
8049566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8059566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8069566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
807f3fbd535SBarry Smith       }
80841b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
80963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
8109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8119566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
8129566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
81341b6fd38SMatthew G. Knepley       }
814f3fbd535SBarry Smith     }
8155b0b0462SBarry Smith   } else if (isbinary) {
8165b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
8179566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
81848a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8195b0b0462SBarry Smith     }
820219b1045SBarry Smith   } else if (isdraw) {
821219b1045SBarry Smith     PetscDraw draw;
822b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
8239566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8249566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8259566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
826219b1045SBarry Smith     bottom = y - th;
827219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
828b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8299566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8309566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8319566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
832b4375e8dSPeter Brune       } else {
833b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8349566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8359566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8369566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8379566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8389566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8399566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
840b4375e8dSPeter Brune       }
8419566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8421cd381d6SBarry Smith       bottom -= th;
843219b1045SBarry Smith     }
8445b0b0462SBarry Smith   }
8453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
846f3fbd535SBarry Smith }
847f3fbd535SBarry Smith 
848af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
849cab2e9ccSBarry Smith 
850f3fbd535SBarry Smith /*
851f3fbd535SBarry Smith     Calls setup for the KSP on each level
852f3fbd535SBarry Smith */
853d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
854d71ae5a4SJacob Faibussowitsch {
855f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
856f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8571a97d7b6SStefano Zampini   PetscInt       i, n;
85898e04984SBarry Smith   PC             cpc;
8593db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
860f3fbd535SBarry Smith   Mat            dA, dB;
861f3fbd535SBarry Smith   Vec            tvec;
862218a07d4SBarry Smith   DM            *dms;
8630a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
86441b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8652b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
866f3fbd535SBarry Smith 
867f3fbd535SBarry Smith   PetscFunctionBegin;
86828b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8691a97d7b6SStefano Zampini   n = mglevels[0]->levels;
87001bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8713aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8723aeaf226SBarry Smith     PetscInt levels;
8739566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8743aeaf226SBarry Smith     levels++;
8753aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8769566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8773aeaf226SBarry Smith       n = levels;
8789566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8793aeaf226SBarry Smith       mglevels = mg->levels;
8803aeaf226SBarry Smith     }
8813aeaf226SBarry Smith   }
8823aeaf226SBarry Smith 
883f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
884f3fbd535SBarry Smith   /* so use those from global PC */
885f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8869566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
88798e04984SBarry Smith   if (opsset) {
88898e04984SBarry Smith     Mat mmat;
8899566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
89098e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
89198e04984SBarry Smith   }
892*bbbcb081SMark Adams   /* fine grid smoother inherits the reuse-pc flag */
893*bbbcb081SMark Adams   PetscCall(KSPGetPC(mglevels[n - 1]->smoothd, &cpc));
894*bbbcb081SMark Adams   cpc->reusepreconditioner = pc->reusepreconditioner;
895*bbbcb081SMark Adams   PetscCall(KSPGetPC(mglevels[n - 1]->smoothu, &cpc));
896*bbbcb081SMark Adams   cpc->reusepreconditioner = pc->reusepreconditioner;
8974a5f07a5SMark F. Adams 
89841b6fd38SMatthew G. Knepley   /* Create CR solvers */
8999566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
90041b6fd38SMatthew G. Knepley   if (doCR) {
90141b6fd38SMatthew G. Knepley     const char *prefix;
90241b6fd38SMatthew G. Knepley 
9039566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
90441b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
90541b6fd38SMatthew G. Knepley       PC   ipc, cr;
90641b6fd38SMatthew G. Knepley       char crprefix[128];
90741b6fd38SMatthew G. Knepley 
9089566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
9093821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
9109566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
9119566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
9129566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
9139566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
9149566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9159566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9169566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9179566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
91841b6fd38SMatthew G. Knepley 
9199566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
9209566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9219566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9229566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
9239566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
9249566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
92541b6fd38SMatthew G. Knepley 
926fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
9279566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
928835f2295SStefano Zampini       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i));
9299566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
93041b6fd38SMatthew G. Knepley     }
93141b6fd38SMatthew G. Knepley   }
93241b6fd38SMatthew G. Knepley 
9334a5f07a5SMark F. Adams   if (!opsset) {
9349566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9354a5f07a5SMark F. Adams     if (use_amat) {
9369566063dSJacob 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"));
9379566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
93869858f1bSStefano Zampini     } else {
9399566063dSJacob 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"));
9409566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9414a5f07a5SMark F. Adams     }
9424a5f07a5SMark F. Adams   }
943f3fbd535SBarry Smith 
9449c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9459c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9469c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9472b3cbbdaSStefano Zampini       break;
9489c7ffb39SBarry Smith     }
9499c7ffb39SBarry Smith   }
9502134b1e4SBarry Smith 
9519566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9522134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9532b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9542134b1e4SBarry Smith     needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9552134b1e4SBarry Smith   }
9562134b1e4SBarry Smith 
9572b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9582b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9592b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9602b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9612b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9622b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9632b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9642b3cbbdaSStefano Zampini     }
9652b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9662b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9672b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9682b3cbbdaSStefano Zampini     }
9692b3cbbdaSStefano Zampini   }
9702b3cbbdaSStefano Zampini 
9719c7ffb39SBarry Smith   /*
9729c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9732b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9749c7ffb39SBarry Smith   */
97532fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
97632fe681dSStefano Zampini     /* first see if we can compute a coarse space */
97732fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
97832fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
97932fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
98032fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
98132fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
98232fe681dSStefano Zampini         }
98332fe681dSStefano Zampini       }
98432fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9852e499ae9SBarry Smith       Mat p;
98673250ac0SBarry Smith       Vec rscale;
9879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
988218a07d4SBarry Smith       dms[n - 1] = pc->dm;
989ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9909566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
991218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
992942e3340SBarry Smith         DMKSP     kdm;
993eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9949566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
9959566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
996c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9979566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
9989566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
999c27ee7a3SPatrick Farrell         }
100041b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
10019566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
10029566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
100341b6fd38SMatthew G. Knepley         }
10049566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
1005d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
1006d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
10070298fd71SBarry Smith         kdm->ops->computerhs = NULL;
10080298fd71SBarry Smith         kdm->rhsctx          = NULL;
100924c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
10109566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
10119566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
10129566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
10139566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
10149566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1015218a07d4SBarry Smith         }
10169566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
10173ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
10189566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
10199566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
10209566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
10213ad4599aSBarry Smith         }
10229566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
1023eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
10249566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
10259566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
10269566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1027eab52d2bSLawrence Mitchell         }
102824c3aa18SBarry Smith       }
10292d2b81a6SBarry Smith 
10309566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10319566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1032ce4cda84SJed Brown     }
103332fe681dSStefano Zampini   }
1034cab2e9ccSBarry Smith 
10352134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10362134b1e4SBarry Smith     Mat       A, B;
10372134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10382134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10392134b1e4SBarry Smith 
10402b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10412b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10422134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1043f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10447827d75bSBarry 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");
104548a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
104648a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
104748a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
104848a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
104948a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10502134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10512134b1e4SBarry Smith       if (!doA && dAeqdB) {
10529566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10532134b1e4SBarry Smith         A = B;
10542134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10559566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10569566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1057b9367914SBarry Smith       }
10582134b1e4SBarry Smith       if (!doB && dAeqdB) {
10599566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10602134b1e4SBarry Smith         B = A;
10612134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10629566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10639566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10647d537d92SJed Brown       }
10652134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10669566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10679566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10689566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10692134b1e4SBarry Smith       }
10702134b1e4SBarry Smith       dA = A;
1071f3fbd535SBarry Smith       dB = B;
1072f3fbd535SBarry Smith     }
1073f3fbd535SBarry Smith   }
1074f3b08a26SMatthew G. Knepley 
1075f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10762b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1077f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
107848a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10792b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1080f3b08a26SMatthew G. Knepley     }
108148a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1082f3b08a26SMatthew G. Knepley   }
1083f3b08a26SMatthew G. Knepley 
10842134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1085caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1086ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1087caa4e7f2SJed Brown       Mat Restrict, Inject;
1088caa4e7f2SJed Brown       Vec rscale;
10899566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
10909566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
10919566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
10929566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
10939566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
10949566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1095caa4e7f2SJed Brown     }
1096caa4e7f2SJed Brown   }
1097f3fbd535SBarry Smith 
1098f3fbd535SBarry Smith   if (!pc->setupcalled) {
109948a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1100f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
110148a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
110248a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1103f3fbd535SBarry Smith     }
110415229ffcSPierre Jolivet     /* insure that if either interpolation or restriction is set the other one is set */
1105f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
11069566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
11079566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1108f3fbd535SBarry Smith     }
1109f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1110f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1111f3fbd535SBarry Smith         Vec *vec;
11129566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
11139566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
11149566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
11159566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1116f3fbd535SBarry Smith       }
1117f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
11189566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11199566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
11209566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1121f3fbd535SBarry Smith       }
1122f3fbd535SBarry Smith       if (!mglevels[i]->x) {
11239566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11249566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
11259566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1126f3fbd535SBarry Smith       }
112741b6fd38SMatthew G. Knepley       if (doCR) {
11289566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11299566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11309566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
113141b6fd38SMatthew G. Knepley       }
1132f3fbd535SBarry Smith     }
1133f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1134f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1135f3fbd535SBarry Smith       Vec *vec;
11369566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11379566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11389566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11399566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1140f3fbd535SBarry Smith     }
114141b6fd38SMatthew G. Knepley     if (doCR) {
11429566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11439566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11449566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
114541b6fd38SMatthew G. Knepley     }
1146f3fbd535SBarry Smith   }
1147f3fbd535SBarry Smith 
114898e04984SBarry Smith   if (pc->dm) {
114998e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
115098e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
115198e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
115298e04984SBarry Smith     }
115398e04984SBarry Smith   }
115408549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
115508549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
115608549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1157f3fbd535SBarry Smith 
1158f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11592a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1160f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11619566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1162f3fbd535SBarry Smith     }
11639566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11649566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11659566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1166d4645a75SStefano Zampini     if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11679566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1168d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1169d42688cbSBarry Smith       Mat mat;
11709566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11719566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1172d42688cbSBarry Smith     }
1173fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1174fcb023d4SJed Brown       Mat mat;
11759566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11769566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1177fcb023d4SJed Brown     }
1178f3fbd535SBarry Smith   }
1179f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1180f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1181f3fbd535SBarry Smith       Mat downmat, downpmat;
1182f3fbd535SBarry Smith 
1183f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11849566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1185f3fbd535SBarry Smith       if (!opsset) {
11869566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
11879566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1188f3fbd535SBarry Smith       }
1189f3fbd535SBarry Smith 
11909566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
11919566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11929566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1193d4645a75SStefano Zampini       if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
11949566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1195f3fbd535SBarry Smith     }
119641b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
119741b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
119841b6fd38SMatthew G. Knepley 
119941b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
12009566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
120141b6fd38SMatthew G. Knepley       if (!opsset) {
12029566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
12039566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
120441b6fd38SMatthew G. Knepley       }
120541b6fd38SMatthew G. Knepley 
12069566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
12079566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
12089566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1209d4645a75SStefano Zampini       if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
12109566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
121141b6fd38SMatthew G. Knepley     }
1212f3fbd535SBarry Smith   }
1213f3fbd535SBarry Smith 
12149566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
12159566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1216d4645a75SStefano Zampini   if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
12179566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1218f3fbd535SBarry Smith 
1219f3fbd535SBarry Smith   /*
1220f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1221e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1222f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1223f3fbd535SBarry Smith 
1224f3fbd535SBarry Smith    Only support one or the other at the same time.
1225f3fbd535SBarry Smith   */
1226f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1228ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1229f3fbd535SBarry Smith   dump = PETSC_FALSE;
1230f3fbd535SBarry Smith #endif
12319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1232ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1233f3fbd535SBarry Smith 
1234f3fbd535SBarry Smith   if (viewer) {
123548a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1236f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12379566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12389566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1239f3fbd535SBarry Smith     }
1240f3fbd535SBarry Smith   }
12413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1242f3fbd535SBarry Smith }
1243f3fbd535SBarry Smith 
1244d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1245d71ae5a4SJacob Faibussowitsch {
124697d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
124797d33e41SMatthew G. Knepley 
124897d33e41SMatthew G. Knepley   PetscFunctionBegin;
124997d33e41SMatthew G. Knepley   *levels = mg->nlevels;
12503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
125197d33e41SMatthew G. Knepley }
125297d33e41SMatthew G. Knepley 
12534b9ad928SBarry Smith /*@
1254f1580f4eSBarry Smith   PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12554b9ad928SBarry Smith 
12564b9ad928SBarry Smith   Not Collective
12574b9ad928SBarry Smith 
12584b9ad928SBarry Smith   Input Parameter:
12594b9ad928SBarry Smith . pc - the preconditioner context
12604b9ad928SBarry Smith 
1261feefa0e1SJacob Faibussowitsch   Output Parameter:
12624b9ad928SBarry Smith . levels - the number of levels
12634b9ad928SBarry Smith 
12644b9ad928SBarry Smith   Level: advanced
12654b9ad928SBarry Smith 
1266562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()`
12674b9ad928SBarry Smith @*/
1268d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1269d71ae5a4SJacob Faibussowitsch {
12704b9ad928SBarry Smith   PetscFunctionBegin;
12710700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12724f572ea9SToby Isaac   PetscAssertPointer(levels, 2);
127397d33e41SMatthew G. Knepley   *levels = 0;
1274cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12764b9ad928SBarry Smith }
12774b9ad928SBarry Smith 
12784b9ad928SBarry Smith /*@
1279f1580f4eSBarry Smith   PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1280e7d4b4cbSMark Adams 
1281e7d4b4cbSMark Adams   Input Parameter:
1282e7d4b4cbSMark Adams . pc - the preconditioner context
1283e7d4b4cbSMark Adams 
128490db8557SMark Adams   Output Parameters:
128590db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
128690db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1287e7d4b4cbSMark Adams 
1288e7d4b4cbSMark Adams   Level: advanced
1289e7d4b4cbSMark Adams 
1290f1580f4eSBarry Smith   Note:
1291f1580f4eSBarry Smith   This is often call the operator complexity in multigrid literature
1292f1580f4eSBarry Smith 
1293562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1294e7d4b4cbSMark Adams @*/
1295d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1296d71ae5a4SJacob Faibussowitsch {
1297e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1298e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1299e7d4b4cbSMark Adams   PetscInt       lev, N;
1300e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1301e7d4b4cbSMark Adams   MatInfo        info;
1302e7d4b4cbSMark Adams 
1303e7d4b4cbSMark Adams   PetscFunctionBegin;
130490db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
13054f572ea9SToby Isaac   if (gc) PetscAssertPointer(gc, 2);
13064f572ea9SToby Isaac   if (oc) PetscAssertPointer(oc, 3);
1307e7d4b4cbSMark Adams   if (!pc->setupcalled) {
130890db8557SMark Adams     if (gc) *gc = 0;
130990db8557SMark Adams     if (oc) *oc = 0;
13103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1311e7d4b4cbSMark Adams   }
1312e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1313e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1314e7d4b4cbSMark Adams     Mat dB;
13159566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
13169566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
13179566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1318e7d4b4cbSMark Adams     sgc += N;
1319e7d4b4cbSMark Adams     soc += info.nz_used;
13209371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
13219371c9d4SSatish Balay       nnz0 = info.nz_used;
13229371c9d4SSatish Balay       n0   = N;
13239371c9d4SSatish Balay     }
1324e7d4b4cbSMark Adams   }
13250fdf79fbSJacob Faibussowitsch   PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13260fdf79fbSJacob Faibussowitsch   *gc = (PetscReal)(sgc / n0);
132790db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1329e7d4b4cbSMark Adams }
1330e7d4b4cbSMark Adams 
1331e7d4b4cbSMark Adams /*@
133204c3f3b8SBarry Smith   PCMGSetType - Determines the form of multigrid to use, either
13334b9ad928SBarry Smith   multiplicative, additive, full, or the Kaskade algorithm.
13344b9ad928SBarry Smith 
1335c3339decSBarry Smith   Logically Collective
13364b9ad928SBarry Smith 
13374b9ad928SBarry Smith   Input Parameters:
13384b9ad928SBarry Smith + pc   - the preconditioner context
1339f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13404b9ad928SBarry Smith 
13414b9ad928SBarry Smith   Options Database Key:
134220f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13434b9ad928SBarry Smith 
13444b9ad928SBarry Smith   Level: advanced
13454b9ad928SBarry Smith 
1346562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13474b9ad928SBarry Smith @*/
1348d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1349d71ae5a4SJacob Faibussowitsch {
1350f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13514b9ad928SBarry Smith 
13524b9ad928SBarry Smith   PetscFunctionBegin;
13530700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1354c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
135531567311SBarry Smith   mg->am = form;
13569dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1357c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
13583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1359c60c7ad4SBarry Smith }
1360c60c7ad4SBarry Smith 
1361c60c7ad4SBarry Smith /*@
1362f1580f4eSBarry Smith   PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1363c60c7ad4SBarry Smith 
1364c3339decSBarry Smith   Logically Collective
1365c60c7ad4SBarry Smith 
1366c60c7ad4SBarry Smith   Input Parameter:
1367c60c7ad4SBarry Smith . pc - the preconditioner context
1368c60c7ad4SBarry Smith 
1369c60c7ad4SBarry Smith   Output Parameter:
1370f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1371c60c7ad4SBarry Smith 
1372c60c7ad4SBarry Smith   Level: advanced
1373c60c7ad4SBarry Smith 
1374562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1375c60c7ad4SBarry Smith @*/
1376d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1377d71ae5a4SJacob Faibussowitsch {
1378c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1379c60c7ad4SBarry Smith 
1380c60c7ad4SBarry Smith   PetscFunctionBegin;
1381c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1382c60c7ad4SBarry Smith   *type = mg->am;
13833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13844b9ad928SBarry Smith }
13854b9ad928SBarry Smith 
13864b9ad928SBarry Smith /*@
1387f1580f4eSBarry Smith   PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
13884b9ad928SBarry Smith   complicated cycling.
13894b9ad928SBarry Smith 
1390c3339decSBarry Smith   Logically Collective
13914b9ad928SBarry Smith 
13924b9ad928SBarry Smith   Input Parameters:
1393c2be2410SBarry Smith + pc - the multigrid context
1394f1580f4eSBarry Smith - n  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
13954b9ad928SBarry Smith 
13964b9ad928SBarry Smith   Options Database Key:
1397c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
13984b9ad928SBarry Smith 
13994b9ad928SBarry Smith   Level: advanced
14004b9ad928SBarry Smith 
1401562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
14024b9ad928SBarry Smith @*/
1403d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1404d71ae5a4SJacob Faibussowitsch {
1405f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1406f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
140779416396SBarry Smith   PetscInt       i, levels;
14084b9ad928SBarry Smith 
14094b9ad928SBarry Smith   PetscFunctionBegin;
14100700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
141169fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
141228b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1413f3fbd535SBarry Smith   levels = mglevels[0]->levels;
14142fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
14153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14164b9ad928SBarry Smith }
14174b9ad928SBarry Smith 
14188cc2d5dfSBarry Smith /*@
14198cc2d5dfSBarry Smith   PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1420f1580f4eSBarry Smith   of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
14218cc2d5dfSBarry Smith 
1422c3339decSBarry Smith   Logically Collective
14238cc2d5dfSBarry Smith 
14248cc2d5dfSBarry Smith   Input Parameters:
14258cc2d5dfSBarry Smith + pc - the multigrid context
14268cc2d5dfSBarry Smith - n  - number of cycles (default is 1)
14278cc2d5dfSBarry Smith 
14288cc2d5dfSBarry Smith   Options Database Key:
1429147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14308cc2d5dfSBarry Smith 
14318cc2d5dfSBarry Smith   Level: advanced
14328cc2d5dfSBarry Smith 
1433f1580f4eSBarry Smith   Note:
1434f1580f4eSBarry Smith   This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14358cc2d5dfSBarry Smith 
1436562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14378cc2d5dfSBarry Smith @*/
1438d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1439d71ae5a4SJacob Faibussowitsch {
1440f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14418cc2d5dfSBarry Smith 
14428cc2d5dfSBarry Smith   PetscFunctionBegin;
14430700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1444c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14452a21e185SBarry Smith   mg->cyclesperpcapply = n;
14463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14478cc2d5dfSBarry Smith }
14488cc2d5dfSBarry Smith 
1449*bbbcb081SMark Adams /*
1450*bbbcb081SMark Adams    Since the finest level KSP shares the original matrix (of the entire system), it's preconditioner
1451*bbbcb081SMark Adams    should not be updated if the whole PC is supposed to reuse the preconditioner
1452*bbbcb081SMark Adams */
1453*bbbcb081SMark Adams static PetscErrorCode PCSetReusePreconditioner_MG(PC pc, PetscBool flag)
1454*bbbcb081SMark Adams {
1455*bbbcb081SMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1456*bbbcb081SMark Adams   PC_MG_Levels **mglevels = mg->levels;
1457*bbbcb081SMark Adams   PetscInt       levels;
1458*bbbcb081SMark Adams   PC             tpc;
1459*bbbcb081SMark Adams 
1460*bbbcb081SMark Adams   PetscFunctionBegin;
1461*bbbcb081SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1462*bbbcb081SMark Adams   PetscValidLogicalCollectiveBool(pc, flag, 2);
1463*bbbcb081SMark Adams   if (mglevels) {
1464*bbbcb081SMark Adams     levels = mglevels[0]->levels;
1465*bbbcb081SMark Adams     PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1466*bbbcb081SMark Adams     tpc->reusepreconditioner = flag;
1467*bbbcb081SMark Adams     PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1468*bbbcb081SMark Adams     tpc->reusepreconditioner = flag;
1469*bbbcb081SMark Adams   }
1470*bbbcb081SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1471*bbbcb081SMark Adams }
1472*bbbcb081SMark Adams 
147366976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1474d71ae5a4SJacob Faibussowitsch {
1475fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1476fb15c04eSBarry Smith 
1477fb15c04eSBarry Smith   PetscFunctionBegin;
14782134b1e4SBarry Smith   mg->galerkin = use;
14793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1480fb15c04eSBarry Smith }
1481fb15c04eSBarry Smith 
1482c2be2410SBarry Smith /*@
148397177400SBarry Smith   PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
148482b87d87SMatthew G. Knepley   finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1485c2be2410SBarry Smith 
1486c3339decSBarry Smith   Logically Collective
1487c2be2410SBarry Smith 
1488c2be2410SBarry Smith   Input Parameters:
1489c91913d3SJed Brown + pc  - the multigrid context
1490f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1491c2be2410SBarry Smith 
1492c2be2410SBarry Smith   Options Database Key:
1493147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1494c2be2410SBarry Smith 
1495c2be2410SBarry Smith   Level: intermediate
1496c2be2410SBarry Smith 
1497f1580f4eSBarry Smith   Note:
1498f1580f4eSBarry Smith   Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1499f1580f4eSBarry Smith   use the `PCMG` construction of the coarser grids.
15001c1aac46SBarry Smith 
1501562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1502c2be2410SBarry Smith @*/
1503d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1504d71ae5a4SJacob Faibussowitsch {
1505c2be2410SBarry Smith   PetscFunctionBegin;
15060700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1507cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
15083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1509c2be2410SBarry Smith }
1510c2be2410SBarry Smith 
15113fc8bf9cSBarry Smith /*@
1512f1580f4eSBarry Smith   PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
15133fc8bf9cSBarry Smith 
15143fc8bf9cSBarry Smith   Not Collective
15153fc8bf9cSBarry Smith 
15163fc8bf9cSBarry Smith   Input Parameter:
15173fc8bf9cSBarry Smith . pc - the multigrid context
15183fc8bf9cSBarry Smith 
15193fc8bf9cSBarry Smith   Output Parameter:
1520f1580f4eSBarry 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`
15213fc8bf9cSBarry Smith 
15223fc8bf9cSBarry Smith   Level: intermediate
15233fc8bf9cSBarry Smith 
1524562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
15253fc8bf9cSBarry Smith @*/
1526d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1527d71ae5a4SJacob Faibussowitsch {
1528f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
15293fc8bf9cSBarry Smith 
15303fc8bf9cSBarry Smith   PetscFunctionBegin;
15310700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15322134b1e4SBarry Smith   *galerkin = mg->galerkin;
15333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15343fc8bf9cSBarry Smith }
15353fc8bf9cSBarry Smith 
153666976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1537d71ae5a4SJacob Faibussowitsch {
1538f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1539f3b08a26SMatthew G. Knepley 
1540f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1541f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
15423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1543f3b08a26SMatthew G. Knepley }
1544f3b08a26SMatthew G. Knepley 
154566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1546d71ae5a4SJacob Faibussowitsch {
1547f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1548f3b08a26SMatthew G. Knepley 
1549f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1550f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
15513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1552f3b08a26SMatthew G. Knepley }
1553f3b08a26SMatthew G. Knepley 
155466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1555d71ae5a4SJacob Faibussowitsch {
15562b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15572b3cbbdaSStefano Zampini 
15582b3cbbdaSStefano Zampini   PetscFunctionBegin;
15592b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15602b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
1561a077d33dSBarry Smith   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
15623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15632b3cbbdaSStefano Zampini }
15642b3cbbdaSStefano Zampini 
156566976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1566d71ae5a4SJacob Faibussowitsch {
15672b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15682b3cbbdaSStefano Zampini 
15692b3cbbdaSStefano Zampini   PetscFunctionBegin;
15702b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15722b3cbbdaSStefano Zampini }
15732b3cbbdaSStefano Zampini 
157466976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1575d71ae5a4SJacob Faibussowitsch {
157641b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
157741b6fd38SMatthew G. Knepley 
157841b6fd38SMatthew G. Knepley   PetscFunctionBegin;
157941b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
15803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
158141b6fd38SMatthew G. Knepley }
158241b6fd38SMatthew G. Knepley 
158366976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1584d71ae5a4SJacob Faibussowitsch {
158541b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
158641b6fd38SMatthew G. Knepley 
158741b6fd38SMatthew G. Knepley   PetscFunctionBegin;
158841b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
15893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159041b6fd38SMatthew G. Knepley }
159141b6fd38SMatthew G. Knepley 
1592cc4c1da9SBarry Smith /*@
15932b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15942b3cbbdaSStefano Zampini 
15952b3cbbdaSStefano 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.
15962b3cbbdaSStefano Zampini 
1597c3339decSBarry Smith   Logically Collective
15982b3cbbdaSStefano Zampini 
15992b3cbbdaSStefano Zampini   Input Parameters:
16002b3cbbdaSStefano Zampini + pc    - the multigrid context
16012b3cbbdaSStefano Zampini - ctype - the type of coarse space
16022b3cbbdaSStefano Zampini 
16032b3cbbdaSStefano Zampini   Options Database Keys:
16042b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
1605a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw`
16062b3cbbdaSStefano Zampini 
16072b3cbbdaSStefano Zampini   Level: intermediate
16082b3cbbdaSStefano Zampini 
1609a077d33dSBarry Smith   Note:
1610a077d33dSBarry Smith   Requires a `DM` with specific functionality be attached to the `PC`.
1611a077d33dSBarry Smith 
1612a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM`
16132b3cbbdaSStefano Zampini @*/
1614d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1615d71ae5a4SJacob Faibussowitsch {
16162b3cbbdaSStefano Zampini   PetscFunctionBegin;
16172b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16182b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
16192b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
16203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16212b3cbbdaSStefano Zampini }
16222b3cbbdaSStefano Zampini 
1623cc4c1da9SBarry Smith /*@
16242b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
16252b3cbbdaSStefano Zampini 
16262b3cbbdaSStefano Zampini   Not Collective
16272b3cbbdaSStefano Zampini 
16282b3cbbdaSStefano Zampini   Input Parameter:
16292b3cbbdaSStefano Zampini . pc - the multigrid context
16302b3cbbdaSStefano Zampini 
16312b3cbbdaSStefano Zampini   Output Parameter:
16322b3cbbdaSStefano Zampini . ctype - the type of coarse space
16332b3cbbdaSStefano Zampini 
16342b3cbbdaSStefano Zampini   Level: intermediate
16352b3cbbdaSStefano Zampini 
1636562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
16372b3cbbdaSStefano Zampini @*/
1638d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1639d71ae5a4SJacob Faibussowitsch {
16402b3cbbdaSStefano Zampini   PetscFunctionBegin;
16412b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16424f572ea9SToby Isaac   PetscAssertPointer(ctype, 2);
16432b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
16443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16452b3cbbdaSStefano Zampini }
16462b3cbbdaSStefano Zampini 
16472b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1648f3b08a26SMatthew G. Knepley /*@
1649f3b08a26SMatthew 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.
1650f3b08a26SMatthew G. Knepley 
1651c3339decSBarry Smith   Logically Collective
1652f3b08a26SMatthew G. Knepley 
1653f3b08a26SMatthew G. Knepley   Input Parameters:
1654f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1655f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1656f3b08a26SMatthew G. Knepley 
1657f3b08a26SMatthew G. Knepley   Options Database Keys:
1658f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1659f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1660f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1661f3b08a26SMatthew G. Knepley 
1662f3b08a26SMatthew G. Knepley   Level: intermediate
1663f3b08a26SMatthew G. Knepley 
1664562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1665f3b08a26SMatthew G. Knepley @*/
1666d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1667d71ae5a4SJacob Faibussowitsch {
1668f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1669f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1670cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1672f3b08a26SMatthew G. Knepley }
1673f3b08a26SMatthew G. Knepley 
1674f3b08a26SMatthew G. Knepley /*@
1675f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1676f1580f4eSBarry Smith   and thus accurately interpolated.
1677f3b08a26SMatthew G. Knepley 
167820f4b53cSBarry Smith   Not Collective
1679f3b08a26SMatthew G. Knepley 
1680f3b08a26SMatthew G. Knepley   Input Parameter:
1681f3b08a26SMatthew G. Knepley . pc - the multigrid context
1682f3b08a26SMatthew G. Knepley 
1683f3b08a26SMatthew G. Knepley   Output Parameter:
1684f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1685f3b08a26SMatthew G. Knepley 
1686f3b08a26SMatthew G. Knepley   Level: intermediate
1687f3b08a26SMatthew G. Knepley 
1688562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1689f3b08a26SMatthew G. Knepley @*/
1690d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1691d71ae5a4SJacob Faibussowitsch {
1692f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1693f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16944f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
1695cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
16963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1697f3b08a26SMatthew G. Knepley }
1698f3b08a26SMatthew G. Knepley 
16994b9ad928SBarry Smith /*@
170041b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
170141b6fd38SMatthew G. Knepley 
1702c3339decSBarry Smith   Logically Collective
170341b6fd38SMatthew G. Knepley 
170441b6fd38SMatthew G. Knepley   Input Parameters:
170541b6fd38SMatthew G. Knepley + pc - the multigrid context
170641b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
170741b6fd38SMatthew G. Knepley 
1708f1580f4eSBarry Smith   Options Database Key:
170941b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
171041b6fd38SMatthew G. Knepley 
171141b6fd38SMatthew G. Knepley   Level: intermediate
171241b6fd38SMatthew G. Knepley 
1713562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
171441b6fd38SMatthew G. Knepley @*/
1715d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1716d71ae5a4SJacob Faibussowitsch {
171741b6fd38SMatthew G. Knepley   PetscFunctionBegin;
171841b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1719cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
17203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172141b6fd38SMatthew G. Knepley }
172241b6fd38SMatthew G. Knepley 
172341b6fd38SMatthew G. Knepley /*@
172441b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
172541b6fd38SMatthew G. Knepley 
172620f4b53cSBarry Smith   Not Collective
172741b6fd38SMatthew G. Knepley 
172841b6fd38SMatthew G. Knepley   Input Parameter:
172941b6fd38SMatthew G. Knepley . pc - the multigrid context
173041b6fd38SMatthew G. Knepley 
173141b6fd38SMatthew G. Knepley   Output Parameter:
173241b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
173341b6fd38SMatthew G. Knepley 
173441b6fd38SMatthew G. Knepley   Level: intermediate
173541b6fd38SMatthew G. Knepley 
1736562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
173741b6fd38SMatthew G. Knepley @*/
1738d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1739d71ae5a4SJacob Faibussowitsch {
174041b6fd38SMatthew G. Knepley   PetscFunctionBegin;
174141b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17424f572ea9SToby Isaac   PetscAssertPointer(cr, 2);
1743cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
17443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
174541b6fd38SMatthew G. Knepley }
174641b6fd38SMatthew G. Knepley 
174741b6fd38SMatthew G. Knepley /*@
174806792cafSBarry Smith   PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1749f1580f4eSBarry Smith   on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1750710315b6SLawrence Mitchell   pre- and post-smoothing steps.
175106792cafSBarry Smith 
1752c3339decSBarry Smith   Logically Collective
175306792cafSBarry Smith 
175406792cafSBarry Smith   Input Parameters:
1755feefa0e1SJacob Faibussowitsch + pc - the multigrid context
175606792cafSBarry Smith - n  - the number of smoothing steps
175706792cafSBarry Smith 
175806792cafSBarry Smith   Options Database Key:
1759a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
176006792cafSBarry Smith 
176106792cafSBarry Smith   Level: advanced
176206792cafSBarry Smith 
1763f1580f4eSBarry Smith   Note:
1764f1580f4eSBarry 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.
176506792cafSBarry Smith 
1766562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()`
176706792cafSBarry Smith @*/
1768d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1769d71ae5a4SJacob Faibussowitsch {
177006792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
177106792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
177206792cafSBarry Smith   PetscInt       i, levels;
177306792cafSBarry Smith 
177406792cafSBarry Smith   PetscFunctionBegin;
177506792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
177606792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
177728b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
177806792cafSBarry Smith   levels = mglevels[0]->levels;
177906792cafSBarry Smith 
178006792cafSBarry Smith   for (i = 1; i < levels; i++) {
1781fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
1782fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
178306792cafSBarry Smith     mg->default_smoothu = n;
178406792cafSBarry Smith     mg->default_smoothd = n;
178506792cafSBarry Smith   }
17863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
178706792cafSBarry Smith }
178806792cafSBarry Smith 
1789f442ab6aSBarry Smith /*@
1790f1580f4eSBarry Smith   PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1791710315b6SLawrence Mitchell   and adds the suffix _up to the options name
1792f442ab6aSBarry Smith 
1793c3339decSBarry Smith   Logically Collective
1794f442ab6aSBarry Smith 
1795f1580f4eSBarry Smith   Input Parameter:
1796f442ab6aSBarry Smith . pc - the preconditioner context
1797f442ab6aSBarry Smith 
1798f442ab6aSBarry Smith   Options Database Key:
1799147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1800f442ab6aSBarry Smith 
1801f442ab6aSBarry Smith   Level: advanced
1802f442ab6aSBarry Smith 
1803f1580f4eSBarry Smith   Note:
1804f1580f4eSBarry 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.
1805f442ab6aSBarry Smith 
1806562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()`
1807f442ab6aSBarry Smith @*/
1808d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1809d71ae5a4SJacob Faibussowitsch {
1810f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1811f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1812f442ab6aSBarry Smith   PetscInt       i, levels;
1813f442ab6aSBarry Smith   KSP            subksp;
1814f442ab6aSBarry Smith 
1815f442ab6aSBarry Smith   PetscFunctionBegin;
1816f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
181728b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1818f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1819f442ab6aSBarry Smith 
1820f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1821710315b6SLawrence Mitchell     const char *prefix = NULL;
1822f442ab6aSBarry Smith     /* make sure smoother up and down are different */
18239566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
18249566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
18259566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
18269566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1827f442ab6aSBarry Smith   }
18283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1829f442ab6aSBarry Smith }
1830f442ab6aSBarry Smith 
183107a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
183266976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1833d71ae5a4SJacob Faibussowitsch {
183407a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
183507a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
183607a4832bSFande Kong   Mat           *mat;
183707a4832bSFande Kong   PetscInt       l;
183807a4832bSFande Kong 
183907a4832bSFande Kong   PetscFunctionBegin;
184028b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
184207a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
184307a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
18449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
184507a4832bSFande Kong   }
184607a4832bSFande Kong   *num_levels     = mg->nlevels;
184707a4832bSFande Kong   *interpolations = mat;
18483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
184907a4832bSFande Kong }
185007a4832bSFande Kong 
185107a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
185266976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1853d71ae5a4SJacob Faibussowitsch {
185407a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
185507a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
185607a4832bSFande Kong   PetscInt       l;
185707a4832bSFande Kong   Mat           *mat;
185807a4832bSFande Kong 
185907a4832bSFande Kong   PetscFunctionBegin;
186028b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
186207a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
1863f4f49eeaSPierre Jolivet     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l]));
18649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
186507a4832bSFande Kong   }
186607a4832bSFande Kong   *num_levels      = mg->nlevels;
186707a4832bSFande Kong   *coarseOperators = mat;
18683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
186907a4832bSFande Kong }
187007a4832bSFande Kong 
1871f3b08a26SMatthew G. Knepley /*@C
1872f1580f4eSBarry Smith   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1873f3b08a26SMatthew G. Knepley 
1874cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1875f3b08a26SMatthew G. Knepley 
1876f3b08a26SMatthew G. Knepley   Input Parameters:
1877f3b08a26SMatthew G. Knepley + name     - name of the constructor
18784d4d2bdcSBarry Smith - function - constructor routine, see `PCMGCoarseSpaceConstructorFn`
1879f3b08a26SMatthew G. Knepley 
1880f3b08a26SMatthew G. Knepley   Level: advanced
1881f3b08a26SMatthew G. Knepley 
1882feefa0e1SJacob Faibussowitsch   Developer Notes:
18834d4d2bdcSBarry Smith   This does not appear to be used anywhere
1884f1580f4eSBarry Smith 
18854d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1886f3b08a26SMatthew G. Knepley @*/
18874d4d2bdcSBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function)
1888d71ae5a4SJacob Faibussowitsch {
1889f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
18909566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
18919566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
18923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1893f3b08a26SMatthew G. Knepley }
1894f3b08a26SMatthew G. Knepley 
1895f3b08a26SMatthew G. Knepley /*@C
1896f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1897f3b08a26SMatthew G. Knepley 
1898cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1899f3b08a26SMatthew G. Knepley 
1900f3b08a26SMatthew G. Knepley   Input Parameter:
1901f3b08a26SMatthew G. Knepley . name - name of the constructor
1902f3b08a26SMatthew G. Knepley 
1903f3b08a26SMatthew G. Knepley   Output Parameter:
1904f3b08a26SMatthew G. Knepley . function - constructor routine
1905f3b08a26SMatthew G. Knepley 
1906f3b08a26SMatthew G. Knepley   Level: advanced
1907f3b08a26SMatthew G. Knepley 
19084d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1909f3b08a26SMatthew G. Knepley @*/
19104d4d2bdcSBarry Smith PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function)
1911d71ae5a4SJacob Faibussowitsch {
1912f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
19139566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
19143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1915f3b08a26SMatthew G. Knepley }
1916f3b08a26SMatthew G. Knepley 
19173b09bd56SBarry Smith /*MC
1918ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
19193b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
19203b09bd56SBarry Smith 
19213b09bd56SBarry Smith    Options Database Keys:
19223b09bd56SBarry Smith +  -pc_mg_levels <nlevels>                            - number of levels including finest
1923391689abSStefano Zampini .  -pc_mg_cycle_type <v,w>                            - provide the cycle desired
19248c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
19253b09bd56SBarry Smith .  -pc_mg_log                                         - log information about time spent on each level of the solver
1926710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup                           - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
19272134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>               - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
19288cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles                        - number of cycles to use as the preconditioner (defaults to 1)
19298cf6037eSBarry Smith .  -pc_mg_dump_matlab                                  - dumps the matrices for each level and the restriction/interpolation matrices
1930a3b724e8SBarry Smith                                                          to a `PETSCVIEWERSOCKET` for reading from MATLAB.
19318cf6037eSBarry Smith -  -pc_mg_dump_binary                                  -dumps the matrices for each level and the restriction/interpolation matrices
19328cf6037eSBarry Smith                                                         to the binary output file called binaryoutput
19333b09bd56SBarry Smith 
193420f4b53cSBarry Smith    Level: intermediate
193520f4b53cSBarry Smith 
193695452b02SPatrick Sanan    Notes:
193704c3f3b8SBarry Smith    The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard
19388f4fb22eSMark Adams    options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`,
19398f4fb22eSMark Adams    and the finest where `-mg_fine_` can override `-mg_levels_`.  One can set different preconditioners etc on specific levels with the prefix
19408f4fb22eSMark Adams    `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example
194104c3f3b8SBarry Smith .vb
194204c3f3b8SBarry Smith    -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor
194304c3f3b8SBarry Smith .ve
194404c3f3b8SBarry Smith    These options also work for controlling the smoothers etc inside `PCGAMG`
194504c3f3b8SBarry Smith 
1946e87b5d96SPierre 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
19473b09bd56SBarry Smith 
19488cf6037eSBarry Smith    When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19498cf6037eSBarry Smith 
1950f1580f4eSBarry Smith    When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
195123067569SBarry Smith    is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
195223067569SBarry Smith    (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
195323067569SBarry Smith    residual is computed at the end of each cycle.
195423067569SBarry Smith 
195504c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1956db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1957db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1958db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1959f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1960f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19613b09bd56SBarry Smith M*/
19623b09bd56SBarry Smith 
1963d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1964d71ae5a4SJacob Faibussowitsch {
1965f3fbd535SBarry Smith   PC_MG *mg;
1966f3fbd535SBarry Smith 
19674b9ad928SBarry Smith   PetscFunctionBegin;
19684dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
19693ec1f749SStefano Zampini   pc->data               = mg;
1970f3fbd535SBarry Smith   mg->nlevels            = -1;
197110eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19722134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1973f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1974f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1975f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1976f3fbd535SBarry Smith 
197737a44384SMark Adams   pc->useAmat = PETSC_TRUE;
197837a44384SMark Adams 
19794b9ad928SBarry Smith   pc->ops->apply             = PCApply_MG;
1980fcb023d4SJed Brown   pc->ops->applytranspose    = PCApplyTranspose_MG;
198130b0564aSStefano Zampini   pc->ops->matapply          = PCMatApply_MG;
19824dbf25a8SPierre Jolivet   pc->ops->matapplytranspose = PCMatApplyTranspose_MG;
19834b9ad928SBarry Smith   pc->ops->setup             = PCSetUp_MG;
1984a06653b4SBarry Smith   pc->ops->reset             = PCReset_MG;
19854b9ad928SBarry Smith   pc->ops->destroy           = PCDestroy_MG;
19864b9ad928SBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_MG;
19874b9ad928SBarry Smith   pc->ops->view              = PCView_MG;
1988fb15c04eSBarry Smith 
19899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
19909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
1991*bbbcb081SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", PCSetReusePreconditioner_MG));
19929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
19939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
19949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
19959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
19969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
19979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
19989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
19999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
20002b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
20012b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
20023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20034b9ad928SBarry Smith }
2004