xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision bcefaa27c4b97575a5b90376350e99dfa4f79ec8)
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;
51218e2965SBarry Smith 
529566063dSJacob Faibussowitsch       PetscCall(VecNorm(mglevels->r, NORM_2, &rnorm));
534b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
5470441072SBarry Smith         if (rnorm < mg->abstol) {
554d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
569566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n", (double)rnorm, (double)mg->abstol));
574b9ad928SBarry Smith         } else {
584d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
599566063dSJacob 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));
604b9ad928SBarry Smith         }
613ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
624b9ad928SBarry Smith       }
634b9ad928SBarry Smith     }
644b9ad928SBarry Smith 
6531567311SBarry Smith     mgc = *(mglevelsin - 1);
669566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
67fcb023d4SJed Brown     if (!transpose) {
689566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->restrct, mglevels->R, &mgc->B));
699566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->restrct, mglevels->r, mgc->b));
70fcb023d4SJed Brown     } else {
719566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate, mglevels->R, &mgc->B));
729566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->interpolate, mglevels->r, mgc->b));
73fcb023d4SJed Brown     }
749566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
7530b0564aSStefano Zampini     if (matapp) {
7630b0564aSStefano Zampini       if (!mgc->X) {
779566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(mgc->B, MAT_DO_NOT_COPY_VALUES, &mgc->X));
7830b0564aSStefano Zampini       } else {
799566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(mgc->X));
8030b0564aSStefano Zampini       }
8130b0564aSStefano Zampini     } else {
829566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mgc->x));
8330b0564aSStefano Zampini     }
8448a46eb9SPierre Jolivet     while (cycles--) PetscCall(PCMGMCycle_Private(pc, mglevelsin - 1, transpose, matapp, reason));
859566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict, 0, 0, 0, 0));
86fcb023d4SJed Brown     if (!transpose) {
879566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate, mgc->X, mglevels->X, &mglevels->X));
889566063dSJacob Faibussowitsch       else PetscCall(MatInterpolateAdd(mglevels->interpolate, mgc->x, mglevels->x, mglevels->x));
89fcb023d4SJed Brown     } else {
909566063dSJacob Faibussowitsch       PetscCall(MatInterpolateAdd(mglevels->restrct, mgc->x, mglevels->x, mglevels->x));
91fcb023d4SJed Brown     }
929566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict, 0, 0, 0, 0));
939566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve, 0, 0, 0, 0));
94fcb023d4SJed Brown     if (!transpose) {
9530b0564aSStefano Zampini       if (matapp) {
969566063dSJacob Faibussowitsch         PetscCall(KSPMatSolve(mglevels->smoothu, mglevels->B, mglevels->X)); /* post smooth */
979566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, NULL));
9830b0564aSStefano Zampini       } else {
999566063dSJacob Faibussowitsch         PetscCall(KSPSolve(mglevels->smoothu, mglevels->b, mglevels->x)); /* post smooth */
1009566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu, pc, mglevels->x));
10130b0564aSStefano Zampini       }
102fcb023d4SJed Brown     } else {
10328b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
1049566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(mglevels->smoothd, mglevels->b, mglevels->x)); /* post smooth */
1059566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd, pc, mglevels->x));
106fcb023d4SJed Brown     }
10741b6fd38SMatthew G. Knepley     if (mglevels->cr) {
10820654ebbSStefano Zampini       Mat crA;
10920654ebbSStefano Zampini 
11028b400f6SJacob Faibussowitsch       PetscCheck(!matapp, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Not supported");
11141b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1129566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1139566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
11420654ebbSStefano Zampini       PetscCall(KSPGetOperators(mglevels->cr, &crA, NULL));
11520654ebbSStefano Zampini       PetscCall(KSPSetNoisy_Private(crA, mglevels->crx));
1169566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr, mglevels->crb, mglevels->crx)); /* compatible relaxation */
1179566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr, pc, mglevels->crx));
11841b6fd38SMatthew G. Knepley     }
1199566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve, 0, 0, 0, 0));
1204b9ad928SBarry Smith   }
1213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1224b9ad928SBarry Smith }
1234b9ad928SBarry Smith 
124d71ae5a4SJacob 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)
125d71ae5a4SJacob Faibussowitsch {
126f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
127f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
128391689abSStefano Zampini   PC             tpc;
129391689abSStefano Zampini   PetscBool      changeu, changed;
130f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
1314b9ad928SBarry Smith 
1324b9ad928SBarry Smith   PetscFunctionBegin;
133a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
134a762d673SBarry Smith   for (i = 0; i < levels; i++) {
135a762d673SBarry Smith     if (!mglevels[i]->A) {
1369566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
1379566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
138a762d673SBarry Smith     }
139a762d673SBarry Smith   }
140391689abSStefano Zampini 
1419566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1429566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
1439566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1449566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
145391689abSStefano Zampini   if (!changed && !changeu) {
1469566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels - 1]->b));
147f3fbd535SBarry Smith     mglevels[levels - 1]->b = b;
148391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
149391689abSStefano Zampini     if (!mglevels[levels - 1]->b) {
150391689abSStefano Zampini       Vec *vec;
151391689abSStefano Zampini 
1529566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
153391689abSStefano Zampini       mglevels[levels - 1]->b = *vec;
1549566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
155391689abSStefano Zampini     }
1569566063dSJacob Faibussowitsch     PetscCall(VecCopy(b, mglevels[levels - 1]->b));
157391689abSStefano Zampini   }
158f3fbd535SBarry Smith   mglevels[levels - 1]->x = x;
1594b9ad928SBarry Smith 
16031567311SBarry Smith   mg->rtol   = rtol;
16131567311SBarry Smith   mg->abstol = abstol;
16231567311SBarry Smith   mg->dtol   = dtol;
1634b9ad928SBarry Smith   if (rtol) {
1644b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1654b9ad928SBarry Smith     PetscReal rnorm;
166218e2965SBarry Smith 
1677319c654SBarry Smith     if (zeroguess) {
1689566063dSJacob Faibussowitsch       PetscCall(VecNorm(b, NORM_2, &rnorm));
1697319c654SBarry Smith     } else {
1709566063dSJacob Faibussowitsch       PetscCall((*mglevels[levels - 1]->residual)(mglevels[levels - 1]->A, b, x, w));
1719566063dSJacob Faibussowitsch       PetscCall(VecNorm(w, NORM_2, &rnorm));
1727319c654SBarry Smith     }
17331567311SBarry Smith     mg->ttol = PetscMax(rtol * rnorm, abstol);
1742fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1752fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1764b9ad928SBarry Smith 
1774d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
178336babb1SJed Brown      stop prematurely due to small residual */
1794d0a8057SBarry Smith   for (i = 1; i < levels; i++) {
180fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
181f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
18223067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
1839566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
184fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->smoothd, 0, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
1854b9ad928SBarry Smith     }
1864d0a8057SBarry Smith   }
1874d0a8057SBarry Smith 
188dd460d27SBarry Smith   *reason = PCRICHARDSON_NOT_SET;
1894d0a8057SBarry Smith   for (i = 0; i < its; i++) {
1909566063dSJacob Faibussowitsch     PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, PETSC_FALSE, PETSC_FALSE, reason));
1914d0a8057SBarry Smith     if (*reason) break;
1924d0a8057SBarry Smith   }
193dd460d27SBarry Smith   if (*reason == PCRICHARDSON_NOT_SET) *reason = PCRICHARDSON_CONVERGED_ITS;
1944d0a8057SBarry Smith   *outits = i;
195391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels - 1]->b = NULL;
1963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1974b9ad928SBarry Smith }
1984b9ad928SBarry Smith 
199d71ae5a4SJacob Faibussowitsch PetscErrorCode PCReset_MG(PC pc)
200d71ae5a4SJacob Faibussowitsch {
2013aeaf226SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
2023aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
2032b3cbbdaSStefano Zampini   PetscInt       i, n;
2043aeaf226SBarry Smith 
2053aeaf226SBarry Smith   PetscFunctionBegin;
2063aeaf226SBarry Smith   if (mglevels) {
2073aeaf226SBarry Smith     n = mglevels[0]->levels;
2083aeaf226SBarry Smith     for (i = 0; i < n - 1; i++) {
2099566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->r));
2109566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->b));
2119566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->x));
2129566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->R));
2139566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->B));
2149566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->X));
2159566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crx));
2169566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i]->crb));
2179566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->restrct));
2189566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->interpolate));
2199566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i + 1]->inject));
2209566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[i + 1]->rscale));
2213aeaf226SBarry Smith     }
2229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crx));
2239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->crb));
224391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
225391689abSStefano Zampini        changes the rhs during PreSolve */
2269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[n - 1]->b));
2279566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mglevels[n - 1]->B));
2283aeaf226SBarry Smith 
2293aeaf226SBarry Smith     for (i = 0; i < n; i++) {
2302b3cbbdaSStefano Zampini       PetscCall(MatDestroy(&mglevels[i]->coarseSpace));
2319566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[i]->A));
23248a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPReset(mglevels[i]->smoothd));
2339566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2349566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2353aeaf226SBarry Smith     }
236f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2373aeaf226SBarry Smith   }
2383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2393aeaf226SBarry Smith }
2403aeaf226SBarry Smith 
24141b6fd38SMatthew G. Knepley /* Implementing CR
24241b6fd38SMatthew G. Knepley 
24341b6fd38SMatthew 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
24441b6fd38SMatthew G. Knepley 
24541b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
24641b6fd38SMatthew G. Knepley 
24741b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
24841b6fd38SMatthew G. Knepley 
24941b6fd38SMatthew G. Knepley   Inj^T Inj
25041b6fd38SMatthew G. Knepley 
25141b6fd38SMatthew G. Knepley and
25241b6fd38SMatthew G. Knepley 
25341b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
25441b6fd38SMatthew G. Knepley 
25541b6fd38SMatthew G. Knepley since
25641b6fd38SMatthew G. Knepley 
25741b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
25841b6fd38SMatthew G. Knepley 
25941b6fd38SMatthew G. Knepley Brannick suggests
26041b6fd38SMatthew G. Knepley 
26141b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
26241b6fd38SMatthew G. Knepley 
26341b6fd38SMatthew 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
26441b6fd38SMatthew G. Knepley 
26541b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
26641b6fd38SMatthew G. Knepley 
26741b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
26841b6fd38SMatthew G. Knepley 
26941b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
27041b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
27141b6fd38SMatthew G. Knepley */
27241b6fd38SMatthew G. Knepley 
27341b6fd38SMatthew G. Knepley typedef struct {
27441b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
27541b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
27641b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27741b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
27841b6fd38SMatthew G. Knepley } CRContext;
27941b6fd38SMatthew G. Knepley 
280d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRSetup_Private(PC pc)
281d71ae5a4SJacob Faibussowitsch {
28241b6fd38SMatthew G. Knepley   CRContext *ctx;
28341b6fd38SMatthew G. Knepley   Mat        It;
28441b6fd38SMatthew G. Knepley 
28541b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2869566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2879566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
28828b400f6SJacob Faibussowitsch   PetscCheck(It, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2899566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2909566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2919566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2929566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S, 1.0));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29441b6fd38SMatthew G. Knepley }
29541b6fd38SMatthew G. Knepley 
296d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
297d71ae5a4SJacob Faibussowitsch {
29841b6fd38SMatthew G. Knepley   CRContext *ctx;
29941b6fd38SMatthew G. Knepley 
30041b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3019566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3029566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
3033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30441b6fd38SMatthew G. Knepley }
30541b6fd38SMatthew G. Knepley 
306d71ae5a4SJacob Faibussowitsch static PetscErrorCode CRDestroy_Private(PC pc)
307d71ae5a4SJacob Faibussowitsch {
30841b6fd38SMatthew G. Knepley   CRContext *ctx;
30941b6fd38SMatthew G. Knepley 
31041b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3119566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3149566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3159566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
3163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31741b6fd38SMatthew G. Knepley }
31841b6fd38SMatthew G. Knepley 
319d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
320d71ae5a4SJacob Faibussowitsch {
32141b6fd38SMatthew G. Knepley   CRContext *ctx;
32241b6fd38SMatthew G. Knepley 
32341b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3249566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), cr));
3259566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*cr, "S (complementary projector to injection)"));
3269566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
32741b6fd38SMatthew G. Knepley   ctx->mg = pc;
32841b6fd38SMatthew G. Knepley   ctx->l  = l;
3299566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3309566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3319566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3329566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3339566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
3343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33541b6fd38SMatthew G. Knepley }
33641b6fd38SMatthew G. Knepley 
3378f4fb22eSMark Adams PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char[], const char[], const char *[], const char *[], PetscBool *);
3388f4fb22eSMark Adams 
339d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels_MG(PC pc, PetscInt levels, MPI_Comm *comms)
340d71ae5a4SJacob Faibussowitsch {
341f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG *)pc->data;
342ce94432eSBarry Smith   MPI_Comm       comm;
3433aeaf226SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
34410eca3edSLisandro Dalcin   PCMGType       mgtype   = mg->am;
34510167fecSBarry Smith   PetscInt       mgctype  = (PetscInt)PC_MG_CYCLE_V;
346f3fbd535SBarry Smith   PetscInt       i;
347f3fbd535SBarry Smith   PetscMPIInt    size;
348f3fbd535SBarry Smith   const char    *prefix;
349f3fbd535SBarry Smith   PC             ipc;
3503aeaf226SBarry Smith   PetscInt       n;
3514b9ad928SBarry Smith 
3524b9ad928SBarry Smith   PetscFunctionBegin;
3530700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
354548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc, levels, 2);
3553ba16761SJacob Faibussowitsch   if (mg->nlevels == levels) PetscFunctionReturn(PETSC_SUCCESS);
3569566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
3573aeaf226SBarry Smith   if (mglevels) {
35810eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
3593aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
3609566063dSJacob Faibussowitsch     PetscCall(PCReset_MG(pc));
3613aeaf226SBarry Smith     n = mglevels[0]->levels;
3623aeaf226SBarry Smith     for (i = 0; i < n; i++) {
36348a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3649566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3659566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3669566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3673aeaf226SBarry Smith     }
3689566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3693aeaf226SBarry Smith   }
370f3fbd535SBarry Smith 
371f3fbd535SBarry Smith   mg->nlevels = levels;
372f3fbd535SBarry Smith 
3739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels, &mglevels));
374f3fbd535SBarry Smith 
3759566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
376f3fbd535SBarry Smith 
377a9db87a2SMatthew G Knepley   mg->stageApply = 0;
378f3fbd535SBarry Smith   for (i = 0; i < levels; i++) {
3794dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(&mglevels[i]));
3802fa5cd67SKarl Rupp 
381f3fbd535SBarry Smith     mglevels[i]->level               = i;
382f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
38310eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
384336babb1SJed Brown     mg->default_smoothu              = 2;
385336babb1SJed Brown     mg->default_smoothd              = 2;
38663e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
38763e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
38863e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
38963e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
390f3fbd535SBarry Smith 
391f3fbd535SBarry Smith     if (comms) comm = comms[i];
392d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3939566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &mglevels[i]->smoothd));
3943821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->smoothd, pc->kspnestlevel));
3959566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd, pc->erroriffailure));
3969566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd, (PetscObject)pc, levels - i));
3979566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, prefix));
3989566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
3998f4fb22eSMark Adams       if (i == 0 && levels > 1) { // coarse grid
4009566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd, "mg_coarse_"));
401f3fbd535SBarry Smith 
4029dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4039566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd, KSPPREONLY));
4049566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd, &ipc));
4059566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm, &size));
406f3fbd535SBarry Smith         if (size > 1) {
4079566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCREDUNDANT));
408f3fbd535SBarry Smith         } else {
4099566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc, PCLU));
410f3fbd535SBarry Smith         }
4119566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc, MAT_SHIFT_INBLOCKS));
4128f4fb22eSMark Adams       } else {
4138f4fb22eSMark Adams         char tprefix[128];
4148f4fb22eSMark Adams 
4158f4fb22eSMark Adams         PetscCall(KSPSetType(mglevels[i]->smoothd, KSPCHEBYSHEV));
4168f4fb22eSMark Adams         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd, KSPConvergedSkip, NULL, NULL));
4178f4fb22eSMark Adams         PetscCall(KSPSetNormType(mglevels[i]->smoothd, KSP_NORM_NONE));
4188f4fb22eSMark Adams         PetscCall(KSPGetPC(mglevels[i]->smoothd, &ipc));
4198f4fb22eSMark Adams         PetscCall(PCSetType(ipc, PCSOR));
420fb842aefSJose E. Roman         PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
4218f4fb22eSMark Adams 
4228f4fb22eSMark Adams         if (i == levels - 1 && levels > 1) { // replace 'mg_finegrid_' with 'mg_levels_X_'
4238f4fb22eSMark Adams           PetscBool set;
424218e2965SBarry Smith 
4258f4fb22eSMark Adams           PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)mglevels[i]->smoothd)->options, ((PetscObject)mglevels[i]->smoothd)->prefix, "-mg_fine_", NULL, NULL, &set));
4268f4fb22eSMark Adams           if (set) {
4278f4fb22eSMark Adams             if (prefix) PetscCall(PetscSNPrintf(tprefix, 128, "%smg_fine_", prefix));
4288f4fb22eSMark Adams             else PetscCall(PetscSNPrintf(tprefix, 128, "mg_fine_"));
4298f4fb22eSMark Adams             PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd, tprefix));
4308f4fb22eSMark Adams           } else {
431835f2295SStefano Zampini             PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4328f4fb22eSMark Adams             PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4338f4fb22eSMark Adams           }
4348f4fb22eSMark Adams         } else {
435835f2295SStefano Zampini           PetscCall(PetscSNPrintf(tprefix, 128, "mg_levels_%" PetscInt_FMT "_", i));
4368f4fb22eSMark Adams           PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd, tprefix));
4378f4fb22eSMark Adams         }
438f3fbd535SBarry Smith       }
439d5a8f7e6SBarry Smith     }
440f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
44131567311SBarry Smith     mg->rtol             = 0.0;
44231567311SBarry Smith     mg->abstol           = 0.0;
44331567311SBarry Smith     mg->dtol             = 0.0;
44431567311SBarry Smith     mg->ttol             = 0.0;
44531567311SBarry Smith     mg->cyclesperpcapply = 1;
446f3fbd535SBarry Smith   }
447f3fbd535SBarry Smith   mg->levels = mglevels;
4489566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc, mgtype));
4493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4504b9ad928SBarry Smith }
4514b9ad928SBarry Smith 
45297d33e41SMatthew G. Knepley /*@C
453f1580f4eSBarry Smith   PCMGSetLevels - Sets the number of levels to use with `PCMG`.
454f1580f4eSBarry Smith   Must be called before any other `PCMG` routine.
45597d33e41SMatthew G. Knepley 
456c3339decSBarry Smith   Logically Collective
45797d33e41SMatthew G. Knepley 
45897d33e41SMatthew G. Knepley   Input Parameters:
45997d33e41SMatthew G. Knepley + pc     - the preconditioner context
46097d33e41SMatthew G. Knepley . levels - the number of levels
46197d33e41SMatthew G. Knepley - comms  - optional communicators for each level; this is to allow solving the coarser problems
462d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
46320f4b53cSBarry Smith            you must pass `MPI_COMM_NULL`. Use comms = `NULL` to specify that all processes
46405552d4bSJunchao Zhang            should participate in each level of problem.
46597d33e41SMatthew G. Knepley 
466efba3485SBarry Smith   Options Database Key:
467efba3485SBarry Smith . -pc_mg_levels <levels> - set the number of levels to use
468efba3485SBarry Smith 
46997d33e41SMatthew G. Knepley   Level: intermediate
47097d33e41SMatthew G. Knepley 
47197d33e41SMatthew G. Knepley   Notes:
47220f4b53cSBarry Smith   If the number of levels is one then the multigrid uses the `-mg_levels` prefix
4738f4fb22eSMark Adams   for setting the level options rather than the `-mg_coarse` or `-mg_fine` prefix.
47497d33e41SMatthew G. Knepley 
475d5a8f7e6SBarry Smith   You can free the information in comms after this routine is called.
476d5a8f7e6SBarry Smith 
477f1580f4eSBarry Smith   The array of MPI communicators must contain `MPI_COMM_NULL` for those ranks that at each level
478d5a8f7e6SBarry Smith   are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
479d5a8f7e6SBarry Smith   the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
480d5a8f7e6SBarry Smith   of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
481f1580f4eSBarry Smith   the first of size 2 and the second of value `MPI_COMM_NULL` since the rank 1 does not participate
482d5a8f7e6SBarry Smith   in the coarse grid solve.
483d5a8f7e6SBarry Smith 
484f1580f4eSBarry Smith   Since each coarser level may have a new `MPI_Comm` with fewer ranks than the previous, one
485d5a8f7e6SBarry Smith   must take special care in providing the restriction and interpolation operation. We recommend
486d5a8f7e6SBarry Smith   providing these as two step operations; first perform a standard restriction or interpolation on
487d5a8f7e6SBarry Smith   the full number of ranks for that level and then use an MPI call to copy the resulting vector
48805552d4bSJunchao Zhang   array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
489d5a8f7e6SBarry Smith   cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
49020f4b53cSBarry Smith   receives or `MPI_AlltoAllv()` could be used to do the reshuffling of the vector entries.
491d5a8f7e6SBarry Smith 
492feefa0e1SJacob Faibussowitsch   Fortran Notes:
49320f4b53cSBarry Smith   Use comms = `PETSC_NULL_MPI_COMM` as the equivalent of `NULL` in the C interface. Note `PETSC_NULL_MPI_COMM`
494f1580f4eSBarry Smith   is not `MPI_COMM_NULL`. It is more like `PETSC_NULL_INTEGER`, `PETSC_NULL_REAL` etc.
495d5a8f7e6SBarry Smith 
496562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetType()`, `PCMGGetLevels()`
49797d33e41SMatthew G. Knepley @*/
498d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetLevels(PC pc, PetscInt levels, MPI_Comm *comms)
499d71ae5a4SJacob Faibussowitsch {
50097d33e41SMatthew G. Knepley   PetscFunctionBegin;
50197d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5024f572ea9SToby Isaac   if (comms) PetscAssertPointer(comms, 3);
503cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetLevels_C", (PC, PetscInt, MPI_Comm *), (pc, levels, comms));
5043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50597d33e41SMatthew G. Knepley }
50697d33e41SMatthew G. Knepley 
507d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_MG(PC pc)
508d71ae5a4SJacob Faibussowitsch {
509a06653b4SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
510a06653b4SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
511a06653b4SBarry Smith   PetscInt       i, n;
512c07bf074SBarry Smith 
513c07bf074SBarry Smith   PetscFunctionBegin;
5149566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
515a06653b4SBarry Smith   if (mglevels) {
516a06653b4SBarry Smith     n = mglevels[0]->levels;
517a06653b4SBarry Smith     for (i = 0; i < n; i++) {
51848a46eb9SPierre Jolivet       if (mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPDestroy(&mglevels[i]->smoothd));
5199566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
5209566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
5219566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
522a06653b4SBarry Smith     }
5239566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
524a06653b4SBarry Smith   }
5259566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5282b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", NULL));
529bbbcb081SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", NULL));
5302b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", NULL));
5312b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", NULL));
5322b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", NULL));
5332b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", NULL));
5342b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", NULL));
5352b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", NULL));
5362b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", NULL));
5372b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", NULL));
5382b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", NULL));
5392b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", NULL));
5403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
541f3fbd535SBarry Smith }
542f3fbd535SBarry Smith 
543f3fbd535SBarry Smith /*
544f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
545f3fbd535SBarry Smith              or full cycle of multigrid.
546f3fbd535SBarry Smith 
547f3fbd535SBarry Smith   Note:
548f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
549f3fbd535SBarry Smith */
550d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG_Internal(PC pc, Vec b, Vec x, Mat B, Mat X, PetscBool transpose)
551d71ae5a4SJacob Faibussowitsch {
552f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
553f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
554391689abSStefano Zampini   PC             tpc;
555f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels, i;
55630b0564aSStefano Zampini   PetscBool      changeu, changed, matapp;
557f3fbd535SBarry Smith 
558f3fbd535SBarry Smith   PetscFunctionBegin;
55930b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5609566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
561e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
562298cc208SBarry Smith   for (i = 0; i < levels; i++) {
563e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5649566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu, &mglevels[i]->A, NULL));
5659566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
566e1d8e5deSBarry Smith     }
567e1d8e5deSBarry Smith   }
568e1d8e5deSBarry Smith 
5699566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
5709566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changed));
5719566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
5729566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc, &changeu));
573391689abSStefano Zampini   if (!changeu && !changed) {
57430b0564aSStefano Zampini     if (matapp) {
5759566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->B));
57630b0564aSStefano Zampini       mglevels[levels - 1]->B = B;
57730b0564aSStefano Zampini     } else {
5789566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels - 1]->b));
579f3fbd535SBarry Smith       mglevels[levels - 1]->b = b;
58030b0564aSStefano Zampini     }
581391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
58230b0564aSStefano Zampini     if (matapp) {
58330b0564aSStefano Zampini       if (mglevels[levels - 1]->B) {
58430b0564aSStefano Zampini         PetscInt  N1, N2;
58530b0564aSStefano Zampini         PetscBool flg;
58630b0564aSStefano Zampini 
5879566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &N1));
5889566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, NULL, &N2));
5899566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 1]->B, ((PetscObject)B)->type_name, &flg));
59048a46eb9SPierre Jolivet         if (N1 != N2 || !flg) PetscCall(MatDestroy(&mglevels[levels - 1]->B));
59130b0564aSStefano Zampini       }
59230b0564aSStefano Zampini       if (!mglevels[levels - 1]->B) {
5939566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mglevels[levels - 1]->B));
59430b0564aSStefano Zampini       } else {
5959566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mglevels[levels - 1]->B, SAME_NONZERO_PATTERN));
59630b0564aSStefano Zampini       }
59730b0564aSStefano Zampini     } else {
598391689abSStefano Zampini       if (!mglevels[levels - 1]->b) {
599391689abSStefano Zampini         Vec *vec;
600391689abSStefano Zampini 
6019566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels - 1]->smoothd, 1, &vec, 0, NULL));
602391689abSStefano Zampini         mglevels[levels - 1]->b = *vec;
6039566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
604391689abSStefano Zampini       }
6059566063dSJacob Faibussowitsch       PetscCall(VecCopy(b, mglevels[levels - 1]->b));
606391689abSStefano Zampini     }
60730b0564aSStefano Zampini   }
6089371c9d4SSatish Balay   if (matapp) {
6099371c9d4SSatish Balay     mglevels[levels - 1]->X = X;
6109371c9d4SSatish Balay   } else {
6119371c9d4SSatish Balay     mglevels[levels - 1]->x = x;
6129371c9d4SSatish Balay   }
61330b0564aSStefano Zampini 
61430b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
61530b0564aSStefano Zampini      Reset operators if sizes/type do no match */
61630b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels - 2]->X) {
61730b0564aSStefano Zampini     PetscInt  Xc, Bc;
61830b0564aSStefano Zampini     PetscBool flg;
61930b0564aSStefano Zampini 
6209566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 2]->X, NULL, &Xc));
6219566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels - 1]->B, NULL, &Bc));
6229566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels - 2]->X, ((PetscObject)mglevels[levels - 1]->X)->type_name, &flg));
62330b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6249566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels - 1]->R));
62530b0564aSStefano Zampini       for (i = 0; i < levels - 1; i++) {
6269566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6279566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6289566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
62930b0564aSStefano Zampini       }
63030b0564aSStefano Zampini     }
63130b0564aSStefano Zampini   }
632391689abSStefano Zampini 
63331567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6349566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6359566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
63648a46eb9SPierre Jolivet     for (i = 0; i < mg->cyclesperpcapply; i++) PetscCall(PCMGMCycle_Private(pc, mglevels + levels - 1, transpose, matapp, NULL));
6372fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6389566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc, mglevels, transpose, matapp));
6392fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6409566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc, mglevels, transpose, matapp));
6412fa5cd67SKarl Rupp   } else {
6429566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc, mglevels, transpose, matapp));
643f3fbd535SBarry Smith   }
6449566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
64530b0564aSStefano Zampini   if (!changeu && !changed) {
6469371c9d4SSatish Balay     if (matapp) {
6479371c9d4SSatish Balay       mglevels[levels - 1]->B = NULL;
6489371c9d4SSatish Balay     } else {
6499371c9d4SSatish Balay       mglevels[levels - 1]->b = NULL;
6509371c9d4SSatish Balay     }
65130b0564aSStefano Zampini   }
6523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
653f3fbd535SBarry Smith }
654f3fbd535SBarry Smith 
655d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_MG(PC pc, Vec b, Vec x)
656d71ae5a4SJacob Faibussowitsch {
657fcb023d4SJed Brown   PetscFunctionBegin;
6589566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_FALSE));
6593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
660fcb023d4SJed Brown }
661fcb023d4SJed Brown 
662d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_MG(PC pc, Vec b, Vec x)
663d71ae5a4SJacob Faibussowitsch {
664fcb023d4SJed Brown   PetscFunctionBegin;
6659566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, b, x, NULL, NULL, PETSC_TRUE));
6663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66730b0564aSStefano Zampini }
66830b0564aSStefano Zampini 
669d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_MG(PC pc, Mat b, Mat x)
670d71ae5a4SJacob Faibussowitsch {
67130b0564aSStefano Zampini   PetscFunctionBegin;
6729566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_FALSE));
6733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
674fcb023d4SJed Brown }
675f3fbd535SBarry Smith 
6764dbf25a8SPierre Jolivet static PetscErrorCode PCMatApplyTranspose_MG(PC pc, Mat b, Mat x)
6774dbf25a8SPierre Jolivet {
6784dbf25a8SPierre Jolivet   PetscFunctionBegin;
6794dbf25a8SPierre Jolivet   PetscCall(PCApply_MG_Internal(pc, NULL, NULL, b, x, PETSC_TRUE));
6804dbf25a8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
6814dbf25a8SPierre Jolivet }
6824dbf25a8SPierre Jolivet 
683ce78bad3SBarry Smith PetscErrorCode PCSetFromOptions_MG(PC pc, PetscOptionItems PetscOptionsObject)
684d71ae5a4SJacob Faibussowitsch {
685710315b6SLawrence Mitchell   PetscInt            levels, cycles;
686f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
687f3fbd535SBarry Smith   PC_MG              *mg = (PC_MG *)pc->data;
6883d3eaba7SBarry Smith   PC_MG_Levels      **mglevels;
689f3fbd535SBarry Smith   PCMGType            mgtype;
690f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6912134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6922b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
693f3fbd535SBarry Smith 
694f3fbd535SBarry Smith   PetscFunctionBegin;
6951d743356SStefano Zampini   levels = PetscMax(mg->nlevels, 1);
696d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Multigrid options");
6979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", levels, &levels, &flg));
6981a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6999566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
700eb3f98d2SBarry Smith     levels++;
7013aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
702eb3f98d2SBarry Smith   }
7039566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, levels, NULL));
7043aeaf226SBarry Smith   mglevels = mg->levels;
7053aeaf226SBarry Smith 
706f3fbd535SBarry Smith   mgctype = (PCMGCycleType)mglevels[0]->cycles;
7079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type", "V cycle or for W-cycle", "PCMGSetCycleType", PCMGCycleTypes, (PetscEnum)mgctype, (PetscEnum *)&mgctype, &flg));
7081baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc, mgctype));
7092b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
7102b3cbbdaSStefano 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));
7112b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc, coarseSpaceType));
7129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n", "Size of the coarse space for adaptive interpolation", "PCMGSetCoarseSpace", mg->Nc, &mg->Nc, &flg));
7139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor", "Monitor the multilevel eigensolver", "PCMGSetAdaptInterpolation", PETSC_FALSE, &mg->mespMonitor, &flg));
71441b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
7159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr", "Monitor coarse space quality using Compatible Relaxation (CR)", "PCMGSetAdaptCR", PETSC_FALSE, &flg2, &flg));
7169566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
717f56b1265SBarry Smith   flg = PETSC_FALSE;
7189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup", "Create separate smoothup KSP and append the prefix _up", "PCMGSetDistinctSmoothUp", PETSC_FALSE, &flg, NULL));
7191baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
7205544a5bcSStefano Zampini   PetscCall(PetscOptionsEnum("-pc_mg_galerkin", "Use Galerkin process to compute coarser operators", "PCMGSetGalerkin", PCMGGalerkinTypes, (PetscEnum)mg->galerkin, (PetscEnum *)&gtype, &flg));
7215544a5bcSStefano Zampini   if (flg) PetscCall(PCMGSetGalerkin(pc, gtype));
72231567311SBarry Smith   mgtype = mg->am;
7239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type", "Multigrid type", "PCMGSetType", PCMGTypes, (PetscEnum)mgtype, (PetscEnum *)&mgtype, &flg));
7241baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc, mgtype));
72531567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
7269566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles", "Number of cycles for each preconditioner step", "PCMGMultiplicativeSetCycles", mg->cyclesperpcapply, &cycles, &flg));
7271baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc, cycles));
728f3fbd535SBarry Smith   }
729f3fbd535SBarry Smith   flg = PETSC_FALSE;
7309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log", "Log times for each multigrid level", "None", flg, &flg, NULL));
731f3fbd535SBarry Smith   if (flg) {
732f3fbd535SBarry Smith     PetscInt i;
733f3fbd535SBarry Smith     char     eventname[128];
7341a97d7b6SStefano Zampini 
735f3fbd535SBarry Smith     levels = mglevels[0]->levels;
736f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
737835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSetup Level %" PetscInt_FMT, i));
7389566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsetup));
739835f2295SStefano Zampini       PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGSmooth Level %" PetscInt_FMT, i));
7409566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventsmoothsolve));
741f3fbd535SBarry Smith       if (i) {
742835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGResid Level %" PetscInt_FMT, i));
7439566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventresidual));
744835f2295SStefano Zampini         PetscCall(PetscSNPrintf(eventname, PETSC_STATIC_ARRAY_LENGTH(eventname), "MGInterp Level %" PetscInt_FMT, i));
7459566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname, ((PetscObject)pc)->classid, &mglevels[i]->eventinterprestrict));
746f3fbd535SBarry Smith       }
747f3fbd535SBarry Smith     }
748eec35531SMatthew G Knepley 
7492611ad71SToby Isaac     if (PetscDefined(USE_LOG)) {
7502611ad71SToby Isaac       const char sname[] = "MG Apply";
751eec35531SMatthew G Knepley 
7522611ad71SToby Isaac       PetscCall(PetscLogStageGetId(sname, &mg->stageApply));
7532611ad71SToby Isaac       if (mg->stageApply < 0) PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
754eec35531SMatthew G Knepley     }
755f3fbd535SBarry Smith   }
756d0609cedSBarry Smith   PetscOptionsHeadEnd();
757f3b08a26SMatthew G. Knepley   /* Check option consistency */
7589566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7599566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
76008401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE), PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
7613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
762f3fbd535SBarry Smith }
763f3fbd535SBarry Smith 
7640a545947SLisandro Dalcin const char *const PCMGTypes[]            = {"MULTIPLICATIVE", "ADDITIVE", "FULL", "KASKADE", "PCMGType", "PC_MG", NULL};
7650a545947SLisandro Dalcin const char *const PCMGCycleTypes[]       = {"invalid", "v", "w", "PCMGCycleType", "PC_MG_CYCLE", NULL};
7660a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[]    = {"both", "pmat", "mat", "none", "external", "PCMGGalerkinType", "PC_MG_GALERKIN", NULL};
7672b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none", "polynomial", "harmonic", "eigenvector", "generalized_eigenvector", "gdsw", "PCMGCoarseSpaceType", "PCMG_ADAPT_NONE", NULL};
768f3fbd535SBarry Smith 
7699804daf3SBarry Smith #include <petscdraw.h>
770d71ae5a4SJacob Faibussowitsch PetscErrorCode PCView_MG(PC pc, PetscViewer viewer)
771d71ae5a4SJacob Faibussowitsch {
772f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
773f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
774e3deeeafSJed Brown   PetscInt       levels   = mglevels ? mglevels[0]->levels : 0, i;
7759f196a02SMartin Diehl   PetscBool      isascii, isbinary, isdraw;
776f3fbd535SBarry Smith 
777f3fbd535SBarry Smith   PetscFunctionBegin;
7789f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
7799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
7809566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
7819f196a02SMartin Diehl   if (isascii) {
782e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
783*bcefaa27SBarry Smith 
784*bcefaa27SBarry Smith     if (levels == 1) PetscCall(PetscViewerASCIIPrintf(viewer, "  WARNING: Multigrid is being run with only a single level!\n"));
78563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am], levels, cyclename));
78648a46eb9SPierre Jolivet     if (mg->am == PC_MG_MULTIPLICATIVE) PetscCall(PetscViewerASCIIPrintf(viewer, "    Cycles per PCApply=%" PetscInt_FMT "\n", mg->cyclesperpcapply));
7872134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7889566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices\n"));
7892134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7909566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for pmat\n"));
7912134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using Galerkin computed coarse grid matrices for mat\n"));
7932134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Using externally compute Galerkin coarse grid matrices\n"));
7954f66f45eSBarry Smith     } else {
7969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "    Not using Galerkin computed coarse grid matrices\n"));
797f3fbd535SBarry Smith     }
7981baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc, viewer));
799f3fbd535SBarry Smith     for (i = 0; i < levels; i++) {
80063a3b9bcSJacob Faibussowitsch       if (i) {
80163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
802f3fbd535SBarry Smith       } else {
80363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n", i));
804f3fbd535SBarry Smith       }
8059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
8069566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8079566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
808f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
8099566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) same as down solver (pre-smoother)\n"));
810f3fbd535SBarry Smith       } else if (i) {
81163a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n", i));
8129566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8139566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8149566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
815f3fbd535SBarry Smith       }
81641b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
81763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "CR solver on level %" PetscInt_FMT " -------------------------------\n", i));
8189566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8199566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr, viewer));
8209566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
82141b6fd38SMatthew G. Knepley       }
822f3fbd535SBarry Smith     }
8235b0b0462SBarry Smith   } else if (isbinary) {
8245b0b0462SBarry Smith     for (i = levels - 1; i >= 0; i--) {
8259566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd, viewer));
82648a46eb9SPierre Jolivet       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8275b0b0462SBarry Smith     }
828219b1045SBarry Smith   } else if (isdraw) {
829219b1045SBarry Smith     PetscDraw draw;
830b4375e8dSPeter Brune     PetscReal x, w, y, bottom, th;
8319566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
8329566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
8339566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw, NULL, &th));
834219b1045SBarry Smith     bottom = y - th;
835219b1045SBarry Smith     for (i = levels - 1; i >= 0; i--) {
836b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8379566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
8389566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8399566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
840b4375e8dSPeter Brune       } else {
841b4375e8dSPeter Brune         w = 0.5 * PetscMin(1.0 - x, x);
8429566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x + w, bottom));
8439566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd, viewer));
8449566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8459566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw, x - w, bottom));
8469566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu, viewer));
8479566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
848b4375e8dSPeter Brune       }
8499566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw, NULL, &bottom, NULL, NULL));
8501cd381d6SBarry Smith       bottom -= th;
851219b1045SBarry Smith     }
8525b0b0462SBarry Smith   }
8533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
854f3fbd535SBarry Smith }
855f3fbd535SBarry Smith 
856af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
857cab2e9ccSBarry Smith 
858f3fbd535SBarry Smith /*
859f3fbd535SBarry Smith     Calls setup for the KSP on each level
860f3fbd535SBarry Smith */
861d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSetUp_MG(PC pc)
862d71ae5a4SJacob Faibussowitsch {
863f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
864f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8651a97d7b6SStefano Zampini   PetscInt       i, n;
86698e04984SBarry Smith   PC             cpc;
8673db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE, opsset, use_amat, missinginterpolate = PETSC_FALSE;
868f3fbd535SBarry Smith   Mat            dA, dB;
869f3fbd535SBarry Smith   Vec            tvec;
870218a07d4SBarry Smith   DM            *dms;
8710a545947SLisandro Dalcin   PetscViewer    viewer = NULL;
87241b6fd38SMatthew G. Knepley   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8732b3cbbdaSStefano Zampini   PetscBool      adaptInterpolation = mg->adaptInterpolation;
874f3fbd535SBarry Smith 
875f3fbd535SBarry Smith   PetscFunctionBegin;
87628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels with PCMGSetLevels() before setting up");
8771a97d7b6SStefano Zampini   n = mglevels[0]->levels;
87801bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8793aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8803aeaf226SBarry Smith     PetscInt levels;
881efba3485SBarry Smith 
8829566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm, &levels));
8833aeaf226SBarry Smith     levels++;
8843aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8859566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc, levels, NULL));
8863aeaf226SBarry Smith       n = levels;
8879566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8883aeaf226SBarry Smith       mglevels = mg->levels;
8893aeaf226SBarry Smith     }
8903aeaf226SBarry Smith   }
8913aeaf226SBarry Smith 
892f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
893f3fbd535SBarry Smith   /* so use those from global PC */
894f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8959566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n - 1]->smoothd, NULL, &opsset));
89698e04984SBarry Smith   if (opsset) {
89798e04984SBarry Smith     Mat mmat;
8989566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, NULL, &mmat));
89998e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
90098e04984SBarry Smith   }
901bbbcb081SMark Adams   /* fine grid smoother inherits the reuse-pc flag */
902bbbcb081SMark Adams   PetscCall(KSPGetPC(mglevels[n - 1]->smoothd, &cpc));
903bbbcb081SMark Adams   cpc->reusepreconditioner = pc->reusepreconditioner;
904bbbcb081SMark Adams   PetscCall(KSPGetPC(mglevels[n - 1]->smoothu, &cpc));
905bbbcb081SMark Adams   cpc->reusepreconditioner = pc->reusepreconditioner;
9064a5f07a5SMark F. Adams 
90741b6fd38SMatthew G. Knepley   /* Create CR solvers */
9089566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
90941b6fd38SMatthew G. Knepley   if (doCR) {
91041b6fd38SMatthew G. Knepley     const char *prefix;
91141b6fd38SMatthew G. Knepley 
9129566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
91341b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
91441b6fd38SMatthew G. Knepley       PC   ipc, cr;
91541b6fd38SMatthew G. Knepley       char crprefix[128];
91641b6fd38SMatthew G. Knepley 
9179566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &mglevels[i]->cr));
9183821be0aSBarry Smith       PetscCall(KSPSetNestLevel(mglevels[i]->cr, pc->kspnestlevel));
9199566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
9209566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->cr, (PetscObject)pc, n - i));
9219566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
9229566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
9239566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9249566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9259566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9269566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
92741b6fd38SMatthew G. Knepley 
9289566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
9299566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9309566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9319566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
9329566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
9339566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
93441b6fd38SMatthew G. Knepley 
935fb842aefSJose E. Roman       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, mg->default_smoothd));
9369566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
937835f2295SStefano Zampini       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%" PetscInt_FMT "_cr_", i));
9389566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
93941b6fd38SMatthew G. Knepley     }
94041b6fd38SMatthew G. Knepley   }
94141b6fd38SMatthew G. Knepley 
9424a5f07a5SMark F. Adams   if (!opsset) {
9439566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc, &use_amat));
9444a5f07a5SMark F. Adams     if (use_amat) {
9459566063dSJacob 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"));
9469566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->mat, pc->pmat));
94769858f1bSStefano Zampini     } else {
9489566063dSJacob 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"));
9499566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n - 1]->smoothd, pc->pmat, pc->pmat));
9504a5f07a5SMark F. Adams     }
9514a5f07a5SMark F. Adams   }
952f3fbd535SBarry Smith 
9539c7ffb39SBarry Smith   for (i = n - 1; i > 0; i--) {
9549c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9559c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9562b3cbbdaSStefano Zampini       break;
9579c7ffb39SBarry Smith     }
9589c7ffb39SBarry Smith   }
9592134b1e4SBarry Smith 
9609566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n - 1]->smoothd, &dA, &dB));
9612134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9623a7d0413SPierre Jolivet   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) needRestricts = PETSC_TRUE; /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9632134b1e4SBarry Smith 
9642b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9652b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9662b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n - 1]->smoothd, pc->dm));
9672b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothd, PETSC_FALSE));
9682b3cbbdaSStefano Zampini     if (mglevels[n - 1]->smoothd != mglevels[n - 1]->smoothu) {
9692b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->smoothu, pc->dm));
9702b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->smoothu, PETSC_FALSE));
9712b3cbbdaSStefano Zampini     }
9722b3cbbdaSStefano Zampini     if (mglevels[n - 1]->cr) {
9732b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n - 1]->cr, pc->dm));
9742b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n - 1]->cr, PETSC_FALSE));
9752b3cbbdaSStefano Zampini     }
9762b3cbbdaSStefano Zampini   }
9772b3cbbdaSStefano Zampini 
9789c7ffb39SBarry Smith   /*
9799c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9802b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9819c7ffb39SBarry Smith   */
98232fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
98332fe681dSStefano Zampini     /* first see if we can compute a coarse space */
98432fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
98532fe681dSStefano Zampini       for (i = n - 2; i > -1; i--) {
98632fe681dSStefano Zampini         if (!mglevels[i + 1]->restrct && !mglevels[i + 1]->interpolate) {
98732fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i + 1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i + 1]->coarseSpace));
98832fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->coarseSpace));
98932fe681dSStefano Zampini         }
99032fe681dSStefano Zampini       }
99132fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9922e499ae9SBarry Smith       Mat p;
99373250ac0SBarry Smith       Vec rscale;
99464da7896SBarry Smith 
99564da7896SBarry Smith       PetscCheck(n == 1 || pc->dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PC lacks a DM so cannot automatically construct a multigrid hierarchy. Number of levels requested %" PetscInt_FMT, n);
9969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n, &dms));
997218a07d4SBarry Smith       dms[n - 1] = pc->dm;
998ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9999566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMCoarsen(dms[i + 1], MPI_COMM_NULL, &dms[i]));
1000218a07d4SBarry Smith       for (i = n - 2; i > -1; i--) {
1001942e3340SBarry Smith         DMKSP     kdm;
1002eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
1003218e2965SBarry Smith 
10049566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd, dms[i]));
10059566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd, PETSC_FALSE));
1006c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
10079566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu, dms[i]));
10089566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu, PETSC_FALSE));
1009c27ee7a3SPatrick Farrell         }
101041b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
10119566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr, dms[i]));
10129566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr, PETSC_FALSE));
101341b6fd38SMatthew G. Knepley         }
10149566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i], &kdm));
1015d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
1016d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
10170298fd71SBarry Smith         kdm->ops->computerhs = NULL;
10180298fd71SBarry Smith         kdm->rhsctx          = NULL;
101924c3aa18SBarry Smith         if (!mglevels[i + 1]->interpolate) {
10209566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i], dms[i + 1], &p, &rscale));
10219566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc, i + 1, p));
10229566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc, i + 1, rscale));
10239566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
10249566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1025218a07d4SBarry Smith         }
10269566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i], &dmhasrestrict));
10273ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i + 1]->restrct) {
10289566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i], dms[i + 1], &p));
10299566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc, i + 1, p));
10309566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
10313ad4599aSBarry Smith         }
10329566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i], &dmhasinject));
1033eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i + 1]->inject) {
10349566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i], dms[i + 1], &p));
10359566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc, i + 1, p));
10369566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1037eab52d2bSLawrence Mitchell         }
103824c3aa18SBarry Smith       }
10392d2b81a6SBarry Smith 
10409566063dSJacob Faibussowitsch       for (i = n - 2; i > -1; i--) PetscCall(DMDestroy(&dms[i]));
10419566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1042ce4cda84SJed Brown     }
104332fe681dSStefano Zampini   }
1044cab2e9ccSBarry Smith 
10452134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10462134b1e4SBarry Smith     Mat       A, B;
10472134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE, doB = PETSC_FALSE;
10482134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10492134b1e4SBarry Smith 
10502b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10512b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10522134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1053f3fbd535SBarry Smith     for (i = n - 2; i > -1; i--) {
10547827d75bSBarry 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");
105548a46eb9SPierre Jolivet       if (!mglevels[i + 1]->interpolate) PetscCall(PCMGSetInterpolation(pc, i + 1, mglevels[i + 1]->restrct));
105648a46eb9SPierre Jolivet       if (!mglevels[i + 1]->restrct) PetscCall(PCMGSetRestriction(pc, i + 1, mglevels[i + 1]->interpolate));
105748a46eb9SPierre Jolivet       if (reuse == MAT_REUSE_MATRIX) PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, &B));
105848a46eb9SPierre Jolivet       if (doA) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dA, mglevels[i + 1]->interpolate, reuse, 1.0, &A));
105948a46eb9SPierre Jolivet       if (doB) PetscCall(MatGalerkin(mglevels[i + 1]->restrct, dB, mglevels[i + 1]->interpolate, reuse, 1.0, &B));
10602134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10612134b1e4SBarry Smith       if (!doA && dAeqdB) {
10629566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10632134b1e4SBarry Smith         A = B;
10642134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10659566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &A, NULL));
10669566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1067b9367914SBarry Smith       }
10682134b1e4SBarry Smith       if (!doB && dAeqdB) {
10699566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10702134b1e4SBarry Smith         B = A;
10712134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10729566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &B));
10739566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10747d537d92SJed Brown       }
10752134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10769566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd, A, B));
10779566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10789566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10792134b1e4SBarry Smith       }
10802134b1e4SBarry Smith       dA = A;
1081f3fbd535SBarry Smith       dB = B;
1082f3fbd535SBarry Smith     }
1083f3fbd535SBarry Smith   }
1084f3b08a26SMatthew G. Knepley 
1085f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10862b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1087f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
108848a46eb9SPierre Jolivet       if (!mglevels[i]->coarseSpace) PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i - 1]->coarseSpace, &mglevels[i]->coarseSpace));
10892b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i - 1]->smoothu, mglevels[i]->smoothu, mglevels[i - 1]->coarseSpace, mglevels[i]->coarseSpace));
1090f3b08a26SMatthew G. Knepley     }
109148a46eb9SPierre Jolivet     for (i = n - 2; i > -1; --i) PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1092f3b08a26SMatthew G. Knepley   }
1093f3b08a26SMatthew G. Knepley 
10942134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1095caa4e7f2SJed Brown     for (i = n - 2; i >= 0; i--) {
1096ccceb50cSJed Brown       DM  dmfine, dmcoarse;
1097caa4e7f2SJed Brown       Mat Restrict, Inject;
1098caa4e7f2SJed Brown       Vec rscale;
1099218e2965SBarry Smith 
11009566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i + 1]->smoothd, &dmfine));
11019566063dSJacob Faibussowitsch       PetscCall(KSPGetDM(mglevels[i]->smoothd, &dmcoarse));
11029566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i + 1, &Restrict));
11039566063dSJacob Faibussowitsch       PetscCall(PCMGGetRScale(pc, i + 1, &rscale));
11049566063dSJacob Faibussowitsch       PetscCall(PCMGGetInjection(pc, i + 1, &Inject));
11059566063dSJacob Faibussowitsch       PetscCall(DMRestrict(dmfine, Restrict, rscale, Inject, dmcoarse));
1106caa4e7f2SJed Brown     }
1107caa4e7f2SJed Brown   }
1108f3fbd535SBarry Smith 
1109f3fbd535SBarry Smith   if (!pc->setupcalled) {
111048a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1111f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
111248a46eb9SPierre Jolivet       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
111348a46eb9SPierre Jolivet       if (mglevels[i]->cr) PetscCall(KSPSetFromOptions(mglevels[i]->cr));
1114f3fbd535SBarry Smith     }
111515229ffcSPierre Jolivet     /* insure that if either interpolation or restriction is set the other one is set */
1116f3fbd535SBarry Smith     for (i = 1; i < n; i++) {
11179566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc, i, NULL));
11189566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc, i, NULL));
1119f3fbd535SBarry Smith     }
1120f3fbd535SBarry Smith     for (i = 0; i < n - 1; i++) {
1121f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1122f3fbd535SBarry Smith         Vec *vec;
11239566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd, 1, &vec, 0, NULL));
11249566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc, i, *vec));
11259566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
11269566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1127f3fbd535SBarry Smith       }
1128f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
11299566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11309566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc, i, tvec));
11319566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1132f3fbd535SBarry Smith       }
1133f3fbd535SBarry Smith       if (!mglevels[i]->x) {
11349566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &tvec));
11359566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc, i, tvec));
11369566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1137f3fbd535SBarry Smith       }
113841b6fd38SMatthew G. Knepley       if (doCR) {
11399566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crx));
11409566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b, &mglevels[i]->crb));
11419566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
114241b6fd38SMatthew G. Knepley       }
1143f3fbd535SBarry Smith     }
1144f3fbd535SBarry Smith     if (n != 1 && !mglevels[n - 1]->r) {
1145f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1146f3fbd535SBarry Smith       Vec *vec;
1147218e2965SBarry Smith 
11489566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n - 1]->smoothd, 1, &vec, 0, NULL));
11499566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc, n - 1, *vec));
11509566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11519566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1152f3fbd535SBarry Smith     }
115341b6fd38SMatthew G. Knepley     if (doCR) {
11549566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crx));
11559566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n - 1]->r, &mglevels[n - 1]->crb));
11569566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n - 1]->crb));
115741b6fd38SMatthew G. Knepley     }
1158f3fbd535SBarry Smith   }
1159f3fbd535SBarry Smith 
116098e04984SBarry Smith   if (pc->dm) {
116198e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
116298e04984SBarry Smith     for (i = 0; i < n - 1; i++) {
116398e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
116498e04984SBarry Smith     }
116598e04984SBarry Smith   }
116608549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
116708549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
116808549ed4SJed Brown   if (mglevels[n - 1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n - 1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1169f3fbd535SBarry Smith 
1170f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
11712a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1172f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11739566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd, PETSC_TRUE));
1174f3fbd535SBarry Smith     }
11759566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
11769566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
11779566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1178d4645a75SStefano Zampini     if (mglevels[i]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
11799566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1180d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1181d42688cbSBarry Smith       Mat mat;
1182218e2965SBarry Smith 
11839566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11849566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc, i, PCMGResidualDefault, mat));
1185d42688cbSBarry Smith     }
1186fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1187fcb023d4SJed Brown       Mat mat;
1188218e2965SBarry Smith 
11899566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd, &mat, NULL));
11909566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc, i, PCMGResidualTransposeDefault, mat));
1191fcb023d4SJed Brown     }
1192f3fbd535SBarry Smith   }
1193f3fbd535SBarry Smith   for (i = 1; i < n; i++) {
1194f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1195f3fbd535SBarry Smith       Mat downmat, downpmat;
1196f3fbd535SBarry Smith 
1197f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
11989566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu, &opsset, NULL));
1199f3fbd535SBarry Smith       if (!opsset) {
12009566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
12019566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu, downmat, downpmat));
1202f3fbd535SBarry Smith       }
1203f3fbd535SBarry Smith 
12049566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu, PETSC_TRUE));
12059566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
12069566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1207d4645a75SStefano Zampini       if (mglevels[i]->smoothu->reason) pc->failedreason = PC_SUBPC_ERROR;
12089566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
1209f3fbd535SBarry Smith     }
121041b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
121141b6fd38SMatthew G. Knepley       Mat downmat, downpmat;
121241b6fd38SMatthew G. Knepley 
121341b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
12149566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr, &opsset, NULL));
121541b6fd38SMatthew G. Knepley       if (!opsset) {
12169566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd, &downmat, &downpmat));
12179566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr, downmat, downpmat));
121841b6fd38SMatthew G. Knepley       }
121941b6fd38SMatthew G. Knepley 
12209566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
12219566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
12229566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
1223d4645a75SStefano Zampini       if (mglevels[i]->cr->reason) pc->failedreason = PC_SUBPC_ERROR;
12249566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup, 0, 0, 0, 0));
122541b6fd38SMatthew G. Knepley     }
1226f3fbd535SBarry Smith   }
1227f3fbd535SBarry Smith 
12289566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
12299566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1230d4645a75SStefano Zampini   if (mglevels[0]->smoothd->reason) pc->failedreason = PC_SUBPC_ERROR;
12319566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup, 0, 0, 0, 0));
1232f3fbd535SBarry Smith 
1233f3fbd535SBarry Smith   /*
1234f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1235e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1236f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1237f3fbd535SBarry Smith 
1238f3fbd535SBarry Smith    Only support one or the other at the same time.
1239f3fbd535SBarry Smith   */
1240f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_matlab", &dump, NULL));
1242ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1243f3fbd535SBarry Smith   dump = PETSC_FALSE;
1244f3fbd535SBarry Smith #endif
12459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_mg_dump_binary", &dump, NULL));
1246ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1247f3fbd535SBarry Smith 
1248f3fbd535SBarry Smith   if (viewer) {
124948a46eb9SPierre Jolivet     for (i = 1; i < n; i++) PetscCall(MatView(mglevels[i]->restrct, viewer));
1250f3fbd535SBarry Smith     for (i = 0; i < n; i++) {
12519566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd, &pc));
12529566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat, viewer));
1253f3fbd535SBarry Smith     }
1254f3fbd535SBarry Smith   }
12553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1256f3fbd535SBarry Smith }
1257f3fbd535SBarry Smith 
1258d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
1259d71ae5a4SJacob Faibussowitsch {
126097d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
126197d33e41SMatthew G. Knepley 
126297d33e41SMatthew G. Knepley   PetscFunctionBegin;
126397d33e41SMatthew G. Knepley   *levels = mg->nlevels;
12643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
126597d33e41SMatthew G. Knepley }
126697d33e41SMatthew G. Knepley 
12674b9ad928SBarry Smith /*@
1268f1580f4eSBarry Smith   PCMGGetLevels - Gets the number of levels to use with `PCMG`.
12694b9ad928SBarry Smith 
12704b9ad928SBarry Smith   Not Collective
12714b9ad928SBarry Smith 
12724b9ad928SBarry Smith   Input Parameter:
12734b9ad928SBarry Smith . pc - the preconditioner context
12744b9ad928SBarry Smith 
1275feefa0e1SJacob Faibussowitsch   Output Parameter:
12764b9ad928SBarry Smith . levels - the number of levels
12774b9ad928SBarry Smith 
12784b9ad928SBarry Smith   Level: advanced
12794b9ad928SBarry Smith 
1280562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetLevels()`
12814b9ad928SBarry Smith @*/
1282d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetLevels(PC pc, PetscInt *levels)
1283d71ae5a4SJacob Faibussowitsch {
12844b9ad928SBarry Smith   PetscFunctionBegin;
12850700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
12864f572ea9SToby Isaac   PetscAssertPointer(levels, 2);
128797d33e41SMatthew G. Knepley   *levels = 0;
1288cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGGetLevels_C", (PC, PetscInt *), (pc, levels));
12893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12904b9ad928SBarry Smith }
12914b9ad928SBarry Smith 
12924b9ad928SBarry Smith /*@
1293f1580f4eSBarry Smith   PCMGGetGridComplexity - compute operator and grid complexity of the `PCMG` hierarchy
1294e7d4b4cbSMark Adams 
1295e7d4b4cbSMark Adams   Input Parameter:
1296e7d4b4cbSMark Adams . pc - the preconditioner context
1297e7d4b4cbSMark Adams 
129890db8557SMark Adams   Output Parameters:
129990db8557SMark Adams + gc - grid complexity = sum_i(n_i) / n_0
130090db8557SMark Adams - oc - operator complexity = sum_i(nnz_i) / nnz_0
1301e7d4b4cbSMark Adams 
1302e7d4b4cbSMark Adams   Level: advanced
1303e7d4b4cbSMark Adams 
1304f1580f4eSBarry Smith   Note:
1305f1580f4eSBarry Smith   This is often call the operator complexity in multigrid literature
1306f1580f4eSBarry Smith 
1307562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`
1308e7d4b4cbSMark Adams @*/
1309d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1310d71ae5a4SJacob Faibussowitsch {
1311e7d4b4cbSMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1312e7d4b4cbSMark Adams   PC_MG_Levels **mglevels = mg->levels;
1313e7d4b4cbSMark Adams   PetscInt       lev, N;
1314e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1315e7d4b4cbSMark Adams   MatInfo        info;
1316e7d4b4cbSMark Adams 
1317e7d4b4cbSMark Adams   PetscFunctionBegin;
131890db8557SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
13194f572ea9SToby Isaac   if (gc) PetscAssertPointer(gc, 2);
13204f572ea9SToby Isaac   if (oc) PetscAssertPointer(oc, 3);
1321e7d4b4cbSMark Adams   if (!pc->setupcalled) {
132290db8557SMark Adams     if (gc) *gc = 0;
132390db8557SMark Adams     if (oc) *oc = 0;
13243ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1325e7d4b4cbSMark Adams   }
1326e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MG has no levels");
1327e7d4b4cbSMark Adams   for (lev = 0; lev < mg->nlevels; lev++) {
1328e7d4b4cbSMark Adams     Mat dB;
13299566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd, NULL, &dB));
13309566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB, MAT_GLOBAL_SUM, &info)); /* global reduction */
13319566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB, &N, NULL));
1332e7d4b4cbSMark Adams     sgc += N;
1333e7d4b4cbSMark Adams     soc += info.nz_used;
13349371c9d4SSatish Balay     if (lev == mg->nlevels - 1) {
13359371c9d4SSatish Balay       nnz0 = info.nz_used;
13369371c9d4SSatish Balay       n0   = N;
13379371c9d4SSatish Balay     }
1338e7d4b4cbSMark Adams   }
13390fdf79fbSJacob Faibussowitsch   PetscCheck(n0 > 0 && gc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number for grid points on finest level is not available");
13400fdf79fbSJacob Faibussowitsch   *gc = (PetscReal)(sgc / n0);
134190db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc / nnz0);
13423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1343e7d4b4cbSMark Adams }
1344e7d4b4cbSMark Adams 
1345e7d4b4cbSMark Adams /*@
134604c3f3b8SBarry Smith   PCMGSetType - Determines the form of multigrid to use, either
13474b9ad928SBarry Smith   multiplicative, additive, full, or the Kaskade algorithm.
13484b9ad928SBarry Smith 
1349c3339decSBarry Smith   Logically Collective
13504b9ad928SBarry Smith 
13514b9ad928SBarry Smith   Input Parameters:
13524b9ad928SBarry Smith + pc   - the preconditioner context
1353f1580f4eSBarry Smith - form - multigrid form, one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`
13544b9ad928SBarry Smith 
13554b9ad928SBarry Smith   Options Database Key:
135620f4b53cSBarry Smith . -pc_mg_type <form> - Sets <form>, one of multiplicative, additive, full, kaskade
13574b9ad928SBarry Smith 
13584b9ad928SBarry Smith   Level: advanced
13594b9ad928SBarry Smith 
1360562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGGetType()`, `PCMGCycleType`
13614b9ad928SBarry Smith @*/
1362d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetType(PC pc, PCMGType form)
1363d71ae5a4SJacob Faibussowitsch {
1364f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
13654b9ad928SBarry Smith 
13664b9ad928SBarry Smith   PetscFunctionBegin;
13670700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1368c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, form, 2);
136931567311SBarry Smith   mg->am = form;
13709dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1371c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
13723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1373c60c7ad4SBarry Smith }
1374c60c7ad4SBarry Smith 
1375c60c7ad4SBarry Smith /*@
1376f1580f4eSBarry Smith   PCMGGetType - Finds the form of multigrid the `PCMG` is using  multiplicative, additive, full, or the Kaskade algorithm.
1377c60c7ad4SBarry Smith 
1378c3339decSBarry Smith   Logically Collective
1379c60c7ad4SBarry Smith 
1380c60c7ad4SBarry Smith   Input Parameter:
1381c60c7ad4SBarry Smith . pc - the preconditioner context
1382c60c7ad4SBarry Smith 
1383c60c7ad4SBarry Smith   Output Parameter:
1384f1580f4eSBarry Smith . type - one of `PC_MG_MULTIPLICATIVE`, `PC_MG_ADDITIVE`, `PC_MG_FULL`, `PC_MG_KASKADE`, `PCMGCycleType`
1385c60c7ad4SBarry Smith 
1386c60c7ad4SBarry Smith   Level: advanced
1387c60c7ad4SBarry Smith 
1388562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGType`, `PCMG`, `PCMGGetLevels()`, `PCMGSetLevels()`, `PCMGSetType()`
1389c60c7ad4SBarry Smith @*/
1390d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetType(PC pc, PCMGType *type)
1391d71ae5a4SJacob Faibussowitsch {
1392c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1393c60c7ad4SBarry Smith 
1394c60c7ad4SBarry Smith   PetscFunctionBegin;
1395c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1396c60c7ad4SBarry Smith   *type = mg->am;
13973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13984b9ad928SBarry Smith }
13994b9ad928SBarry Smith 
14004b9ad928SBarry Smith /*@
1401f1580f4eSBarry Smith   PCMGSetCycleType - Sets the type cycles to use.  Use `PCMGSetCycleTypeOnLevel()` for more
14024b9ad928SBarry Smith   complicated cycling.
14034b9ad928SBarry Smith 
1404c3339decSBarry Smith   Logically Collective
14054b9ad928SBarry Smith 
14064b9ad928SBarry Smith   Input Parameters:
1407c2be2410SBarry Smith + pc - the multigrid context
1408f1580f4eSBarry Smith - n  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
14094b9ad928SBarry Smith 
14104b9ad928SBarry Smith   Options Database Key:
1411c1cbb1deSBarry Smith . -pc_mg_cycle_type <v,w> - provide the cycle desired
14124b9ad928SBarry Smith 
14134b9ad928SBarry Smith   Level: advanced
14144b9ad928SBarry Smith 
1415562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetCycleTypeOnLevel()`, `PCMGType`, `PCMGCycleType`
14164b9ad928SBarry Smith @*/
1417d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetCycleType(PC pc, PCMGCycleType n)
1418d71ae5a4SJacob Faibussowitsch {
1419f3fbd535SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1420f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
142179416396SBarry Smith   PetscInt       i, levels;
14224b9ad928SBarry Smith 
14234b9ad928SBarry Smith   PetscFunctionBegin;
14240700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
142569fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc, n, 2);
142628b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1427f3fbd535SBarry Smith   levels = mglevels[0]->levels;
14282fa5cd67SKarl Rupp   for (i = 0; i < levels; i++) mglevels[i]->cycles = n;
14293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14304b9ad928SBarry Smith }
14314b9ad928SBarry Smith 
14328cc2d5dfSBarry Smith /*@
14338cc2d5dfSBarry Smith   PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
1434f1580f4eSBarry Smith   of multigrid when `PCMGType` is `PC_MG_MULTIPLICATIVE`
14358cc2d5dfSBarry Smith 
1436c3339decSBarry Smith   Logically Collective
14378cc2d5dfSBarry Smith 
14388cc2d5dfSBarry Smith   Input Parameters:
14398cc2d5dfSBarry Smith + pc - the multigrid context
14408cc2d5dfSBarry Smith - n  - number of cycles (default is 1)
14418cc2d5dfSBarry Smith 
14428cc2d5dfSBarry Smith   Options Database Key:
1443147403d9SBarry Smith . -pc_mg_multiplicative_cycles n - set the number of cycles
14448cc2d5dfSBarry Smith 
14458cc2d5dfSBarry Smith   Level: advanced
14468cc2d5dfSBarry Smith 
1447f1580f4eSBarry Smith   Note:
1448f1580f4eSBarry Smith   This is not associated with setting a v or w cycle, that is set with `PCMGSetCycleType()`
14498cc2d5dfSBarry Smith 
1450562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`, `PCMGCycleType`, `PCMGType`
14518cc2d5dfSBarry Smith @*/
1452d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGMultiplicativeSetCycles(PC pc, PetscInt n)
1453d71ae5a4SJacob Faibussowitsch {
1454f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
14558cc2d5dfSBarry Smith 
14568cc2d5dfSBarry Smith   PetscFunctionBegin;
14570700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1458c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
14592a21e185SBarry Smith   mg->cyclesperpcapply = n;
14603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14618cc2d5dfSBarry Smith }
14628cc2d5dfSBarry Smith 
1463bbbcb081SMark Adams /*
1464bbbcb081SMark Adams    Since the finest level KSP shares the original matrix (of the entire system), it's preconditioner
1465bbbcb081SMark Adams    should not be updated if the whole PC is supposed to reuse the preconditioner
1466bbbcb081SMark Adams */
1467bbbcb081SMark Adams static PetscErrorCode PCSetReusePreconditioner_MG(PC pc, PetscBool flag)
1468bbbcb081SMark Adams {
1469bbbcb081SMark Adams   PC_MG         *mg       = (PC_MG *)pc->data;
1470bbbcb081SMark Adams   PC_MG_Levels **mglevels = mg->levels;
1471bbbcb081SMark Adams   PetscInt       levels;
1472bbbcb081SMark Adams   PC             tpc;
1473bbbcb081SMark Adams 
1474bbbcb081SMark Adams   PetscFunctionBegin;
1475bbbcb081SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1476bbbcb081SMark Adams   PetscValidLogicalCollectiveBool(pc, flag, 2);
1477bbbcb081SMark Adams   if (mglevels) {
1478bbbcb081SMark Adams     levels = mglevels[0]->levels;
1479bbbcb081SMark Adams     PetscCall(KSPGetPC(mglevels[levels - 1]->smoothd, &tpc));
1480bbbcb081SMark Adams     tpc->reusepreconditioner = flag;
1481bbbcb081SMark Adams     PetscCall(KSPGetPC(mglevels[levels - 1]->smoothu, &tpc));
1482bbbcb081SMark Adams     tpc->reusepreconditioner = flag;
1483bbbcb081SMark Adams   }
1484bbbcb081SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1485bbbcb081SMark Adams }
1486bbbcb081SMark Adams 
148766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetGalerkin_MG(PC pc, PCMGGalerkinType use)
1488d71ae5a4SJacob Faibussowitsch {
1489fb15c04eSBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
1490fb15c04eSBarry Smith 
1491fb15c04eSBarry Smith   PetscFunctionBegin;
14922134b1e4SBarry Smith   mg->galerkin = use;
14933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1494fb15c04eSBarry Smith }
1495fb15c04eSBarry Smith 
1496c2be2410SBarry Smith /*@
149797177400SBarry Smith   PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
149882b87d87SMatthew G. Knepley   finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1499c2be2410SBarry Smith 
1500c3339decSBarry Smith   Logically Collective
1501c2be2410SBarry Smith 
1502c2be2410SBarry Smith   Input Parameters:
1503c91913d3SJed Brown + pc  - the multigrid context
1504f1580f4eSBarry Smith - use - one of `PC_MG_GALERKIN_BOTH`, `PC_MG_GALERKIN_PMAT`, `PC_MG_GALERKIN_MAT`, or `PC_MG_GALERKIN_NONE`
1505c2be2410SBarry Smith 
1506c2be2410SBarry Smith   Options Database Key:
1507147403d9SBarry Smith . -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1508c2be2410SBarry Smith 
1509c2be2410SBarry Smith   Level: intermediate
1510c2be2410SBarry Smith 
1511f1580f4eSBarry Smith   Note:
1512f1580f4eSBarry Smith   Some codes that use `PCMG` such as `PCGAMG` use Galerkin internally while constructing the hierarchy and thus do not
1513f1580f4eSBarry Smith   use the `PCMG` construction of the coarser grids.
15141c1aac46SBarry Smith 
1515562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetGalerkin()`, `PCMGGalerkinType`
1516c2be2410SBarry Smith @*/
1517d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetGalerkin(PC pc, PCMGGalerkinType use)
1518d71ae5a4SJacob Faibussowitsch {
1519c2be2410SBarry Smith   PetscFunctionBegin;
15200700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1521cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetGalerkin_C", (PC, PCMGGalerkinType), (pc, use));
15223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1523c2be2410SBarry Smith }
1524c2be2410SBarry Smith 
15253fc8bf9cSBarry Smith /*@
1526f1580f4eSBarry Smith   PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e. A_i-1 = r_i * A_i * p_i
15273fc8bf9cSBarry Smith 
15283fc8bf9cSBarry Smith   Not Collective
15293fc8bf9cSBarry Smith 
15303fc8bf9cSBarry Smith   Input Parameter:
15313fc8bf9cSBarry Smith . pc - the multigrid context
15323fc8bf9cSBarry Smith 
15333fc8bf9cSBarry Smith   Output Parameter:
1534f1580f4eSBarry 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`
15353fc8bf9cSBarry Smith 
15363fc8bf9cSBarry Smith   Level: intermediate
15373fc8bf9cSBarry Smith 
1538562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGGalerkinType`
15393fc8bf9cSBarry Smith @*/
1540d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetGalerkin(PC pc, PCMGGalerkinType *galerkin)
1541d71ae5a4SJacob Faibussowitsch {
1542f3fbd535SBarry Smith   PC_MG *mg = (PC_MG *)pc->data;
15433fc8bf9cSBarry Smith 
15443fc8bf9cSBarry Smith   PetscFunctionBegin;
15450700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15462134b1e4SBarry Smith   *galerkin = mg->galerkin;
15473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15483fc8bf9cSBarry Smith }
15493fc8bf9cSBarry Smith 
155066976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1551d71ae5a4SJacob Faibussowitsch {
1552f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1553f3b08a26SMatthew G. Knepley 
1554f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1555f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
15563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1557f3b08a26SMatthew G. Knepley }
1558f3b08a26SMatthew G. Knepley 
155966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1560d71ae5a4SJacob Faibussowitsch {
1561f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
1562f3b08a26SMatthew G. Knepley 
1563f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1564f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
15653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1566f3b08a26SMatthew G. Knepley }
1567f3b08a26SMatthew G. Knepley 
156866976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
1569d71ae5a4SJacob Faibussowitsch {
15702b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15712b3cbbdaSStefano Zampini 
15722b3cbbdaSStefano Zampini   PetscFunctionBegin;
15732b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15742b3cbbdaSStefano Zampini   mg->coarseSpaceType    = ctype;
1575a077d33dSBarry Smith   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_BOTH));
15763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15772b3cbbdaSStefano Zampini }
15782b3cbbdaSStefano Zampini 
157966976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
1580d71ae5a4SJacob Faibussowitsch {
15812b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *)pc->data;
15822b3cbbdaSStefano Zampini 
15832b3cbbdaSStefano Zampini   PetscFunctionBegin;
15842b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15862b3cbbdaSStefano Zampini }
15872b3cbbdaSStefano Zampini 
158866976f2fSJacob Faibussowitsch static PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
1589d71ae5a4SJacob Faibussowitsch {
159041b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
159141b6fd38SMatthew G. Knepley 
159241b6fd38SMatthew G. Knepley   PetscFunctionBegin;
159341b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
15943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159541b6fd38SMatthew G. Knepley }
159641b6fd38SMatthew G. Knepley 
159766976f2fSJacob Faibussowitsch static PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
1598d71ae5a4SJacob Faibussowitsch {
159941b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *)pc->data;
160041b6fd38SMatthew G. Knepley 
160141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
160241b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
16033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160441b6fd38SMatthew G. Knepley }
160541b6fd38SMatthew G. Knepley 
1606cc4c1da9SBarry Smith /*@
16072b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
16082b3cbbdaSStefano Zampini 
16092b3cbbdaSStefano 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.
16102b3cbbdaSStefano Zampini 
1611c3339decSBarry Smith   Logically Collective
16122b3cbbdaSStefano Zampini 
16132b3cbbdaSStefano Zampini   Input Parameters:
16142b3cbbdaSStefano Zampini + pc    - the multigrid context
16152b3cbbdaSStefano Zampini - ctype - the type of coarse space
16162b3cbbdaSStefano Zampini 
16172b3cbbdaSStefano Zampini   Options Database Keys:
16182b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
1619a3b724e8SBarry Smith - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, `polynomial`, `harmonic`, `eigenvector`, `generalized_eigenvector`, `gdsw`
16202b3cbbdaSStefano Zampini 
16212b3cbbdaSStefano Zampini   Level: intermediate
16222b3cbbdaSStefano Zampini 
1623a077d33dSBarry Smith   Note:
1624a077d33dSBarry Smith   Requires a `DM` with specific functionality be attached to the `PC`.
1625a077d33dSBarry Smith 
1626a077d33dSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`, `DM`
16272b3cbbdaSStefano Zampini @*/
1628d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
1629d71ae5a4SJacob Faibussowitsch {
16302b3cbbdaSStefano Zampini   PetscFunctionBegin;
16312b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16322b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc, ctype, 2);
16332b3cbbdaSStefano Zampini   PetscTryMethod(pc, "PCMGSetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType), (pc, ctype));
16343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16352b3cbbdaSStefano Zampini }
16362b3cbbdaSStefano Zampini 
1637cc4c1da9SBarry Smith /*@
16382b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
16392b3cbbdaSStefano Zampini 
16402b3cbbdaSStefano Zampini   Not Collective
16412b3cbbdaSStefano Zampini 
16422b3cbbdaSStefano Zampini   Input Parameter:
16432b3cbbdaSStefano Zampini . pc - the multigrid context
16442b3cbbdaSStefano Zampini 
16452b3cbbdaSStefano Zampini   Output Parameter:
16462b3cbbdaSStefano Zampini . ctype - the type of coarse space
16472b3cbbdaSStefano Zampini 
16482b3cbbdaSStefano Zampini   Level: intermediate
16492b3cbbdaSStefano Zampini 
1650562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`, `PCMGSetAdaptInterpolation()`
16512b3cbbdaSStefano Zampini @*/
1652d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
1653d71ae5a4SJacob Faibussowitsch {
16542b3cbbdaSStefano Zampini   PetscFunctionBegin;
16552b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
16564f572ea9SToby Isaac   PetscAssertPointer(ctype, 2);
16572b3cbbdaSStefano Zampini   PetscUseMethod(pc, "PCMGGetAdaptCoarseSpaceType_C", (PC, PCMGCoarseSpaceType *), (pc, ctype));
16583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16592b3cbbdaSStefano Zampini }
16602b3cbbdaSStefano Zampini 
16612b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1662f3b08a26SMatthew G. Knepley /*@
1663f3b08a26SMatthew 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.
1664f3b08a26SMatthew G. Knepley 
1665c3339decSBarry Smith   Logically Collective
1666f3b08a26SMatthew G. Knepley 
1667f3b08a26SMatthew G. Knepley   Input Parameters:
1668f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1669f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1670f3b08a26SMatthew G. Knepley 
1671f3b08a26SMatthew G. Knepley   Options Database Keys:
1672f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1673f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1674f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1675f3b08a26SMatthew G. Knepley 
1676f3b08a26SMatthew G. Knepley   Level: intermediate
1677f3b08a26SMatthew G. Knepley 
1678562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1679f3b08a26SMatthew G. Knepley @*/
1680d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1681d71ae5a4SJacob Faibussowitsch {
1682f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1683f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1684cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptInterpolation_C", (PC, PetscBool), (pc, adapt));
16853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1686f3b08a26SMatthew G. Knepley }
1687f3b08a26SMatthew G. Knepley 
1688f3b08a26SMatthew G. Knepley /*@
1689f1580f4eSBarry Smith   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh,
1690f1580f4eSBarry Smith   and thus accurately interpolated.
1691f3b08a26SMatthew G. Knepley 
169220f4b53cSBarry Smith   Not Collective
1693f3b08a26SMatthew G. Knepley 
1694f3b08a26SMatthew G. Knepley   Input Parameter:
1695f3b08a26SMatthew G. Knepley . pc - the multigrid context
1696f3b08a26SMatthew G. Knepley 
1697f3b08a26SMatthew G. Knepley   Output Parameter:
1698f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1699f3b08a26SMatthew G. Knepley 
1700f3b08a26SMatthew G. Knepley   Level: intermediate
1701f3b08a26SMatthew G. Knepley 
1702562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
1703f3b08a26SMatthew G. Knepley @*/
1704d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1705d71ae5a4SJacob Faibussowitsch {
1706f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1707f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17084f572ea9SToby Isaac   PetscAssertPointer(adapt, 2);
1709cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptInterpolation_C", (PC, PetscBool *), (pc, adapt));
17103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1711f3b08a26SMatthew G. Knepley }
1712f3b08a26SMatthew G. Knepley 
17134b9ad928SBarry Smith /*@
171441b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
171541b6fd38SMatthew G. Knepley 
1716c3339decSBarry Smith   Logically Collective
171741b6fd38SMatthew G. Knepley 
171841b6fd38SMatthew G. Knepley   Input Parameters:
171941b6fd38SMatthew G. Knepley + pc - the multigrid context
172041b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
172141b6fd38SMatthew G. Knepley 
1722f1580f4eSBarry Smith   Options Database Key:
172341b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
172441b6fd38SMatthew G. Knepley 
172541b6fd38SMatthew G. Knepley   Level: intermediate
172641b6fd38SMatthew G. Knepley 
1727562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
172841b6fd38SMatthew G. Knepley @*/
1729d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
1730d71ae5a4SJacob Faibussowitsch {
173141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
173241b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1733cac4c232SBarry Smith   PetscTryMethod(pc, "PCMGSetAdaptCR_C", (PC, PetscBool), (pc, cr));
17343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
173541b6fd38SMatthew G. Knepley }
173641b6fd38SMatthew G. Knepley 
173741b6fd38SMatthew G. Knepley /*@
173841b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
173941b6fd38SMatthew G. Knepley 
174020f4b53cSBarry Smith   Not Collective
174141b6fd38SMatthew G. Knepley 
174241b6fd38SMatthew G. Knepley   Input Parameter:
174341b6fd38SMatthew G. Knepley . pc - the multigrid context
174441b6fd38SMatthew G. Knepley 
174541b6fd38SMatthew G. Knepley   Output Parameter:
174641b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
174741b6fd38SMatthew G. Knepley 
174841b6fd38SMatthew G. Knepley   Level: intermediate
174941b6fd38SMatthew G. Knepley 
1750562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
175141b6fd38SMatthew G. Knepley @*/
1752d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
1753d71ae5a4SJacob Faibussowitsch {
175441b6fd38SMatthew G. Knepley   PetscFunctionBegin;
175541b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
17564f572ea9SToby Isaac   PetscAssertPointer(cr, 2);
1757cac4c232SBarry Smith   PetscUseMethod(pc, "PCMGGetAdaptCR_C", (PC, PetscBool *), (pc, cr));
17583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175941b6fd38SMatthew G. Knepley }
176041b6fd38SMatthew G. Knepley 
176141b6fd38SMatthew G. Knepley /*@
176206792cafSBarry Smith   PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1763f1580f4eSBarry Smith   on all levels.  Use `PCMGDistinctSmoothUp()` to create separate up and down smoothers if you want different numbers of
1764710315b6SLawrence Mitchell   pre- and post-smoothing steps.
176506792cafSBarry Smith 
1766c3339decSBarry Smith   Logically Collective
176706792cafSBarry Smith 
176806792cafSBarry Smith   Input Parameters:
1769feefa0e1SJacob Faibussowitsch + pc - the multigrid context
177006792cafSBarry Smith - n  - the number of smoothing steps
177106792cafSBarry Smith 
177206792cafSBarry Smith   Options Database Key:
1773a2b725a8SWilliam Gropp . -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
177406792cafSBarry Smith 
177506792cafSBarry Smith   Level: advanced
177606792cafSBarry Smith 
1777f1580f4eSBarry Smith   Note:
1778f1580f4eSBarry 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.
177906792cafSBarry Smith 
1780562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetDistinctSmoothUp()`
178106792cafSBarry Smith @*/
1782d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetNumberSmooth(PC pc, PetscInt n)
1783d71ae5a4SJacob Faibussowitsch {
178406792cafSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
178506792cafSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
178606792cafSBarry Smith   PetscInt       i, levels;
178706792cafSBarry Smith 
178806792cafSBarry Smith   PetscFunctionBegin;
178906792cafSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
179006792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
179128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
179206792cafSBarry Smith   levels = mglevels[0]->levels;
179306792cafSBarry Smith 
179406792cafSBarry Smith   for (i = 1; i < levels; i++) {
1795fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothu, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
1796fb842aefSJose E. Roman     PetscCall(KSPSetTolerances(mglevels[i]->smoothd, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, n));
179706792cafSBarry Smith     mg->default_smoothu = n;
179806792cafSBarry Smith     mg->default_smoothd = n;
179906792cafSBarry Smith   }
18003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
180106792cafSBarry Smith }
180206792cafSBarry Smith 
1803f442ab6aSBarry Smith /*@
1804f1580f4eSBarry Smith   PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate `KSP` from the down (pre) smoother on all levels
1805710315b6SLawrence Mitchell   and adds the suffix _up to the options name
1806f442ab6aSBarry Smith 
1807c3339decSBarry Smith   Logically Collective
1808f442ab6aSBarry Smith 
1809f1580f4eSBarry Smith   Input Parameter:
1810f442ab6aSBarry Smith . pc - the preconditioner context
1811f442ab6aSBarry Smith 
1812f442ab6aSBarry Smith   Options Database Key:
1813147403d9SBarry Smith . -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1814f442ab6aSBarry Smith 
1815f442ab6aSBarry Smith   Level: advanced
1816f442ab6aSBarry Smith 
1817f1580f4eSBarry Smith   Note:
1818f1580f4eSBarry 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.
1819f442ab6aSBarry Smith 
1820562efe2eSBarry Smith .seealso: [](ch_ksp), `PCMG`, `PCMGSetNumberSmooth()`
1821f442ab6aSBarry Smith @*/
1822d71ae5a4SJacob Faibussowitsch PetscErrorCode PCMGSetDistinctSmoothUp(PC pc)
1823d71ae5a4SJacob Faibussowitsch {
1824f442ab6aSBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1825f442ab6aSBarry Smith   PC_MG_Levels **mglevels = mg->levels;
1826f442ab6aSBarry Smith   PetscInt       i, levels;
1827f442ab6aSBarry Smith   KSP            subksp;
1828f442ab6aSBarry Smith 
1829f442ab6aSBarry Smith   PetscFunctionBegin;
1830f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
183128b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Must set MG levels with PCMGSetLevels() before calling");
1832f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1833f442ab6aSBarry Smith 
1834f442ab6aSBarry Smith   for (i = 1; i < levels; i++) {
1835710315b6SLawrence Mitchell     const char *prefix = NULL;
1836f442ab6aSBarry Smith     /* make sure smoother up and down are different */
18379566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc, i, &subksp));
18389566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd, &prefix));
18399566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp, prefix));
18409566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp, "up_"));
1841f442ab6aSBarry Smith   }
18423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1843f442ab6aSBarry Smith }
1844f442ab6aSBarry Smith 
184507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
184666976f2fSJacob Faibussowitsch static PetscErrorCode PCGetInterpolations_MG(PC pc, PetscInt *num_levels, Mat *interpolations[])
1847d71ae5a4SJacob Faibussowitsch {
184807a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
184907a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
185007a4832bSFande Kong   Mat           *mat;
185107a4832bSFande Kong   PetscInt       l;
185207a4832bSFande Kong 
185307a4832bSFande Kong   PetscFunctionBegin;
185428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
185607a4832bSFande Kong   for (l = 1; l < mg->nlevels; l++) {
185707a4832bSFande Kong     mat[l - 1] = mglevels[l]->interpolate;
18589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l - 1]));
185907a4832bSFande Kong   }
186007a4832bSFande Kong   *num_levels     = mg->nlevels;
186107a4832bSFande Kong   *interpolations = mat;
18623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
186307a4832bSFande Kong }
186407a4832bSFande Kong 
186507a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
186666976f2fSJacob Faibussowitsch static PetscErrorCode PCGetCoarseOperators_MG(PC pc, PetscInt *num_levels, Mat *coarseOperators[])
1867d71ae5a4SJacob Faibussowitsch {
186807a4832bSFande Kong   PC_MG         *mg       = (PC_MG *)pc->data;
186907a4832bSFande Kong   PC_MG_Levels **mglevels = mg->levels;
187007a4832bSFande Kong   PetscInt       l;
187107a4832bSFande Kong   Mat           *mat;
187207a4832bSFande Kong 
187307a4832bSFande Kong   PetscFunctionBegin;
187428b400f6SJacob Faibussowitsch   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
18759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels, &mat));
187607a4832bSFande Kong   for (l = 0; l < mg->nlevels - 1; l++) {
1877f4f49eeaSPierre Jolivet     PetscCall(KSPGetOperators(mglevels[l]->smoothd, NULL, &mat[l]));
18789566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
187907a4832bSFande Kong   }
188007a4832bSFande Kong   *num_levels      = mg->nlevels;
188107a4832bSFande Kong   *coarseOperators = mat;
18823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
188307a4832bSFande Kong }
188407a4832bSFande Kong 
1885f3b08a26SMatthew G. Knepley /*@C
1886f1580f4eSBarry Smith   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the `PCMG` package for coarse space construction.
1887f3b08a26SMatthew G. Knepley 
1888cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1889f3b08a26SMatthew G. Knepley 
1890f3b08a26SMatthew G. Knepley   Input Parameters:
1891f3b08a26SMatthew G. Knepley + name     - name of the constructor
18924d4d2bdcSBarry Smith - function - constructor routine, see `PCMGCoarseSpaceConstructorFn`
1893f3b08a26SMatthew G. Knepley 
1894f3b08a26SMatthew G. Knepley   Level: advanced
1895f3b08a26SMatthew G. Knepley 
1896feefa0e1SJacob Faibussowitsch   Developer Notes:
18974d4d2bdcSBarry Smith   This does not appear to be used anywhere
1898f1580f4eSBarry Smith 
18994d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1900f3b08a26SMatthew G. Knepley @*/
19014d4d2bdcSBarry Smith PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn *function)
1902d71ae5a4SJacob Faibussowitsch {
1903f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
19049566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
19059566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList, name, function));
19063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1907f3b08a26SMatthew G. Knepley }
1908f3b08a26SMatthew G. Knepley 
1909f3b08a26SMatthew G. Knepley /*@C
1910f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1911f3b08a26SMatthew G. Knepley 
1912cc4c1da9SBarry Smith   Not Collective, No Fortran Support
1913f3b08a26SMatthew G. Knepley 
1914f3b08a26SMatthew G. Knepley   Input Parameter:
1915f3b08a26SMatthew G. Knepley . name - name of the constructor
1916f3b08a26SMatthew G. Knepley 
1917f3b08a26SMatthew G. Knepley   Output Parameter:
1918f3b08a26SMatthew G. Knepley . function - constructor routine
1919f3b08a26SMatthew G. Knepley 
1920f3b08a26SMatthew G. Knepley   Level: advanced
1921f3b08a26SMatthew G. Knepley 
19224d4d2bdcSBarry Smith .seealso: [](ch_ksp), `PCMGCoarseSpaceConstructorFn`, `PCMG`, `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1923f3b08a26SMatthew G. Knepley @*/
19244d4d2bdcSBarry Smith PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PCMGCoarseSpaceConstructorFn **function)
1925d71ae5a4SJacob Faibussowitsch {
1926f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
19279566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList, name, function));
19283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1929f3b08a26SMatthew G. Knepley }
1930f3b08a26SMatthew G. Knepley 
19313b09bd56SBarry Smith /*MC
1932efba3485SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional information about the restriction/interpolation
1933efba3485SBarry Smith    operators using `PCMGSetInterpolation()` and/or `PCMGSetRestriction()`(and possibly the coarser grid matrices) or a `DM` that can provide such information.
19343b09bd56SBarry Smith 
19353b09bd56SBarry Smith    Options Database Keys:
19363b09bd56SBarry Smith +  -pc_mg_levels <nlevels>                            - number of levels including finest
1937391689abSStefano Zampini .  -pc_mg_cycle_type <v,w>                            - provide the cycle desired
19388c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
19393b09bd56SBarry Smith .  -pc_mg_log                                         - log information about time spent on each level of the solver
1940710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup                           - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
1941efba3485SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>               - use the Galerkin process to compute coarser operators, i.e., $A_{coarse} = R A_{fine} R^T$
19428cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles                        - number of cycles to use as the preconditioner (defaults to 1)
19438cf6037eSBarry Smith .  -pc_mg_dump_matlab                                  - dumps the matrices for each level and the restriction/interpolation matrices
1944a3b724e8SBarry Smith                                                          to a `PETSCVIEWERSOCKET` for reading from MATLAB.
19458cf6037eSBarry Smith -  -pc_mg_dump_binary                                  -dumps the matrices for each level and the restriction/interpolation matrices
19468cf6037eSBarry Smith                                                         to the binary output file called binaryoutput
19473b09bd56SBarry Smith 
194820f4b53cSBarry Smith    Level: intermediate
194920f4b53cSBarry Smith 
195095452b02SPatrick Sanan    Notes:
1951efba3485SBarry Smith    `PCMG` provides a general framework for implementing multigrid methods. Use `PCGAMG` for PETSc's algebraic multigrid preconditioner, `PCHYPRE` for hypre's
1952efba3485SBarry Smith    BoomerAMG algebraic multigrid, and `PCML` for Trilinos's ML preconditioner. `PCAMGX` provides access to NVIDIA's AmgX algebraic multigrid.
1953efba3485SBarry Smith 
1954efba3485SBarry Smith    If you use `KSPSetDM()` (or `SNESSetDM()` or `TSSetDM()`) with an appropriate `DM`, such as `DMDA`, then `PCMG` will use the geometric information
1955efba3485SBarry Smith    from the `DM` to generate appropriate restriction and interpolation information and construct a geometric multigrid.
1956efba3485SBarry Smith 
1957efba3485SBarry Smith    If you do not provide an appropriate `DM` and do not provide restriction or interpolation operators with `PCMGSetInterpolation()` and/or `PCMGSetRestriction()`,
1958efba3485SBarry Smith    then `PCMG` will run multigrid with only a single level (so not really multigrid).
1959efba3485SBarry Smith 
196004c3f3b8SBarry Smith    The Krylov solver (if any) and preconditioner (smoother) and their parameters are controlled from the options database with the standard
19618f4fb22eSMark Adams    options database keywords prefixed with `-mg_levels_` to affect all the levels but the coarsest, which is controlled with `-mg_coarse_`,
19628f4fb22eSMark Adams    and the finest where `-mg_fine_` can override `-mg_levels_`.  One can set different preconditioners etc on specific levels with the prefix
19638f4fb22eSMark Adams    `-mg_levels_n_` where `n` is the level number (zero being the coarse level. For example
196404c3f3b8SBarry Smith .vb
196504c3f3b8SBarry Smith    -mg_levels_ksp_type gmres -mg_levels_pc_type bjacobi -mg_coarse_pc_type svd -mg_levels_2_pc_type sor
196604c3f3b8SBarry Smith .ve
196704c3f3b8SBarry Smith    These options also work for controlling the smoothers etc inside `PCGAMG`
196804c3f3b8SBarry Smith 
1969e87b5d96SPierre 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
19703b09bd56SBarry Smith 
19718cf6037eSBarry Smith    When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19728cf6037eSBarry Smith 
1973f1580f4eSBarry Smith    When run with `KSPRICHARDSON` the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
197423067569SBarry Smith    is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
197523067569SBarry Smith    (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
197623067569SBarry Smith    residual is computed at the end of each cycle.
197723067569SBarry Smith 
197804c3f3b8SBarry Smith .seealso: [](sec_mg), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1979db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1980db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1981db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1982f1580f4eSBarry Smith           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`,
1983f1580f4eSBarry Smith           `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetAdaptCoarseSpaceType()`
19843b09bd56SBarry Smith M*/
19853b09bd56SBarry Smith 
1986d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1987d71ae5a4SJacob Faibussowitsch {
1988f3fbd535SBarry Smith   PC_MG *mg;
1989f3fbd535SBarry Smith 
19904b9ad928SBarry Smith   PetscFunctionBegin;
19914dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mg));
19923ec1f749SStefano Zampini   pc->data               = mg;
1993f3fbd535SBarry Smith   mg->nlevels            = -1;
199410eca3edSLisandro Dalcin   mg->am                 = PC_MG_MULTIPLICATIVE;
19952134b1e4SBarry Smith   mg->galerkin           = PC_MG_GALERKIN_NONE;
1996f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1997f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1998f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1999f3fbd535SBarry Smith 
200037a44384SMark Adams   pc->useAmat = PETSC_TRUE;
200137a44384SMark Adams 
20024b9ad928SBarry Smith   pc->ops->apply             = PCApply_MG;
2003fcb023d4SJed Brown   pc->ops->applytranspose    = PCApplyTranspose_MG;
200430b0564aSStefano Zampini   pc->ops->matapply          = PCMatApply_MG;
20054dbf25a8SPierre Jolivet   pc->ops->matapplytranspose = PCMatApplyTranspose_MG;
20064b9ad928SBarry Smith   pc->ops->setup             = PCSetUp_MG;
2007a06653b4SBarry Smith   pc->ops->reset             = PCReset_MG;
20084b9ad928SBarry Smith   pc->ops->destroy           = PCDestroy_MG;
20094b9ad928SBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_MG;
20104b9ad928SBarry Smith   pc->ops->view              = PCView_MG;
2011fb15c04eSBarry Smith 
20129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
20139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetGalerkin_C", PCMGSetGalerkin_MG));
2014bbbcb081SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetReusePreconditioner_C", PCSetReusePreconditioner_MG));
20159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetLevels_C", PCMGGetLevels_MG));
20169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetLevels_C", PCMGSetLevels_MG));
20179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetInterpolations_C", PCGetInterpolations_MG));
20189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGetCoarseOperators_C", PCGetCoarseOperators_MG));
20199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptInterpolation_C", PCMGSetAdaptInterpolation_MG));
20209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptInterpolation_C", PCMGGetAdaptInterpolation_MG));
20219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCR_C", PCMGSetAdaptCR_MG));
20229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCR_C", PCMGGetAdaptCR_MG));
20232b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGSetAdaptCoarseSpaceType_C", PCMGSetAdaptCoarseSpaceType_MG));
20242b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCMGGetAdaptCoarseSpaceType_C", PCMGGetAdaptCoarseSpaceType_MG));
20253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20264b9ad928SBarry Smith }
2027