xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 1baa6e3354bfe224b33a0c158f482508792a8a6e)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h>                    /*I "petscksp.h" I*/
641b6fd38SMatthew G. Knepley #include <petsc/private/kspimpl.h>
71e25c274SJed Brown #include <petscdm.h>
8391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC,PetscBool*);
94b9ad928SBarry Smith 
10f3b08a26SMatthew G. Knepley /*
11f3b08a26SMatthew G. Knepley    Contains the list of registered coarse space construction routines
12f3b08a26SMatthew G. Knepley */
13f3b08a26SMatthew G. Knepley PetscFunctionList PCMGCoarseList = NULL;
14f3b08a26SMatthew G. Knepley 
1530b0564aSStefano Zampini PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PetscBool transpose,PetscBool matapp,PCRichardsonConvergedReason *reason)
164b9ad928SBarry Smith {
1731567311SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
1831567311SBarry Smith   PC_MG_Levels   *mgc,*mglevels = *mglevelsin;
1931567311SBarry Smith   PetscInt       cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles;
204b9ad928SBarry Smith 
214b9ad928SBarry Smith   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0));
23fcb023d4SJed Brown   if (!transpose) {
2430b0564aSStefano Zampini     if (matapp) {
259566063dSJacob Faibussowitsch       PetscCall(KSPMatSolve(mglevels->smoothd,mglevels->B,mglevels->X));  /* pre-smooth */
269566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd,pc,NULL));
2730b0564aSStefano Zampini     } else {
289566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x));  /* pre-smooth */
299566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd,pc,mglevels->x));
3030b0564aSStefano Zampini     }
31fcb023d4SJed Brown   } else {
3228b400f6SJacob Faibussowitsch     PetscCheck(!matapp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Not supported");
339566063dSJacob Faibussowitsch     PetscCall(KSPSolveTranspose(mglevels->smoothu,mglevels->b,mglevels->x)); /* transpose of post-smooth */
349566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(mglevels->smoothu,pc,mglevels->x));
35fcb023d4SJed Brown   }
369566063dSJacob Faibussowitsch   if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0));
3731567311SBarry Smith   if (mglevels->level) {  /* not the coarsest grid */
389566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventBegin(mglevels->eventresidual,0,0,0,0));
3930b0564aSStefano Zampini     if (matapp && !mglevels->R) {
409566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(mglevels->B,MAT_DO_NOT_COPY_VALUES,&mglevels->R));
4130b0564aSStefano Zampini     }
42fcb023d4SJed Brown     if (!transpose) {
439566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidual)(mglevels->A,mglevels->B,mglevels->X,mglevels->R));
449566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r));
45fcb023d4SJed Brown     } else {
469566063dSJacob Faibussowitsch       if (matapp) PetscCall((*mglevels->matresidualtranspose)(mglevels->A,mglevels->B,mglevels->X,mglevels->R));
479566063dSJacob Faibussowitsch       else PetscCall((*mglevels->residualtranspose)(mglevels->A,mglevels->b,mglevels->x,mglevels->r));
48fcb023d4SJed Brown     }
499566063dSJacob Faibussowitsch     if (mglevels->eventresidual) PetscCall(PetscLogEventEnd(mglevels->eventresidual,0,0,0,0));
504b9ad928SBarry Smith 
514b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
5231567311SBarry Smith     if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) {
534b9ad928SBarry Smith       PetscReal rnorm;
549566063dSJacob Faibussowitsch       PetscCall(VecNorm(mglevels->r,NORM_2,&rnorm));
554b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
5670441072SBarry Smith         if (rnorm < mg->abstol) {
574d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
589566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol));
594b9ad928SBarry Smith         } else {
604d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
619566063dSJacob 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));
624b9ad928SBarry Smith         }
634b9ad928SBarry Smith         PetscFunctionReturn(0);
644b9ad928SBarry Smith       }
654b9ad928SBarry Smith     }
664b9ad928SBarry Smith 
6731567311SBarry Smith     mgc = *(mglevelsin - 1);
689566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0));
69fcb023d4SJed Brown     if (!transpose) {
709566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->restrct,mglevels->R,&mgc->B));
719566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->restrct,mglevels->r,mgc->b));
72fcb023d4SJed Brown     } else {
739566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatRestrict(mglevels->interpolate,mglevels->R,&mgc->B));
749566063dSJacob Faibussowitsch       else PetscCall(MatRestrict(mglevels->interpolate,mglevels->r,mgc->b));
75fcb023d4SJed Brown     }
769566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0));
7730b0564aSStefano Zampini     if (matapp) {
7830b0564aSStefano Zampini       if (!mgc->X) {
799566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(mgc->B,MAT_DO_NOT_COPY_VALUES,&mgc->X));
8030b0564aSStefano Zampini       } else {
819566063dSJacob Faibussowitsch         PetscCall(MatZeroEntries(mgc->X));
8230b0564aSStefano Zampini       }
8330b0564aSStefano Zampini     } else {
849566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mgc->x));
8530b0564aSStefano Zampini     }
864b9ad928SBarry Smith     while (cycles--) {
879566063dSJacob Faibussowitsch       PetscCall(PCMGMCycle_Private(pc,mglevelsin-1,transpose,matapp,reason));
884b9ad928SBarry Smith     }
899566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0));
90fcb023d4SJed Brown     if (!transpose) {
919566063dSJacob Faibussowitsch       if (matapp) PetscCall(MatMatInterpolateAdd(mglevels->interpolate,mgc->X,mglevels->X,&mglevels->X));
929566063dSJacob Faibussowitsch       else PetscCall(MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x));
93fcb023d4SJed Brown     } else {
949566063dSJacob Faibussowitsch       PetscCall(MatInterpolateAdd(mglevels->restrct,mgc->x,mglevels->x,mglevels->x));
95fcb023d4SJed Brown     }
969566063dSJacob Faibussowitsch     if (mglevels->eventinterprestrict) PetscCall(PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0));
979566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0));
98fcb023d4SJed Brown     if (!transpose) {
9930b0564aSStefano Zampini       if (matapp) {
1009566063dSJacob Faibussowitsch         PetscCall(KSPMatSolve(mglevels->smoothu,mglevels->B,mglevels->X));    /* post smooth */
1019566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu,pc,NULL));
10230b0564aSStefano Zampini       } else {
1039566063dSJacob Faibussowitsch         PetscCall(KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x));    /* post smooth */
1049566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(mglevels->smoothu,pc,mglevels->x));
10530b0564aSStefano Zampini       }
106fcb023d4SJed Brown     } else {
10728b400f6SJacob Faibussowitsch       PetscCheck(!matapp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Not supported");
1089566063dSJacob Faibussowitsch       PetscCall(KSPSolveTranspose(mglevels->smoothd,mglevels->b,mglevels->x));    /* post smooth */
1099566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->smoothd,pc,mglevels->x));
110fcb023d4SJed Brown     }
11141b6fd38SMatthew G. Knepley     if (mglevels->cr) {
11228b400f6SJacob Faibussowitsch       PetscCheck(!matapp,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Not supported");
11341b6fd38SMatthew G. Knepley       /* TODO Turn on copy and turn off noisy if we have an exact solution
1149566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->x, mglevels->crx));
1159566063dSJacob Faibussowitsch       PetscCall(VecCopy(mglevels->b, mglevels->crb)); */
1169566063dSJacob Faibussowitsch       PetscCall(KSPSetNoisy_Private(mglevels->crx));
1179566063dSJacob Faibussowitsch       PetscCall(KSPSolve(mglevels->cr,mglevels->crb,mglevels->crx));    /* compatible relaxation */
1189566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(mglevels->cr,pc,mglevels->crx));
11941b6fd38SMatthew G. Knepley     }
1209566063dSJacob Faibussowitsch     if (mglevels->eventsmoothsolve) PetscCall(PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0));
1214b9ad928SBarry Smith   }
1224b9ad928SBarry Smith   PetscFunctionReturn(0);
1234b9ad928SBarry Smith }
1244b9ad928SBarry Smith 
125ace3abfcSBarry Smith 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)
1264b9ad928SBarry Smith {
127f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
128f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
129391689abSStefano Zampini   PC             tpc;
130391689abSStefano Zampini   PetscBool      changeu,changed;
131f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
1324b9ad928SBarry Smith 
1334b9ad928SBarry Smith   PetscFunctionBegin;
134a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
135a762d673SBarry Smith   for (i=0; i<levels; i++) {
136a762d673SBarry Smith     if (!mglevels[i]->A) {
1379566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL));
1389566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
139a762d673SBarry Smith     }
140a762d673SBarry Smith   }
141391689abSStefano Zampini 
1429566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels-1]->smoothd,&tpc));
1439566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc,&changed));
1449566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels-1]->smoothu,&tpc));
1459566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc,&changeu));
146391689abSStefano Zampini   if (!changed && !changeu) {
1479566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&mglevels[levels-1]->b));
148f3fbd535SBarry Smith     mglevels[levels-1]->b = b;
149391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
150391689abSStefano Zampini     if (!mglevels[levels-1]->b) {
151391689abSStefano Zampini       Vec *vec;
152391689abSStefano Zampini 
1539566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL));
154391689abSStefano Zampini       mglevels[levels-1]->b = *vec;
1559566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
156391689abSStefano Zampini     }
1579566063dSJacob Faibussowitsch     PetscCall(VecCopy(b,mglevels[levels-1]->b));
158391689abSStefano Zampini   }
159f3fbd535SBarry Smith   mglevels[levels-1]->x = x;
1604b9ad928SBarry Smith 
16131567311SBarry Smith   mg->rtol   = rtol;
16231567311SBarry Smith   mg->abstol = abstol;
16331567311SBarry Smith   mg->dtol   = dtol;
1644b9ad928SBarry Smith   if (rtol) {
1654b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1664b9ad928SBarry Smith     PetscReal rnorm;
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++) {
1809566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT));
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));
1849566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT));
1854b9ad928SBarry Smith     }
1864d0a8057SBarry Smith   }
1874d0a8057SBarry Smith 
1884d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
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   }
1934d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1944d0a8057SBarry Smith   *outits = i;
195391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels-1]->b = NULL;
1964b9ad928SBarry Smith   PetscFunctionReturn(0);
1974b9ad928SBarry Smith }
1984b9ad928SBarry Smith 
1993aeaf226SBarry Smith PetscErrorCode PCReset_MG(PC pc)
2003aeaf226SBarry Smith {
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));
2323aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
2339566063dSJacob Faibussowitsch         PetscCall(KSPReset(mglevels[i]->smoothd));
2343aeaf226SBarry Smith       }
2359566063dSJacob Faibussowitsch       PetscCall(KSPReset(mglevels[i]->smoothu));
2369566063dSJacob Faibussowitsch       if (mglevels[i]->cr) PetscCall(KSPReset(mglevels[i]->cr));
2373aeaf226SBarry Smith     }
238f3b08a26SMatthew G. Knepley     mg->Nc = 0;
2393aeaf226SBarry Smith   }
2403aeaf226SBarry Smith   PetscFunctionReturn(0);
2413aeaf226SBarry Smith }
2423aeaf226SBarry Smith 
24341b6fd38SMatthew G. Knepley /* Implementing CR
24441b6fd38SMatthew G. Knepley 
24541b6fd38SMatthew 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
24641b6fd38SMatthew G. Knepley 
24741b6fd38SMatthew G. Knepley   Inj^T (Inj Inj^T)^{-1} Inj
24841b6fd38SMatthew G. Knepley 
24941b6fd38SMatthew G. Knepley and if Inj is a VecScatter, as it is now in PETSc, we have
25041b6fd38SMatthew G. Knepley 
25141b6fd38SMatthew G. Knepley   Inj^T Inj
25241b6fd38SMatthew G. Knepley 
25341b6fd38SMatthew G. Knepley and
25441b6fd38SMatthew G. Knepley 
25541b6fd38SMatthew G. Knepley   S = I - Inj^T Inj
25641b6fd38SMatthew G. Knepley 
25741b6fd38SMatthew G. Knepley since
25841b6fd38SMatthew G. Knepley 
25941b6fd38SMatthew G. Knepley   Inj S = Inj - (Inj Inj^T) Inj = 0.
26041b6fd38SMatthew G. Knepley 
26141b6fd38SMatthew G. Knepley Brannick suggests
26241b6fd38SMatthew G. Knepley 
26341b6fd38SMatthew G. Knepley   A \to S^T A S  \qquad\mathrm{and}\qquad M \to S^T M S
26441b6fd38SMatthew G. Knepley 
26541b6fd38SMatthew 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
26641b6fd38SMatthew G. Knepley 
26741b6fd38SMatthew G. Knepley   M^{-1} A \to S M^{-1} A S
26841b6fd38SMatthew G. Knepley 
26941b6fd38SMatthew G. Knepley In fact, since it is somewhat hard in PETSc to do the symmetric application, we will just apply S on the left.
27041b6fd38SMatthew G. Knepley 
27141b6fd38SMatthew G. Knepley   Check: || Inj P - I ||_F < tol
27241b6fd38SMatthew G. Knepley   Check: In general, Inj Inj^T = I
27341b6fd38SMatthew G. Knepley */
27441b6fd38SMatthew G. Knepley 
27541b6fd38SMatthew G. Knepley typedef struct {
27641b6fd38SMatthew G. Knepley   PC       mg;  /* The PCMG object */
27741b6fd38SMatthew G. Knepley   PetscInt l;   /* The multigrid level for this solver */
27841b6fd38SMatthew G. Knepley   Mat      Inj; /* The injection matrix */
27941b6fd38SMatthew G. Knepley   Mat      S;   /* I - Inj^T Inj */
28041b6fd38SMatthew G. Knepley } CRContext;
28141b6fd38SMatthew G. Knepley 
28241b6fd38SMatthew G. Knepley static PetscErrorCode CRSetup_Private(PC pc)
28341b6fd38SMatthew G. Knepley {
28441b6fd38SMatthew G. Knepley   CRContext     *ctx;
28541b6fd38SMatthew G. Knepley   Mat            It;
28641b6fd38SMatthew G. Knepley 
28741b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
2889566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
2899566063dSJacob Faibussowitsch   PetscCall(PCMGGetInjection(ctx->mg, ctx->l, &It));
29028b400f6SJacob Faibussowitsch   PetscCheck(It,PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_WRONGSTATE, "CR requires that injection be defined for this PCMG");
2919566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(It, &ctx->Inj));
2929566063dSJacob Faibussowitsch   PetscCall(MatCreateNormal(ctx->Inj, &ctx->S));
2939566063dSJacob Faibussowitsch   PetscCall(MatScale(ctx->S, -1.0));
2949566063dSJacob Faibussowitsch   PetscCall(MatShift(ctx->S,  1.0));
29541b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
29641b6fd38SMatthew G. Knepley }
29741b6fd38SMatthew G. Knepley 
29841b6fd38SMatthew G. Knepley static PetscErrorCode CRApply_Private(PC pc, Vec x, Vec y)
29941b6fd38SMatthew G. Knepley {
30041b6fd38SMatthew G. Knepley   CRContext     *ctx;
30141b6fd38SMatthew G. Knepley 
30241b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3039566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3049566063dSJacob Faibussowitsch   PetscCall(MatMult(ctx->S, x, y));
30541b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
30641b6fd38SMatthew G. Knepley }
30741b6fd38SMatthew G. Knepley 
30841b6fd38SMatthew G. Knepley static PetscErrorCode CRDestroy_Private(PC pc)
30941b6fd38SMatthew G. Knepley {
31041b6fd38SMatthew G. Knepley   CRContext     *ctx;
31141b6fd38SMatthew G. Knepley 
31241b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3139566063dSJacob Faibussowitsch   PetscCall(PCShellGetContext(pc, &ctx));
3149566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->Inj));
3159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->S));
3169566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
3179566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(pc, NULL));
31841b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
31941b6fd38SMatthew G. Knepley }
32041b6fd38SMatthew G. Knepley 
32141b6fd38SMatthew G. Knepley static PetscErrorCode CreateCR_Private(PC pc, PetscInt l, PC *cr)
32241b6fd38SMatthew G. Knepley {
32341b6fd38SMatthew G. Knepley   CRContext     *ctx;
32441b6fd38SMatthew G. Knepley 
32541b6fd38SMatthew G. Knepley   PetscFunctionBeginUser;
3269566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject) pc), cr));
3279566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) *cr, "S (complementary projector to injection)"));
3289566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(1, &ctx));
32941b6fd38SMatthew G. Knepley   ctx->mg = pc;
33041b6fd38SMatthew G. Knepley   ctx->l  = l;
3319566063dSJacob Faibussowitsch   PetscCall(PCSetType(*cr, PCSHELL));
3329566063dSJacob Faibussowitsch   PetscCall(PCShellSetContext(*cr, ctx));
3339566063dSJacob Faibussowitsch   PetscCall(PCShellSetApply(*cr, CRApply_Private));
3349566063dSJacob Faibussowitsch   PetscCall(PCShellSetSetUp(*cr, CRSetup_Private));
3359566063dSJacob Faibussowitsch   PetscCall(PCShellSetDestroy(*cr, CRDestroy_Private));
33641b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
33741b6fd38SMatthew G. Knepley }
33841b6fd38SMatthew G. Knepley 
33997d33e41SMatthew G. Knepley PetscErrorCode PCMGSetLevels_MG(PC pc,PetscInt levels,MPI_Comm *comms)
3404b9ad928SBarry Smith {
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);
355548767e0SJed Brown   if (mg->nlevels == levels) PetscFunctionReturn(0);
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++) {
3633aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
3649566063dSJacob Faibussowitsch         PetscCall(KSPDestroy(&mglevels[i]->smoothd));
3653aeaf226SBarry Smith       }
3669566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
3679566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
3689566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
3693aeaf226SBarry Smith     }
3709566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
3713aeaf226SBarry Smith   }
372f3fbd535SBarry Smith 
373f3fbd535SBarry Smith   mg->nlevels = levels;
374f3fbd535SBarry Smith 
3759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(levels,&mglevels));
3769566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*))));
377f3fbd535SBarry Smith 
3789566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc,&prefix));
379f3fbd535SBarry Smith 
380a9db87a2SMatthew G Knepley   mg->stageApply = 0;
381f3fbd535SBarry Smith   for (i=0; i<levels; i++) {
3829566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(pc,&mglevels[i]));
3832fa5cd67SKarl Rupp 
384f3fbd535SBarry Smith     mglevels[i]->level               = i;
385f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
38610eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
387336babb1SJed Brown     mg->default_smoothu              = 2;
388336babb1SJed Brown     mg->default_smoothd              = 2;
38963e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
39063e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
39163e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
39263e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
393f3fbd535SBarry Smith 
394f3fbd535SBarry Smith     if (comms) comm = comms[i];
395d5a8f7e6SBarry Smith     if (comm != MPI_COMM_NULL) {
3969566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm,&mglevels[i]->smoothd));
3979566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure));
3989566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i));
3999566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix));
4009566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level));
4010ee9a668SBarry Smith       if (i || levels == 1) {
4020ee9a668SBarry Smith         char tprefix[128];
4030ee9a668SBarry Smith 
4049566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV));
4059566063dSJacob Faibussowitsch         PetscCall(KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL));
4069566063dSJacob Faibussowitsch         PetscCall(KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE));
4079566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[i]->smoothd,&ipc));
4089566063dSJacob Faibussowitsch         PetscCall(PCSetType(ipc,PCSOR));
4099566063dSJacob Faibussowitsch         PetscCall(KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd));
410f3fbd535SBarry Smith 
4119566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(tprefix,128,"mg_levels_%d_",(int)i));
4129566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix));
4130ee9a668SBarry Smith       } else {
4149566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_"));
415f3fbd535SBarry Smith 
4169dbfc187SHong Zhang         /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
4179566063dSJacob Faibussowitsch         PetscCall(KSPSetType(mglevels[0]->smoothd,KSPPREONLY));
4189566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(mglevels[0]->smoothd,&ipc));
4199566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(comm,&size));
420f3fbd535SBarry Smith         if (size > 1) {
4219566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc,PCREDUNDANT));
422f3fbd535SBarry Smith         } else {
4239566063dSJacob Faibussowitsch           PetscCall(PCSetType(ipc,PCLU));
424f3fbd535SBarry Smith         }
4259566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS));
426f3fbd535SBarry Smith       }
4279566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd));
428d5a8f7e6SBarry Smith     }
429f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
43031567311SBarry Smith     mg->rtol             = 0.0;
43131567311SBarry Smith     mg->abstol           = 0.0;
43231567311SBarry Smith     mg->dtol             = 0.0;
43331567311SBarry Smith     mg->ttol             = 0.0;
43431567311SBarry Smith     mg->cyclesperpcapply = 1;
435f3fbd535SBarry Smith   }
436f3fbd535SBarry Smith   mg->levels = mglevels;
4379566063dSJacob Faibussowitsch   PetscCall(PCMGSetType(pc,mgtype));
4384b9ad928SBarry Smith   PetscFunctionReturn(0);
4394b9ad928SBarry Smith }
4404b9ad928SBarry Smith 
44197d33e41SMatthew G. Knepley /*@C
44297d33e41SMatthew G. Knepley    PCMGSetLevels - Sets the number of levels to use with MG.
44397d33e41SMatthew G. Knepley    Must be called before any other MG routine.
44497d33e41SMatthew G. Knepley 
44597d33e41SMatthew G. Knepley    Logically Collective on PC
44697d33e41SMatthew G. Knepley 
44797d33e41SMatthew G. Knepley    Input Parameters:
44897d33e41SMatthew G. Knepley +  pc - the preconditioner context
44997d33e41SMatthew G. Knepley .  levels - the number of levels
45097d33e41SMatthew G. Knepley -  comms - optional communicators for each level; this is to allow solving the coarser problems
451d5a8f7e6SBarry Smith            on smaller sets of processes. For processes that are not included in the computation
45205552d4bSJunchao Zhang            you must pass MPI_COMM_NULL. Use comms = NULL to specify that all processes
45305552d4bSJunchao Zhang            should participate in each level of problem.
45497d33e41SMatthew G. Knepley 
45597d33e41SMatthew G. Knepley    Level: intermediate
45697d33e41SMatthew G. Knepley 
45797d33e41SMatthew G. Knepley    Notes:
45897d33e41SMatthew G. Knepley      If the number of levels is one then the multigrid uses the -mg_levels prefix
45997d33e41SMatthew G. Knepley      for setting the level options rather than the -mg_coarse prefix.
46097d33e41SMatthew G. Knepley 
461d5a8f7e6SBarry Smith      You can free the information in comms after this routine is called.
462d5a8f7e6SBarry Smith 
463d5a8f7e6SBarry Smith      The array of MPI communicators must contain MPI_COMM_NULL for those ranks that at each level
464d5a8f7e6SBarry Smith      are not participating in the coarser solve. For example, with 2 levels and 1 and 2 ranks on
465d5a8f7e6SBarry Smith      the two levels, rank 0 in the original communicator will pass in an array of 2 communicators
466d5a8f7e6SBarry Smith      of size 2 and 1, while rank 1 in the original communicator will pass in array of 2 communicators
467d5a8f7e6SBarry Smith      the first of size 2 and the second of value MPI_COMM_NULL since the rank 1 does not participate
468d5a8f7e6SBarry Smith      in the coarse grid solve.
469d5a8f7e6SBarry Smith 
470d5a8f7e6SBarry Smith      Since each coarser level may have a new MPI_Comm with fewer ranks than the previous, one
471d5a8f7e6SBarry Smith      must take special care in providing the restriction and interpolation operation. We recommend
472d5a8f7e6SBarry Smith      providing these as two step operations; first perform a standard restriction or interpolation on
473d5a8f7e6SBarry Smith      the full number of ranks for that level and then use an MPI call to copy the resulting vector
47405552d4bSJunchao Zhang      array entries (after calls to VecGetArray()) to the smaller or larger number of ranks, note in both
475d5a8f7e6SBarry Smith      cases the MPI calls must be made on the larger of the two communicators. Traditional MPI send and
476d5a8f7e6SBarry Smith      recieves or MPI_AlltoAllv() could be used to do the reshuffling of the vector entries.
477d5a8f7e6SBarry Smith 
47805552d4bSJunchao Zhang    Fortran Notes:
47905552d4bSJunchao Zhang      Use comms = PETSC_NULL_MPI_COMM as the equivalent of NULL in the C interface. Note PETSC_NULL_MPI_COMM
48005552d4bSJunchao Zhang      is not MPI_COMM_NULL. It is more like PETSC_NULL_INTEGER, PETSC_NULL_REAL etc.
481d5a8f7e6SBarry Smith 
482db781477SPatrick Sanan .seealso: `PCMGSetType()`, `PCMGGetLevels()`
48397d33e41SMatthew G. Knepley @*/
48497d33e41SMatthew G. Knepley PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
48597d33e41SMatthew G. Knepley {
48697d33e41SMatthew G. Knepley   PetscFunctionBegin;
48797d33e41SMatthew G. Knepley   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
48897d33e41SMatthew G. Knepley   if (comms) PetscValidPointer(comms,3);
489cac4c232SBarry Smith   PetscTryMethod(pc,"PCMGSetLevels_C",(PC,PetscInt,MPI_Comm*),(pc,levels,comms));
49097d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
49197d33e41SMatthew G. Knepley }
49297d33e41SMatthew G. Knepley 
493c07bf074SBarry Smith PetscErrorCode PCDestroy_MG(PC pc)
494c07bf074SBarry Smith {
495a06653b4SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
496a06653b4SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
497a06653b4SBarry Smith   PetscInt       i,n;
498c07bf074SBarry Smith 
499c07bf074SBarry Smith   PetscFunctionBegin;
5009566063dSJacob Faibussowitsch   PetscCall(PCReset_MG(pc));
501a06653b4SBarry Smith   if (mglevels) {
502a06653b4SBarry Smith     n = mglevels[0]->levels;
503a06653b4SBarry Smith     for (i=0; i<n; i++) {
504a06653b4SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
5059566063dSJacob Faibussowitsch         PetscCall(KSPDestroy(&mglevels[i]->smoothd));
506a06653b4SBarry Smith       }
5079566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->smoothu));
5089566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&mglevels[i]->cr));
5099566063dSJacob Faibussowitsch       PetscCall(PetscFree(mglevels[i]));
510a06653b4SBarry Smith     }
5119566063dSJacob Faibussowitsch     PetscCall(PetscFree(mg->levels));
512a06653b4SBarry Smith   }
5139566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
5149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",NULL));
5159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",NULL));
5162b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",NULL));
5172b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",NULL));
5182b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",NULL));
5192b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",NULL));
5202b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",NULL));
5212b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptInterpolation_C",NULL));
5222b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptInterpolation_C",NULL));
5232b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptCR_C",NULL));
5242b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptCR_C",NULL));
5252b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptCoarseSpaceType_C",NULL));
5262b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptCoarseSpaceType_C",NULL));
527f3fbd535SBarry Smith   PetscFunctionReturn(0);
528f3fbd535SBarry Smith }
529f3fbd535SBarry Smith 
530f3fbd535SBarry Smith /*
531f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
532f3fbd535SBarry Smith              or full cycle of multigrid.
533f3fbd535SBarry Smith 
534f3fbd535SBarry Smith   Note:
535f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
536f3fbd535SBarry Smith */
53730b0564aSStefano Zampini static PetscErrorCode PCApply_MG_Internal(PC pc,Vec b,Vec x,Mat B,Mat X,PetscBool transpose)
538f3fbd535SBarry Smith {
539f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
540f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
541391689abSStefano Zampini   PC             tpc;
542f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
54330b0564aSStefano Zampini   PetscBool      changeu,changed,matapp;
544f3fbd535SBarry Smith 
545f3fbd535SBarry Smith   PetscFunctionBegin;
54630b0564aSStefano Zampini   matapp = (PetscBool)(B && X);
5479566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePush(mg->stageApply));
548e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
549298cc208SBarry Smith   for (i=0; i<levels; i++) {
550e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
5519566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL));
5529566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)mglevels[i]->A));
553e1d8e5deSBarry Smith     }
554e1d8e5deSBarry Smith   }
555e1d8e5deSBarry Smith 
5569566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels-1]->smoothd,&tpc));
5579566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc,&changed));
5589566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[levels-1]->smoothu,&tpc));
5599566063dSJacob Faibussowitsch   PetscCall(PCPreSolveChangeRHS(tpc,&changeu));
560391689abSStefano Zampini   if (!changeu && !changed) {
56130b0564aSStefano Zampini     if (matapp) {
5629566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels-1]->B));
56330b0564aSStefano Zampini       mglevels[levels-1]->B = B;
56430b0564aSStefano Zampini     } else {
5659566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&mglevels[levels-1]->b));
566f3fbd535SBarry Smith       mglevels[levels-1]->b = b;
56730b0564aSStefano Zampini     }
568391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
56930b0564aSStefano Zampini     if (matapp) {
57030b0564aSStefano Zampini       if (mglevels[levels-1]->B) {
57130b0564aSStefano Zampini         PetscInt  N1,N2;
57230b0564aSStefano Zampini         PetscBool flg;
57330b0564aSStefano Zampini 
5749566063dSJacob Faibussowitsch         PetscCall(MatGetSize(mglevels[levels-1]->B,NULL,&N1));
5759566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B,NULL,&N2));
5769566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels-1]->B,((PetscObject)B)->type_name,&flg));
57730b0564aSStefano Zampini         if (N1 != N2 || !flg) {
5789566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&mglevels[levels-1]->B));
57930b0564aSStefano Zampini         }
58030b0564aSStefano Zampini       }
58130b0564aSStefano Zampini       if (!mglevels[levels-1]->B) {
5829566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&mglevels[levels-1]->B));
58330b0564aSStefano Zampini       } else {
5849566063dSJacob Faibussowitsch         PetscCall(MatCopy(B,mglevels[levels-1]->B,SAME_NONZERO_PATTERN));
58530b0564aSStefano Zampini       }
58630b0564aSStefano Zampini     } else {
587391689abSStefano Zampini       if (!mglevels[levels-1]->b) {
588391689abSStefano Zampini         Vec *vec;
589391689abSStefano Zampini 
5909566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL));
591391689abSStefano Zampini         mglevels[levels-1]->b = *vec;
5929566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
593391689abSStefano Zampini       }
5949566063dSJacob Faibussowitsch       PetscCall(VecCopy(b,mglevels[levels-1]->b));
595391689abSStefano Zampini     }
59630b0564aSStefano Zampini   }
59730b0564aSStefano Zampini   if (matapp) { mglevels[levels-1]->X = X; }
59830b0564aSStefano Zampini   else { mglevels[levels-1]->x = x; }
59930b0564aSStefano Zampini 
60030b0564aSStefano Zampini   /* If coarser Xs are present, it means we have already block applied the PC at least once
60130b0564aSStefano Zampini      Reset operators if sizes/type do no match */
60230b0564aSStefano Zampini   if (matapp && levels > 1 && mglevels[levels-2]->X) {
60330b0564aSStefano Zampini     PetscInt  Xc,Bc;
60430b0564aSStefano Zampini     PetscBool flg;
60530b0564aSStefano Zampini 
6069566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels-2]->X,NULL,&Xc));
6079566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mglevels[levels-1]->B,NULL,&Bc));
6089566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mglevels[levels-2]->X,((PetscObject)mglevels[levels-1]->X)->type_name,&flg));
60930b0564aSStefano Zampini     if (Xc != Bc || !flg) {
6109566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&mglevels[levels-1]->R));
61130b0564aSStefano Zampini       for (i=0;i<levels-1;i++) {
6129566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->R));
6139566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->B));
6149566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&mglevels[i]->X));
61530b0564aSStefano Zampini       }
61630b0564aSStefano Zampini     }
61730b0564aSStefano Zampini   }
618391689abSStefano Zampini 
61931567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
6209566063dSJacob Faibussowitsch     if (matapp) PetscCall(MatZeroEntries(X));
6219566063dSJacob Faibussowitsch     else PetscCall(VecZeroEntries(x));
62231567311SBarry Smith     for (i=0; i<mg->cyclesperpcapply; i++) {
6239566063dSJacob Faibussowitsch       PetscCall(PCMGMCycle_Private(pc,mglevels+levels-1,transpose,matapp,NULL));
624f3fbd535SBarry Smith     }
6252fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
6269566063dSJacob Faibussowitsch     PetscCall(PCMGACycle_Private(pc,mglevels,transpose,matapp));
6272fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
6289566063dSJacob Faibussowitsch     PetscCall(PCMGKCycle_Private(pc,mglevels,transpose,matapp));
6292fa5cd67SKarl Rupp   } else {
6309566063dSJacob Faibussowitsch     PetscCall(PCMGFCycle_Private(pc,mglevels,transpose,matapp));
631f3fbd535SBarry Smith   }
6329566063dSJacob Faibussowitsch   if (mg->stageApply) PetscCall(PetscLogStagePop());
63330b0564aSStefano Zampini   if (!changeu && !changed) {
63430b0564aSStefano Zampini     if (matapp) { mglevels[levels-1]->B = NULL; }
63530b0564aSStefano Zampini     else { mglevels[levels-1]->b = NULL; }
63630b0564aSStefano Zampini   }
637f3fbd535SBarry Smith   PetscFunctionReturn(0);
638f3fbd535SBarry Smith }
639f3fbd535SBarry Smith 
640fcb023d4SJed Brown static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
641fcb023d4SJed Brown {
642fcb023d4SJed Brown   PetscFunctionBegin;
6439566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc,b,x,NULL,NULL,PETSC_FALSE));
644fcb023d4SJed Brown   PetscFunctionReturn(0);
645fcb023d4SJed Brown }
646fcb023d4SJed Brown 
647fcb023d4SJed Brown static PetscErrorCode PCApplyTranspose_MG(PC pc,Vec b,Vec x)
648fcb023d4SJed Brown {
649fcb023d4SJed Brown   PetscFunctionBegin;
6509566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc,b,x,NULL,NULL,PETSC_TRUE));
65130b0564aSStefano Zampini   PetscFunctionReturn(0);
65230b0564aSStefano Zampini }
65330b0564aSStefano Zampini 
65430b0564aSStefano Zampini static PetscErrorCode PCMatApply_MG(PC pc,Mat b,Mat x)
65530b0564aSStefano Zampini {
65630b0564aSStefano Zampini   PetscFunctionBegin;
6579566063dSJacob Faibussowitsch   PetscCall(PCApply_MG_Internal(pc,NULL,NULL,b,x,PETSC_FALSE));
658fcb023d4SJed Brown   PetscFunctionReturn(0);
659fcb023d4SJed Brown }
660f3fbd535SBarry Smith 
6614416b707SBarry Smith PetscErrorCode PCSetFromOptions_MG(PetscOptionItems *PetscOptionsObject,PC pc)
662f3fbd535SBarry Smith {
663710315b6SLawrence Mitchell   PetscInt            levels,cycles;
664f3b08a26SMatthew G. Knepley   PetscBool           flg, flg2;
665f3fbd535SBarry Smith   PC_MG               *mg = (PC_MG*)pc->data;
6663d3eaba7SBarry Smith   PC_MG_Levels        **mglevels;
667f3fbd535SBarry Smith   PCMGType            mgtype;
668f3fbd535SBarry Smith   PCMGCycleType       mgctype;
6692134b1e4SBarry Smith   PCMGGalerkinType    gtype;
6702b3cbbdaSStefano Zampini   PCMGCoarseSpaceType coarseSpaceType;
671f3fbd535SBarry Smith 
672f3fbd535SBarry Smith   PetscFunctionBegin;
6731d743356SStefano Zampini   levels = PetscMax(mg->nlevels,1);
674d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"Multigrid options");
6759566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg));
6761a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
6779566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm,&levels));
678eb3f98d2SBarry Smith     levels++;
6793aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
680eb3f98d2SBarry Smith   }
6819566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc,levels,NULL));
6823aeaf226SBarry Smith   mglevels = mg->levels;
6833aeaf226SBarry Smith 
684f3fbd535SBarry Smith   mgctype = (PCMGCycleType) mglevels[0]->cycles;
6859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg));
686*1baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetCycleType(pc,mgctype));
6872134b1e4SBarry Smith   gtype = mg->galerkin;
6889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",PCMGGalerkinTypes,(PetscEnum)gtype,(PetscEnum*)&gtype,&flg));
689*1baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetGalerkin(pc,gtype));
6902b3cbbdaSStefano Zampini   coarseSpaceType = mg->coarseSpaceType;
6912b3cbbdaSStefano 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));
6922b3cbbdaSStefano Zampini   if (flg) PetscCall(PCMGSetAdaptCoarseSpaceType(pc,coarseSpaceType));
6939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_mg_adapt_interp_n","Size of the coarse space for adaptive interpolation","PCMGSetCoarseSpace",mg->Nc,&mg->Nc,&flg));
6949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_mesp_monitor","Monitor the multilevel eigensolver","PCMGSetAdaptInterpolation",PETSC_FALSE,&mg->mespMonitor,&flg));
69541b6fd38SMatthew G. Knepley   flg2 = PETSC_FALSE;
6969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_adapt_cr","Monitor coarse space quality using Compatible Relaxation (CR)","PCMGSetAdaptCR",PETSC_FALSE,&flg2,&flg));
6979566063dSJacob Faibussowitsch   if (flg) PetscCall(PCMGSetAdaptCR(pc, flg2));
698f56b1265SBarry Smith   flg = PETSC_FALSE;
6999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_distinct_smoothup","Create separate smoothup KSP and append the prefix _up","PCMGSetDistinctSmoothUp",PETSC_FALSE,&flg,NULL));
700*1baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetDistinctSmoothUp(pc));
70131567311SBarry Smith   mgtype = mg->am;
7029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg));
703*1baa6e33SBarry Smith   if (flg) PetscCall(PCMGSetType(pc,mgtype));
70431567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
7059566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGMultiplicativeSetCycles",mg->cyclesperpcapply,&cycles,&flg));
706*1baa6e33SBarry Smith     if (flg) PetscCall(PCMGMultiplicativeSetCycles(pc,cycles));
707f3fbd535SBarry Smith   }
708f3fbd535SBarry Smith   flg  = PETSC_FALSE;
7099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL));
710f3fbd535SBarry Smith   if (flg) {
711f3fbd535SBarry Smith     PetscInt i;
712f3fbd535SBarry Smith     char     eventname[128];
7131a97d7b6SStefano Zampini 
714f3fbd535SBarry Smith     levels = mglevels[0]->levels;
715f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
716f3fbd535SBarry Smith       sprintf(eventname,"MGSetup Level %d",(int)i);
7179566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup));
718f3fbd535SBarry Smith       sprintf(eventname,"MGSmooth Level %d",(int)i);
7199566063dSJacob Faibussowitsch       PetscCall(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve));
720f3fbd535SBarry Smith       if (i) {
721f3fbd535SBarry Smith         sprintf(eventname,"MGResid Level %d",(int)i);
7229566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual));
723f3fbd535SBarry Smith         sprintf(eventname,"MGInterp Level %d",(int)i);
7249566063dSJacob Faibussowitsch         PetscCall(PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict));
725f3fbd535SBarry Smith       }
726f3fbd535SBarry Smith     }
727eec35531SMatthew G Knepley 
728ec60ca73SSatish Balay #if defined(PETSC_USE_LOG)
729eec35531SMatthew G Knepley     {
730eec35531SMatthew G Knepley       const char    *sname = "MG Apply";
731eec35531SMatthew G Knepley       PetscStageLog stageLog;
732eec35531SMatthew G Knepley       PetscInt      st;
733eec35531SMatthew G Knepley 
7349566063dSJacob Faibussowitsch       PetscCall(PetscLogGetStageLog(&stageLog));
735eec35531SMatthew G Knepley       for (st = 0; st < stageLog->numStages; ++st) {
736eec35531SMatthew G Knepley         PetscBool same;
737eec35531SMatthew G Knepley 
7389566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(stageLog->stageInfo[st].name, sname, &same));
7392fa5cd67SKarl Rupp         if (same) mg->stageApply = st;
740eec35531SMatthew G Knepley       }
741eec35531SMatthew G Knepley       if (!mg->stageApply) {
7429566063dSJacob Faibussowitsch         PetscCall(PetscLogStageRegister(sname, &mg->stageApply));
743eec35531SMatthew G Knepley       }
744eec35531SMatthew G Knepley     }
745ec60ca73SSatish Balay #endif
746f3fbd535SBarry Smith   }
747d0609cedSBarry Smith   PetscOptionsHeadEnd();
748f3b08a26SMatthew G. Knepley   /* Check option consistency */
7499566063dSJacob Faibussowitsch   PetscCall(PCMGGetGalerkin(pc, &gtype));
7509566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptInterpolation(pc, &flg));
75108401ef6SPierre Jolivet   PetscCheck(!flg || !(gtype >= PC_MG_GALERKIN_NONE),PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_INCOMP, "Must use Galerkin coarse operators when adapting the interpolator");
752f3fbd535SBarry Smith   PetscFunctionReturn(0);
753f3fbd535SBarry Smith }
754f3fbd535SBarry Smith 
7550a545947SLisandro Dalcin const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",NULL};
7560a545947SLisandro Dalcin const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",NULL};
7570a545947SLisandro Dalcin const char *const PCMGGalerkinTypes[] = {"both","pmat","mat","none","external","PCMGGalerkinType","PC_MG_GALERKIN",NULL};
7582b3cbbdaSStefano Zampini const char *const PCMGCoarseSpaceTypes[] = {"none","polynomial","harmonic","eigenvector","generalized_eigenvector","gdsw","PCMGCoarseSpaceType","PCMG_ADAPT_NONE",NULL};
759f3fbd535SBarry Smith 
7609804daf3SBarry Smith #include <petscdraw.h>
761f3fbd535SBarry Smith PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
762f3fbd535SBarry Smith {
763f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
764f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
765e3deeeafSJed Brown   PetscInt       levels = mglevels ? mglevels[0]->levels : 0,i;
766219b1045SBarry Smith   PetscBool      iascii,isbinary,isdraw;
767f3fbd535SBarry Smith 
768f3fbd535SBarry Smith   PetscFunctionBegin;
7699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
7709566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary));
7719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
772f3fbd535SBarry Smith   if (iascii) {
773e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
77463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  type is %s, levels=%" PetscInt_FMT " cycles=%s\n", PCMGTypes[mg->am],levels,cyclename));
77531567311SBarry Smith     if (mg->am == PC_MG_MULTIPLICATIVE) {
77663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%" PetscInt_FMT "\n",mg->cyclesperpcapply));
777f3fbd535SBarry Smith     }
7782134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
7799566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n"));
7802134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
7819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for pmat\n"));
7822134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
7839566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for mat\n"));
7842134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
7859566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using externally compute Galerkin coarse grid matrices\n"));
7864f66f45eSBarry Smith     } else {
7879566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid matrices\n"));
788f3fbd535SBarry Smith     }
789*1baa6e33SBarry Smith     if (mg->view) PetscCall((*mg->view)(pc,viewer));
790f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
79163a3b9bcSJacob Faibussowitsch       if (i) {
79263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %" PetscInt_FMT " -------------------------------\n",i));
793f3fbd535SBarry Smith       } else {
79463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level %" PetscInt_FMT " -------------------------------\n",i));
795f3fbd535SBarry Smith       }
7969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7979566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd,viewer));
7989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
799f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
8009566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n"));
801f3fbd535SBarry Smith       } else if (i) {
80263a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %" PetscInt_FMT " -------------------------------\n",i));
8039566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8049566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu,viewer));
8059566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
806f3fbd535SBarry Smith       }
80741b6fd38SMatthew G. Knepley       if (i && mglevels[i]->cr) {
80863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"CR solver on level %" PetscInt_FMT " -------------------------------\n",i));
8099566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(viewer));
8109566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->cr,viewer));
8119566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
81241b6fd38SMatthew G. Knepley       }
813f3fbd535SBarry Smith     }
8145b0b0462SBarry Smith   } else if (isbinary) {
8155b0b0462SBarry Smith     for (i=levels-1; i>=0; i--) {
8169566063dSJacob Faibussowitsch       PetscCall(KSPView(mglevels[i]->smoothd,viewer));
8175b0b0462SBarry Smith       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) {
8189566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu,viewer));
8195b0b0462SBarry Smith       }
8205b0b0462SBarry Smith     }
821219b1045SBarry Smith   } else if (isdraw) {
822219b1045SBarry Smith     PetscDraw draw;
823b4375e8dSPeter Brune     PetscReal x,w,y,bottom,th;
8249566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
8259566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw,&x,&y));
8269566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringGetSize(draw,NULL,&th));
827219b1045SBarry Smith     bottom = y - th;
828219b1045SBarry Smith     for (i=levels-1; i>=0; i--) {
829b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
8309566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw,x,bottom));
8319566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd,viewer));
8329566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
833b4375e8dSPeter Brune       } else {
834b4375e8dSPeter Brune         w    = 0.5*PetscMin(1.0-x,x);
8359566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw,x+w,bottom));
8369566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothd,viewer));
8379566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
8389566063dSJacob Faibussowitsch         PetscCall(PetscDrawPushCurrentPoint(draw,x-w,bottom));
8399566063dSJacob Faibussowitsch         PetscCall(KSPView(mglevels[i]->smoothu,viewer));
8409566063dSJacob Faibussowitsch         PetscCall(PetscDrawPopCurrentPoint(draw));
841b4375e8dSPeter Brune       }
8429566063dSJacob Faibussowitsch       PetscCall(PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL));
8431cd381d6SBarry Smith       bottom -= th;
844219b1045SBarry Smith     }
8455b0b0462SBarry Smith   }
846f3fbd535SBarry Smith   PetscFunctionReturn(0);
847f3fbd535SBarry Smith }
848f3fbd535SBarry Smith 
849af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
850cab2e9ccSBarry Smith 
851f3fbd535SBarry Smith /*
852f3fbd535SBarry Smith     Calls setup for the KSP on each level
853f3fbd535SBarry Smith */
854f3fbd535SBarry Smith PetscErrorCode PCSetUp_MG(PC pc)
855f3fbd535SBarry Smith {
856f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
857f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
8581a97d7b6SStefano Zampini   PetscInt     i,n;
85998e04984SBarry Smith   PC           cpc;
8603db492dfSBarry Smith   PetscBool    dump = PETSC_FALSE,opsset,use_amat,missinginterpolate = PETSC_FALSE;
861f3fbd535SBarry Smith   Mat          dA,dB;
862f3fbd535SBarry Smith   Vec          tvec;
863218a07d4SBarry Smith   DM           *dms;
8640a545947SLisandro Dalcin   PetscViewer  viewer = NULL;
86541b6fd38SMatthew G. Knepley   PetscBool    dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE, doCR = PETSC_FALSE;
8662b3cbbdaSStefano Zampini   PetscBool    adaptInterpolation = mg->adaptInterpolation;
867f3fbd535SBarry Smith 
868f3fbd535SBarry Smith   PetscFunctionBegin;
86928b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels with PCMGSetLevels() before setting up");
8701a97d7b6SStefano Zampini   n = mglevels[0]->levels;
87101bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
8723aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
8733aeaf226SBarry Smith     PetscInt levels;
8749566063dSJacob Faibussowitsch     PetscCall(DMGetRefineLevel(pc->dm,&levels));
8753aeaf226SBarry Smith     levels++;
8763aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
8779566063dSJacob Faibussowitsch       PetscCall(PCMGSetLevels(pc,levels,NULL));
8783aeaf226SBarry Smith       n        = levels;
8799566063dSJacob Faibussowitsch       PetscCall(PCSetFromOptions(pc)); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
8803aeaf226SBarry Smith       mglevels = mg->levels;
8813aeaf226SBarry Smith     }
8823aeaf226SBarry Smith   }
8839566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(mglevels[0]->smoothd,&cpc));
8843aeaf226SBarry Smith 
885f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
886f3fbd535SBarry Smith   /* so use those from global PC */
887f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
8889566063dSJacob Faibussowitsch   PetscCall(KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset));
88998e04984SBarry Smith   if (opsset) {
89098e04984SBarry Smith     Mat mmat;
8919566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat));
89298e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
89398e04984SBarry Smith   }
8944a5f07a5SMark F. Adams 
89541b6fd38SMatthew G. Knepley   /* Create CR solvers */
8969566063dSJacob Faibussowitsch   PetscCall(PCMGGetAdaptCR(pc, &doCR));
89741b6fd38SMatthew G. Knepley   if (doCR) {
89841b6fd38SMatthew G. Knepley     const char *prefix;
89941b6fd38SMatthew G. Knepley 
9009566063dSJacob Faibussowitsch     PetscCall(PCGetOptionsPrefix(pc, &prefix));
90141b6fd38SMatthew G. Knepley     for (i = 1; i < n; ++i) {
90241b6fd38SMatthew G. Knepley       PC   ipc, cr;
90341b6fd38SMatthew G. Knepley       char crprefix[128];
90441b6fd38SMatthew G. Knepley 
9059566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject) pc), &mglevels[i]->cr));
9069566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(mglevels[i]->cr, PETSC_FALSE));
9079566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject) mglevels[i]->cr, (PetscObject) pc, n-i));
9089566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(mglevels[i]->cr, prefix));
9099566063dSJacob Faibussowitsch       PetscCall(PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->cr, PetscMGLevelId, mglevels[i]->level));
9109566063dSJacob Faibussowitsch       PetscCall(KSPSetType(mglevels[i]->cr, KSPCHEBYSHEV));
9119566063dSJacob Faibussowitsch       PetscCall(KSPSetConvergenceTest(mglevels[i]->cr, KSPConvergedSkip, NULL, NULL));
9129566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(mglevels[i]->cr, KSP_NORM_PRECONDITIONED));
9139566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->cr, &ipc));
91441b6fd38SMatthew G. Knepley 
9159566063dSJacob Faibussowitsch       PetscCall(PCSetType(ipc, PCCOMPOSITE));
9169566063dSJacob Faibussowitsch       PetscCall(PCCompositeSetType(ipc, PC_COMPOSITE_MULTIPLICATIVE));
9179566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(ipc, PCSOR));
9189566063dSJacob Faibussowitsch       PetscCall(CreateCR_Private(pc, i, &cr));
9199566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPC(ipc, cr));
9209566063dSJacob Faibussowitsch       PetscCall(PCDestroy(&cr));
92141b6fd38SMatthew G. Knepley 
9229566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(mglevels[i]->cr, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, mg->default_smoothd));
9239566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr, PETSC_TRUE));
9249566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(crprefix, 128, "mg_levels_%d_cr_", (int) i));
9259566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(mglevels[i]->cr, crprefix));
9269566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject) pc, (PetscObject) mglevels[i]->cr));
92741b6fd38SMatthew G. Knepley     }
92841b6fd38SMatthew G. Knepley   }
92941b6fd38SMatthew G. Knepley 
9304a5f07a5SMark F. Adams   if (!opsset) {
9319566063dSJacob Faibussowitsch     PetscCall(PCGetUseAmat(pc,&use_amat));
9324a5f07a5SMark F. Adams     if (use_amat) {
9339566063dSJacob 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"));
9349566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat));
93569858f1bSStefano Zampini     } else {
9369566063dSJacob 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"));
9379566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat));
9384a5f07a5SMark F. Adams     }
9394a5f07a5SMark F. Adams   }
940f3fbd535SBarry Smith 
9419c7ffb39SBarry Smith   for (i=n-1; i>0; i--) {
9429c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
9439c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
9442b3cbbdaSStefano Zampini       break;
9459c7ffb39SBarry Smith     }
9469c7ffb39SBarry Smith   }
9472134b1e4SBarry Smith 
9489566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB));
9492134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
9502b3cbbdaSStefano Zampini   if (mg->galerkin == PC_MG_GALERKIN_NONE || ((mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_MAT) && !dAeqdB)) {
9512134b1e4SBarry Smith     needRestricts = PETSC_TRUE;  /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
9522134b1e4SBarry Smith   }
9532134b1e4SBarry Smith 
9542b3cbbdaSStefano Zampini   if (pc->dm && !pc->setupcalled) {
9552b3cbbdaSStefano Zampini     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
9562b3cbbdaSStefano Zampini     PetscCall(KSPSetDM(mglevels[n-1]->smoothd,pc->dm));
9572b3cbbdaSStefano Zampini     PetscCall(KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE));
9582b3cbbdaSStefano Zampini     if (mglevels[n-1]->smoothd != mglevels[n-1]->smoothu) {
9592b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n-1]->smoothu,pc->dm));
9602b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n-1]->smoothu,PETSC_FALSE));
9612b3cbbdaSStefano Zampini     }
9622b3cbbdaSStefano Zampini     if (mglevels[n-1]->cr) {
9632b3cbbdaSStefano Zampini       PetscCall(KSPSetDM(mglevels[n-1]->cr,pc->dm));
9642b3cbbdaSStefano Zampini       PetscCall(KSPSetDMActive(mglevels[n-1]->cr,PETSC_FALSE));
9652b3cbbdaSStefano Zampini     }
9662b3cbbdaSStefano Zampini   }
9672b3cbbdaSStefano Zampini 
9689c7ffb39SBarry Smith   /*
9699c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
9702b3cbbdaSStefano Zampini    Skipping for externally managed hierarchy (such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
9719c7ffb39SBarry Smith   */
97232fe681dSStefano Zampini   if (missinginterpolate && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
97332fe681dSStefano Zampini     /* first see if we can compute a coarse space */
97432fe681dSStefano Zampini     if (mg->coarseSpaceType == PCMG_ADAPT_GDSW) {
97532fe681dSStefano Zampini       for (i=n-2; i>-1; i--) {
97632fe681dSStefano Zampini         if (!mglevels[i+1]->restrct && !mglevels[i+1]->interpolate) {
97732fe681dSStefano Zampini           PetscCall(PCMGComputeCoarseSpace_Internal(pc, i+1, mg->coarseSpaceType, mg->Nc, NULL, &mglevels[i+1]->coarseSpace));
97832fe681dSStefano Zampini           PetscCall(PCMGSetInterpolation(pc,i+1,mglevels[i+1]->coarseSpace));
97932fe681dSStefano Zampini         }
98032fe681dSStefano Zampini       }
98132fe681dSStefano Zampini     } else { /* construct the interpolation from the DMs */
9822e499ae9SBarry Smith       Mat p;
98373250ac0SBarry Smith       Vec rscale;
9849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(n,&dms));
985218a07d4SBarry Smith       dms[n-1] = pc->dm;
986ef1267afSMatthew G. Knepley       /* Separately create them so we do not get DMKSP interference between levels */
9879566063dSJacob Faibussowitsch       for (i=n-2; i>-1; i--) PetscCall(DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]));
988218a07d4SBarry Smith       for (i=n-2; i>-1; i--) {
989942e3340SBarry Smith         DMKSP     kdm;
990eab52d2bSLawrence Mitchell         PetscBool dmhasrestrict, dmhasinject;
9919566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(mglevels[i]->smoothd,dms[i]));
9929566063dSJacob Faibussowitsch         if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE));
993c27ee7a3SPatrick Farrell         if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
9949566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->smoothu,dms[i]));
9959566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->smoothu,PETSC_FALSE));
996c27ee7a3SPatrick Farrell         }
99741b6fd38SMatthew G. Knepley         if (mglevels[i]->cr) {
9989566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(mglevels[i]->cr,dms[i]));
9999566063dSJacob Faibussowitsch           if (!needRestricts) PetscCall(KSPSetDMActive(mglevels[i]->cr,PETSC_FALSE));
100041b6fd38SMatthew G. Knepley         }
10019566063dSJacob Faibussowitsch         PetscCall(DMGetDMKSPWrite(dms[i],&kdm));
1002d1a3e677SJed Brown         /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
1003d1a3e677SJed Brown          * a bitwise OR of computing the matrix, RHS, and initial iterate. */
10040298fd71SBarry Smith         kdm->ops->computerhs = NULL;
10050298fd71SBarry Smith         kdm->rhsctx          = NULL;
100624c3aa18SBarry Smith         if (!mglevels[i+1]->interpolate) {
10079566063dSJacob Faibussowitsch           PetscCall(DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale));
10089566063dSJacob Faibussowitsch           PetscCall(PCMGSetInterpolation(pc,i+1,p));
10099566063dSJacob Faibussowitsch           if (rscale) PetscCall(PCMGSetRScale(pc,i+1,rscale));
10109566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&rscale));
10119566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1012218a07d4SBarry Smith         }
10139566063dSJacob Faibussowitsch         PetscCall(DMHasCreateRestriction(dms[i],&dmhasrestrict));
10143ad4599aSBarry Smith         if (dmhasrestrict && !mglevels[i+1]->restrct) {
10159566063dSJacob Faibussowitsch           PetscCall(DMCreateRestriction(dms[i],dms[i+1],&p));
10169566063dSJacob Faibussowitsch           PetscCall(PCMGSetRestriction(pc,i+1,p));
10179566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
10183ad4599aSBarry Smith         }
10199566063dSJacob Faibussowitsch         PetscCall(DMHasCreateInjection(dms[i],&dmhasinject));
1020eab52d2bSLawrence Mitchell         if (dmhasinject && !mglevels[i+1]->inject) {
10219566063dSJacob Faibussowitsch           PetscCall(DMCreateInjection(dms[i],dms[i+1],&p));
10229566063dSJacob Faibussowitsch           PetscCall(PCMGSetInjection(pc,i+1,p));
10239566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&p));
1024eab52d2bSLawrence Mitchell         }
102524c3aa18SBarry Smith       }
10262d2b81a6SBarry Smith 
10279566063dSJacob Faibussowitsch       for (i=n-2; i>-1; i--) PetscCall(DMDestroy(&dms[i]));
10289566063dSJacob Faibussowitsch       PetscCall(PetscFree(dms));
1029ce4cda84SJed Brown     }
103032fe681dSStefano Zampini   }
1031cab2e9ccSBarry Smith 
10322134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
10332134b1e4SBarry Smith     Mat       A,B;
10342134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE,doB = PETSC_FALSE;
10352134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
10362134b1e4SBarry Smith 
10372b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_PMAT || mg->galerkin == PC_MG_GALERKIN_BOTH) doB = PETSC_TRUE;
10382b3cbbdaSStefano Zampini     if (mg->galerkin == PC_MG_GALERKIN_MAT || (mg->galerkin == PC_MG_GALERKIN_BOTH && dA != dB)) doA = PETSC_TRUE;
10392134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
1040f3fbd535SBarry Smith     for (i=n-2; i>-1; i--) {
10417827d75bSBarry 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");
1042b9367914SBarry Smith       if (!mglevels[i+1]->interpolate) {
10439566063dSJacob Faibussowitsch         PetscCall(PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct));
1044b9367914SBarry Smith       }
1045b9367914SBarry Smith       if (!mglevels[i+1]->restrct) {
10469566063dSJacob Faibussowitsch         PetscCall(PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate));
1047b9367914SBarry Smith       }
10482134b1e4SBarry Smith       if (reuse == MAT_REUSE_MATRIX) {
10499566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd,&A,&B));
10502134b1e4SBarry Smith       }
10512134b1e4SBarry Smith       if (doA) {
10529566063dSJacob Faibussowitsch         PetscCall(MatGalerkin(mglevels[i+1]->restrct,dA,mglevels[i+1]->interpolate,reuse,1.0,&A));
10532134b1e4SBarry Smith       }
10542134b1e4SBarry Smith       if (doB) {
10559566063dSJacob Faibussowitsch         PetscCall(MatGalerkin(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,reuse,1.0,&B));
1056b9367914SBarry Smith       }
10572134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
10582134b1e4SBarry Smith       if (!doA && dAeqdB) {
10599566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)B));
10602134b1e4SBarry Smith         A = B;
10612134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX) {
10629566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd,&A,NULL));
10639566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)A));
1064b9367914SBarry Smith       }
10652134b1e4SBarry Smith       if (!doB && dAeqdB) {
10669566063dSJacob Faibussowitsch         if (reuse == MAT_INITIAL_MATRIX) PetscCall(PetscObjectReference((PetscObject)A));
10672134b1e4SBarry Smith         B = A;
10682134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
10699566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd,NULL,&B));
10709566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)B));
10717d537d92SJed Brown       }
10722134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
10739566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothd,A,B));
10749566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)A));
10759566063dSJacob Faibussowitsch         PetscCall(PetscObjectDereference((PetscObject)B));
10762134b1e4SBarry Smith       }
10772134b1e4SBarry Smith       dA = A;
1078f3fbd535SBarry Smith       dB = B;
1079f3fbd535SBarry Smith     }
1080f3fbd535SBarry Smith   }
1081f3b08a26SMatthew G. Knepley 
1082f3b08a26SMatthew G. Knepley   /* Adapt interpolation matrices */
10832b3cbbdaSStefano Zampini   if (adaptInterpolation) {
1084f3b08a26SMatthew G. Knepley     for (i = 0; i < n; ++i) {
10852b3cbbdaSStefano Zampini       if (!mglevels[i]->coarseSpace) {
10869566063dSJacob Faibussowitsch         PetscCall(PCMGComputeCoarseSpace_Internal(pc, i, mg->coarseSpaceType, mg->Nc, !i ? NULL : mglevels[i-1]->coarseSpace, &mglevels[i]->coarseSpace));
10872b3cbbdaSStefano Zampini       }
10882b3cbbdaSStefano Zampini       if (i) PetscCall(PCMGAdaptInterpolator_Internal(pc, i, mglevels[i-1]->smoothu, mglevels[i]->smoothu, mglevels[i-1]->coarseSpace, mglevels[i]->coarseSpace));
1089f3b08a26SMatthew G. Knepley     }
1090f3b08a26SMatthew G. Knepley     for (i = n-2; i > -1; --i) {
10919566063dSJacob Faibussowitsch       PetscCall(PCMGRecomputeLevelOperators_Internal(pc, i));
1092f3b08a26SMatthew G. Knepley     }
1093f3b08a26SMatthew G. Knepley   }
1094f3b08a26SMatthew G. Knepley 
10952134b1e4SBarry Smith   if (needRestricts && pc->dm) {
1096caa4e7f2SJed Brown     for (i=n-2; i>=0; i--) {
1097ccceb50cSJed Brown       DM  dmfine,dmcoarse;
1098caa4e7f2SJed Brown       Mat Restrict,Inject;
1099caa4e7f2SJed Brown       Vec rscale;
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) {
1110f3fbd535SBarry Smith     for (i=0; i<n; i++) {
11119566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(mglevels[i]->smoothd));
1112f3fbd535SBarry Smith     }
1113f3fbd535SBarry Smith     for (i=1; i<n; i++) {
1114f3fbd535SBarry Smith       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
11159566063dSJacob Faibussowitsch         PetscCall(KSPSetFromOptions(mglevels[i]->smoothu));
1116f3fbd535SBarry Smith       }
111741b6fd38SMatthew G. Knepley       if (mglevels[i]->cr) {
11189566063dSJacob Faibussowitsch         PetscCall(KSPSetFromOptions(mglevels[i]->cr));
111941b6fd38SMatthew G. Knepley       }
1120f3fbd535SBarry Smith     }
11213ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
1122f3fbd535SBarry Smith     for (i=1; i<n; i++) {
11239566063dSJacob Faibussowitsch       PetscCall(PCMGGetInterpolation(pc,i,NULL));
11249566063dSJacob Faibussowitsch       PetscCall(PCMGGetRestriction(pc,i,NULL));
1125f3fbd535SBarry Smith     }
1126f3fbd535SBarry Smith     for (i=0; i<n-1; i++) {
1127f3fbd535SBarry Smith       if (!mglevels[i]->b) {
1128f3fbd535SBarry Smith         Vec *vec;
11299566063dSJacob Faibussowitsch         PetscCall(KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL));
11309566063dSJacob Faibussowitsch         PetscCall(PCMGSetRhs(pc,i,*vec));
11319566063dSJacob Faibussowitsch         PetscCall(VecDestroy(vec));
11329566063dSJacob Faibussowitsch         PetscCall(PetscFree(vec));
1133f3fbd535SBarry Smith       }
1134f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
11359566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b,&tvec));
11369566063dSJacob Faibussowitsch         PetscCall(PCMGSetR(pc,i,tvec));
11379566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1138f3fbd535SBarry Smith       }
1139f3fbd535SBarry Smith       if (!mglevels[i]->x) {
11409566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b,&tvec));
11419566063dSJacob Faibussowitsch         PetscCall(PCMGSetX(pc,i,tvec));
11429566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&tvec));
1143f3fbd535SBarry Smith       }
114441b6fd38SMatthew G. Knepley       if (doCR) {
11459566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b,&mglevels[i]->crx));
11469566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(mglevels[i]->b,&mglevels[i]->crb));
11479566063dSJacob Faibussowitsch         PetscCall(VecZeroEntries(mglevels[i]->crb));
114841b6fd38SMatthew G. Knepley       }
1149f3fbd535SBarry Smith     }
1150f3fbd535SBarry Smith     if (n != 1 && !mglevels[n-1]->r) {
1151f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
1152f3fbd535SBarry Smith       Vec *vec;
11539566063dSJacob Faibussowitsch       PetscCall(KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL));
11549566063dSJacob Faibussowitsch       PetscCall(PCMGSetR(pc,n-1,*vec));
11559566063dSJacob Faibussowitsch       PetscCall(VecDestroy(vec));
11569566063dSJacob Faibussowitsch       PetscCall(PetscFree(vec));
1157f3fbd535SBarry Smith     }
115841b6fd38SMatthew G. Knepley     if (doCR) {
11599566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n-1]->r, &mglevels[n-1]->crx));
11609566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(mglevels[n-1]->r, &mglevels[n-1]->crb));
11619566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(mglevels[n-1]->crb));
116241b6fd38SMatthew G. Knepley     }
1163f3fbd535SBarry Smith   }
1164f3fbd535SBarry Smith 
116598e04984SBarry Smith   if (pc->dm) {
116698e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
116798e04984SBarry Smith     for (i=0; i<n-1; i++) {
116898e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
116998e04984SBarry Smith     }
117098e04984SBarry Smith   }
117108549ed4SJed Brown   // We got here (PCSetUp_MG) because the matrix has changed, which means the smoother needs to be set up again (e.g.,
117208549ed4SJed Brown   // new diagonal for Jacobi). Setting it here allows it to be logged under PCSetUp rather than deep inside a PCApply.
117308549ed4SJed Brown   if (mglevels[n-1]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[n-1]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
1174f3fbd535SBarry Smith 
1175f3fbd535SBarry Smith   for (i=1; i<n; i++) {
11762a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1) {
1177f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
11789566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE));
1179f3fbd535SBarry Smith     }
11809566063dSJacob Faibussowitsch     if (mglevels[i]->cr) PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr,PETSC_TRUE));
11819566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0));
11829566063dSJacob Faibussowitsch     PetscCall(KSPSetUp(mglevels[i]->smoothd));
1183c0decd05SBarry Smith     if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PC_FAILED) {
1184899639b0SHong Zhang       pc->failedreason = PC_SUBPC_ERROR;
1185899639b0SHong Zhang     }
11869566063dSJacob Faibussowitsch     if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0));
1187d42688cbSBarry Smith     if (!mglevels[i]->residual) {
1188d42688cbSBarry Smith       Mat mat;
11899566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd,&mat,NULL));
11909566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidual(pc,i,PCMGResidualDefault,mat));
1191d42688cbSBarry Smith     }
1192fcb023d4SJed Brown     if (!mglevels[i]->residualtranspose) {
1193fcb023d4SJed Brown       Mat mat;
11949566063dSJacob Faibussowitsch       PetscCall(KSPGetOperators(mglevels[i]->smoothd,&mat,NULL));
11959566063dSJacob Faibussowitsch       PetscCall(PCMGSetResidualTranspose(pc,i,PCMGResidualTransposeDefault,mat));
1196fcb023d4SJed Brown     }
1197f3fbd535SBarry Smith   }
1198f3fbd535SBarry Smith   for (i=1; i<n; i++) {
1199f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
1200f3fbd535SBarry Smith       Mat downmat,downpmat;
1201f3fbd535SBarry Smith 
1202f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
12039566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL));
1204f3fbd535SBarry Smith       if (!opsset) {
12059566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat));
12069566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat));
1207f3fbd535SBarry Smith       }
1208f3fbd535SBarry Smith 
12099566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE));
12109566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0));
12119566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->smoothu));
1212c0decd05SBarry Smith       if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PC_FAILED) {
1213899639b0SHong Zhang         pc->failedreason = PC_SUBPC_ERROR;
1214899639b0SHong Zhang       }
12159566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0));
1216f3fbd535SBarry Smith     }
121741b6fd38SMatthew G. Knepley     if (mglevels[i]->cr) {
121841b6fd38SMatthew G. Knepley       Mat downmat,downpmat;
121941b6fd38SMatthew G. Knepley 
122041b6fd38SMatthew G. Knepley       /* check if operators have been set for up, if not use down operators to set them */
12219566063dSJacob Faibussowitsch       PetscCall(KSPGetOperatorsSet(mglevels[i]->cr,&opsset,NULL));
122241b6fd38SMatthew G. Knepley       if (!opsset) {
12239566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat));
12249566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[i]->cr,downmat,downpmat));
122541b6fd38SMatthew G. Knepley       }
122641b6fd38SMatthew G. Knepley 
12279566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(mglevels[i]->cr,PETSC_TRUE));
12289566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0));
12299566063dSJacob Faibussowitsch       PetscCall(KSPSetUp(mglevels[i]->cr));
123041b6fd38SMatthew G. Knepley       if (mglevels[i]->cr->reason == KSP_DIVERGED_PC_FAILED) {
123141b6fd38SMatthew G. Knepley         pc->failedreason = PC_SUBPC_ERROR;
123241b6fd38SMatthew G. Knepley       }
12339566063dSJacob Faibussowitsch       if (mglevels[i]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0));
123441b6fd38SMatthew G. Knepley     }
1235f3fbd535SBarry Smith   }
1236f3fbd535SBarry Smith 
12379566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0));
12389566063dSJacob Faibussowitsch   PetscCall(KSPSetUp(mglevels[0]->smoothd));
1239c0decd05SBarry Smith   if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PC_FAILED) {
1240899639b0SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
1241899639b0SHong Zhang   }
12429566063dSJacob Faibussowitsch   if (mglevels[0]->eventsmoothsetup) PetscCall(PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0));
1243f3fbd535SBarry Smith 
1244f3fbd535SBarry Smith   /*
1245f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
1246e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
1247f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
1248f3fbd535SBarry Smith 
1249f3fbd535SBarry Smith    Only support one or the other at the same time.
1250f3fbd535SBarry Smith   */
1251f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
12529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL));
1253ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
1254f3fbd535SBarry Smith   dump = PETSC_FALSE;
1255f3fbd535SBarry Smith #endif
12569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL));
1257ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
1258f3fbd535SBarry Smith 
1259f3fbd535SBarry Smith   if (viewer) {
1260f3fbd535SBarry Smith     for (i=1; i<n; i++) {
12619566063dSJacob Faibussowitsch       PetscCall(MatView(mglevels[i]->restrct,viewer));
1262f3fbd535SBarry Smith     }
1263f3fbd535SBarry Smith     for (i=0; i<n; i++) {
12649566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(mglevels[i]->smoothd,&pc));
12659566063dSJacob Faibussowitsch       PetscCall(MatView(pc->mat,viewer));
1266f3fbd535SBarry Smith     }
1267f3fbd535SBarry Smith   }
1268f3fbd535SBarry Smith   PetscFunctionReturn(0);
1269f3fbd535SBarry Smith }
1270f3fbd535SBarry Smith 
1271f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
1272f3fbd535SBarry Smith 
127397d33e41SMatthew G. Knepley PetscErrorCode PCMGGetLevels_MG(PC pc, PetscInt *levels)
127497d33e41SMatthew G. Knepley {
127597d33e41SMatthew G. Knepley   PC_MG *mg = (PC_MG *) pc->data;
127697d33e41SMatthew G. Knepley 
127797d33e41SMatthew G. Knepley   PetscFunctionBegin;
127897d33e41SMatthew G. Knepley   *levels = mg->nlevels;
127997d33e41SMatthew G. Knepley   PetscFunctionReturn(0);
128097d33e41SMatthew G. Knepley }
128197d33e41SMatthew G. Knepley 
12824b9ad928SBarry Smith /*@
128397177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
12844b9ad928SBarry Smith 
12854b9ad928SBarry Smith    Not Collective
12864b9ad928SBarry Smith 
12874b9ad928SBarry Smith    Input Parameter:
12884b9ad928SBarry Smith .  pc - the preconditioner context
12894b9ad928SBarry Smith 
12904b9ad928SBarry Smith    Output parameter:
12914b9ad928SBarry Smith .  levels - the number of levels
12924b9ad928SBarry Smith 
12934b9ad928SBarry Smith    Level: advanced
12944b9ad928SBarry Smith 
1295db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
12964b9ad928SBarry Smith @*/
12977087cfbeSBarry Smith PetscErrorCode PCMGGetLevels(PC pc,PetscInt *levels)
12984b9ad928SBarry Smith {
12994b9ad928SBarry Smith   PetscFunctionBegin;
13000700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
13014482741eSBarry Smith   PetscValidIntPointer(levels,2);
130297d33e41SMatthew G. Knepley   *levels = 0;
1303cac4c232SBarry Smith   PetscTryMethod(pc,"PCMGGetLevels_C",(PC,PetscInt*),(pc,levels));
13044b9ad928SBarry Smith   PetscFunctionReturn(0);
13054b9ad928SBarry Smith }
13064b9ad928SBarry Smith 
13074b9ad928SBarry Smith /*@
1308e7d4b4cbSMark Adams    PCMGGetGridComplexity - compute operator and grid complexity of MG hierarchy
1309e7d4b4cbSMark Adams 
1310e7d4b4cbSMark Adams    Input Parameter:
1311e7d4b4cbSMark Adams .  pc - the preconditioner context
1312e7d4b4cbSMark Adams 
131390db8557SMark Adams    Output Parameters:
131490db8557SMark Adams +  gc - grid complexity = sum_i(n_i) / n_0
131590db8557SMark Adams -  oc - operator complexity = sum_i(nnz_i) / nnz_0
1316e7d4b4cbSMark Adams 
1317e7d4b4cbSMark Adams    Level: advanced
1318e7d4b4cbSMark Adams 
1319db781477SPatrick Sanan .seealso: `PCMGGetLevels()`
1320e7d4b4cbSMark Adams @*/
1321e7d4b4cbSMark Adams PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc, PetscReal *oc)
1322e7d4b4cbSMark Adams {
1323e7d4b4cbSMark Adams   PC_MG          *mg      = (PC_MG*)pc->data;
1324e7d4b4cbSMark Adams   PC_MG_Levels   **mglevels = mg->levels;
1325e7d4b4cbSMark Adams   PetscInt       lev,N;
1326e7d4b4cbSMark Adams   PetscLogDouble nnz0 = 0, sgc = 0, soc = 0, n0 = 0;
1327e7d4b4cbSMark Adams   MatInfo        info;
1328e7d4b4cbSMark Adams 
1329e7d4b4cbSMark Adams   PetscFunctionBegin;
133090db8557SMark Adams   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
133190db8557SMark Adams   if (gc) PetscValidRealPointer(gc,2);
133290db8557SMark Adams   if (oc) PetscValidRealPointer(oc,3);
1333e7d4b4cbSMark Adams   if (!pc->setupcalled) {
133490db8557SMark Adams     if (gc) *gc = 0;
133590db8557SMark Adams     if (oc) *oc = 0;
1336e7d4b4cbSMark Adams     PetscFunctionReturn(0);
1337e7d4b4cbSMark Adams   }
1338e7d4b4cbSMark Adams   PetscCheck(mg->nlevels > 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"MG has no levels");
1339e7d4b4cbSMark Adams   for (lev=0; lev<mg->nlevels; lev++) {
1340e7d4b4cbSMark Adams     Mat dB;
13419566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[lev]->smoothd,NULL,&dB));
13429566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(dB,MAT_GLOBAL_SUM,&info)); /* global reduction */
13439566063dSJacob Faibussowitsch     PetscCall(MatGetSize(dB,&N,NULL));
1344e7d4b4cbSMark Adams     sgc += N;
1345e7d4b4cbSMark Adams     soc += info.nz_used;
1346e7d4b4cbSMark Adams     if (lev==mg->nlevels-1) {nnz0 = info.nz_used; n0 = N;}
1347e7d4b4cbSMark Adams   }
134890db8557SMark Adams   if (n0 > 0 && gc) *gc = (PetscReal)(sgc/n0);
1349e7d4b4cbSMark Adams   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number for grid points on finest level is not available");
135090db8557SMark Adams   if (nnz0 > 0 && oc) *oc = (PetscReal)(soc/nnz0);
1351e7d4b4cbSMark Adams   PetscFunctionReturn(0);
1352e7d4b4cbSMark Adams }
1353e7d4b4cbSMark Adams 
1354e7d4b4cbSMark Adams /*@
135597177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
13564b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
13574b9ad928SBarry Smith 
1358ad4df100SBarry Smith    Logically Collective on PC
13594b9ad928SBarry Smith 
13604b9ad928SBarry Smith    Input Parameters:
13614b9ad928SBarry Smith +  pc - the preconditioner context
13629dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
13639dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
13644b9ad928SBarry Smith 
13654b9ad928SBarry Smith    Options Database Key:
13664b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
13674b9ad928SBarry Smith    additive, full, kaskade
13684b9ad928SBarry Smith 
13694b9ad928SBarry Smith    Level: advanced
13704b9ad928SBarry Smith 
1371db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
13724b9ad928SBarry Smith @*/
13737087cfbeSBarry Smith PetscErrorCode  PCMGSetType(PC pc,PCMGType form)
13744b9ad928SBarry Smith {
1375f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
13764b9ad928SBarry Smith 
13774b9ad928SBarry Smith   PetscFunctionBegin;
13780700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1379c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,form,2);
138031567311SBarry Smith   mg->am = form;
13819dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
1382c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
1383c60c7ad4SBarry Smith   PetscFunctionReturn(0);
1384c60c7ad4SBarry Smith }
1385c60c7ad4SBarry Smith 
1386c60c7ad4SBarry Smith /*@
1387c60c7ad4SBarry Smith    PCMGGetType - Determines the form of multigrid to use:
1388c60c7ad4SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
1389c60c7ad4SBarry Smith 
1390c60c7ad4SBarry Smith    Logically Collective on PC
1391c60c7ad4SBarry Smith 
1392c60c7ad4SBarry Smith    Input Parameter:
1393c60c7ad4SBarry Smith .  pc - the preconditioner context
1394c60c7ad4SBarry Smith 
1395c60c7ad4SBarry Smith    Output Parameter:
1396c60c7ad4SBarry Smith .  type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE
1397c60c7ad4SBarry Smith 
1398c60c7ad4SBarry Smith    Level: advanced
1399c60c7ad4SBarry Smith 
1400db781477SPatrick Sanan .seealso: `PCMGSetLevels()`
1401c60c7ad4SBarry Smith @*/
1402c60c7ad4SBarry Smith PetscErrorCode  PCMGGetType(PC pc,PCMGType *type)
1403c60c7ad4SBarry Smith {
1404c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
1405c60c7ad4SBarry Smith 
1406c60c7ad4SBarry Smith   PetscFunctionBegin;
1407c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1408c60c7ad4SBarry Smith   *type = mg->am;
14094b9ad928SBarry Smith   PetscFunctionReturn(0);
14104b9ad928SBarry Smith }
14114b9ad928SBarry Smith 
14124b9ad928SBarry Smith /*@
14130d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
14144b9ad928SBarry Smith    complicated cycling.
14154b9ad928SBarry Smith 
1416ad4df100SBarry Smith    Logically Collective on PC
14174b9ad928SBarry Smith 
14184b9ad928SBarry Smith    Input Parameters:
1419c2be2410SBarry Smith +  pc - the multigrid context
1420c1cbb1deSBarry Smith -  n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W
14214b9ad928SBarry Smith 
14224b9ad928SBarry Smith    Options Database Key:
1423c1cbb1deSBarry Smith .  -pc_mg_cycle_type <v,w> - provide the cycle desired
14244b9ad928SBarry Smith 
14254b9ad928SBarry Smith    Level: advanced
14264b9ad928SBarry Smith 
1427db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()`
14284b9ad928SBarry Smith @*/
14297087cfbeSBarry Smith PetscErrorCode  PCMGSetCycleType(PC pc,PCMGCycleType n)
14304b9ad928SBarry Smith {
1431f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
1432f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
143379416396SBarry Smith   PetscInt     i,levels;
14344b9ad928SBarry Smith 
14354b9ad928SBarry Smith   PetscFunctionBegin;
14360700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
143769fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc,n,2);
143828b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
1439f3fbd535SBarry Smith   levels = mglevels[0]->levels;
14402fa5cd67SKarl Rupp   for (i=0; i<levels; i++) mglevels[i]->cycles = n;
14414b9ad928SBarry Smith   PetscFunctionReturn(0);
14424b9ad928SBarry Smith }
14434b9ad928SBarry Smith 
14448cc2d5dfSBarry Smith /*@
14458cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
14468cc2d5dfSBarry Smith          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
14478cc2d5dfSBarry Smith 
1448ad4df100SBarry Smith    Logically Collective on PC
14498cc2d5dfSBarry Smith 
14508cc2d5dfSBarry Smith    Input Parameters:
14518cc2d5dfSBarry Smith +  pc - the multigrid context
14528cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
14538cc2d5dfSBarry Smith 
14548cc2d5dfSBarry Smith    Options Database Key:
1455147403d9SBarry Smith .  -pc_mg_multiplicative_cycles n - set the number of cycles
14568cc2d5dfSBarry Smith 
14578cc2d5dfSBarry Smith    Level: advanced
14588cc2d5dfSBarry Smith 
145995452b02SPatrick Sanan    Notes:
146095452b02SPatrick Sanan     This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
14618cc2d5dfSBarry Smith 
1462db781477SPatrick Sanan .seealso: `PCMGSetCycleTypeOnLevel()`, `PCMGSetCycleType()`
14638cc2d5dfSBarry Smith @*/
14647087cfbeSBarry Smith PetscErrorCode  PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
14658cc2d5dfSBarry Smith {
1466f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
14678cc2d5dfSBarry Smith 
14688cc2d5dfSBarry Smith   PetscFunctionBegin;
14690700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1470c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
14712a21e185SBarry Smith   mg->cyclesperpcapply = n;
14728cc2d5dfSBarry Smith   PetscFunctionReturn(0);
14738cc2d5dfSBarry Smith }
14748cc2d5dfSBarry Smith 
14752134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use)
1476fb15c04eSBarry Smith {
1477fb15c04eSBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
1478fb15c04eSBarry Smith 
1479fb15c04eSBarry Smith   PetscFunctionBegin;
14802134b1e4SBarry Smith   mg->galerkin = use;
1481fb15c04eSBarry Smith   PetscFunctionReturn(0);
1482fb15c04eSBarry Smith }
1483fb15c04eSBarry Smith 
1484c2be2410SBarry Smith /*@
148597177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
148682b87d87SMatthew G. Knepley       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1487c2be2410SBarry Smith 
1488ad4df100SBarry Smith    Logically Collective on PC
1489c2be2410SBarry Smith 
1490c2be2410SBarry Smith    Input Parameters:
1491c91913d3SJed Brown +  pc - the multigrid context
14922134b1e4SBarry Smith -  use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE
1493c2be2410SBarry Smith 
1494c2be2410SBarry Smith    Options Database Key:
1495147403d9SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - set the matrices to form via the Galerkin process
1496c2be2410SBarry Smith 
1497c2be2410SBarry Smith    Level: intermediate
1498c2be2410SBarry Smith 
149995452b02SPatrick Sanan    Notes:
150095452b02SPatrick Sanan     Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not
15011c1aac46SBarry Smith      use the PCMG construction of the coarser grids.
15021c1aac46SBarry Smith 
1503db781477SPatrick Sanan .seealso: `PCMGGetGalerkin()`, `PCMGGalerkinType`
15043fc8bf9cSBarry Smith 
1505c2be2410SBarry Smith @*/
15062134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin(PC pc,PCMGGalerkinType use)
1507c2be2410SBarry Smith {
1508c2be2410SBarry Smith   PetscFunctionBegin;
15090700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1510cac4c232SBarry Smith   PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PCMGGalerkinType),(pc,use));
1511c2be2410SBarry Smith   PetscFunctionReturn(0);
1512c2be2410SBarry Smith }
1513c2be2410SBarry Smith 
15143fc8bf9cSBarry Smith /*@
15153fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
151682b87d87SMatthew G. Knepley       A_i-1 = r_i * A_i * p_i
15173fc8bf9cSBarry Smith 
15183fc8bf9cSBarry Smith    Not Collective
15193fc8bf9cSBarry Smith 
15203fc8bf9cSBarry Smith    Input Parameter:
15213fc8bf9cSBarry Smith .  pc - the multigrid context
15223fc8bf9cSBarry Smith 
15233fc8bf9cSBarry Smith    Output Parameter:
15242134b1e4SBarry 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
15253fc8bf9cSBarry Smith 
15263fc8bf9cSBarry Smith    Level: intermediate
15273fc8bf9cSBarry Smith 
1528db781477SPatrick Sanan .seealso: `PCMGSetGalerkin()`, `PCMGGalerkinType`
15293fc8bf9cSBarry Smith 
15303fc8bf9cSBarry Smith @*/
15312134b1e4SBarry Smith PetscErrorCode  PCMGGetGalerkin(PC pc,PCMGGalerkinType  *galerkin)
15323fc8bf9cSBarry Smith {
1533f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
15343fc8bf9cSBarry Smith 
15353fc8bf9cSBarry Smith   PetscFunctionBegin;
15360700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
15372134b1e4SBarry Smith   *galerkin = mg->galerkin;
15383fc8bf9cSBarry Smith   PetscFunctionReturn(0);
15393fc8bf9cSBarry Smith }
15403fc8bf9cSBarry Smith 
1541f3b08a26SMatthew G. Knepley PetscErrorCode PCMGSetAdaptInterpolation_MG(PC pc, PetscBool adapt)
1542f3b08a26SMatthew G. Knepley {
1543f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *) pc->data;
1544f3b08a26SMatthew G. Knepley 
1545f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1546f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = adapt;
1547f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1548f3b08a26SMatthew G. Knepley }
1549f3b08a26SMatthew G. Knepley 
1550f3b08a26SMatthew G. Knepley PetscErrorCode PCMGGetAdaptInterpolation_MG(PC pc, PetscBool *adapt)
1551f3b08a26SMatthew G. Knepley {
1552f3b08a26SMatthew G. Knepley   PC_MG *mg = (PC_MG *) pc->data;
1553f3b08a26SMatthew G. Knepley 
1554f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1555f3b08a26SMatthew G. Knepley   *adapt = mg->adaptInterpolation;
1556f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1557f3b08a26SMatthew G. Knepley }
1558f3b08a26SMatthew G. Knepley 
15592b3cbbdaSStefano Zampini PetscErrorCode PCMGSetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType ctype)
15602b3cbbdaSStefano Zampini {
15612b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *) pc->data;
15622b3cbbdaSStefano Zampini 
15632b3cbbdaSStefano Zampini   PetscFunctionBegin;
15642b3cbbdaSStefano Zampini   mg->adaptInterpolation = ctype != PCMG_ADAPT_NONE ? PETSC_TRUE : PETSC_FALSE;
15652b3cbbdaSStefano Zampini   mg->coarseSpaceType = ctype;
15662b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15672b3cbbdaSStefano Zampini }
15682b3cbbdaSStefano Zampini 
15692b3cbbdaSStefano Zampini PetscErrorCode PCMGGetAdaptCoarseSpaceType_MG(PC pc, PCMGCoarseSpaceType *ctype)
15702b3cbbdaSStefano Zampini {
15712b3cbbdaSStefano Zampini   PC_MG *mg = (PC_MG *) pc->data;
15722b3cbbdaSStefano Zampini 
15732b3cbbdaSStefano Zampini   PetscFunctionBegin;
15742b3cbbdaSStefano Zampini   *ctype = mg->coarseSpaceType;
15752b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
15762b3cbbdaSStefano Zampini }
15772b3cbbdaSStefano Zampini 
157841b6fd38SMatthew G. Knepley PetscErrorCode PCMGSetAdaptCR_MG(PC pc, PetscBool cr)
157941b6fd38SMatthew G. Knepley {
158041b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *) pc->data;
158141b6fd38SMatthew G. Knepley 
158241b6fd38SMatthew G. Knepley   PetscFunctionBegin;
158341b6fd38SMatthew G. Knepley   mg->compatibleRelaxation = cr;
158441b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
158541b6fd38SMatthew G. Knepley }
158641b6fd38SMatthew G. Knepley 
158741b6fd38SMatthew G. Knepley PetscErrorCode PCMGGetAdaptCR_MG(PC pc, PetscBool *cr)
158841b6fd38SMatthew G. Knepley {
158941b6fd38SMatthew G. Knepley   PC_MG *mg = (PC_MG *) pc->data;
159041b6fd38SMatthew G. Knepley 
159141b6fd38SMatthew G. Knepley   PetscFunctionBegin;
159241b6fd38SMatthew G. Knepley   *cr = mg->compatibleRelaxation;
159341b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
159441b6fd38SMatthew G. Knepley }
159541b6fd38SMatthew G. Knepley 
15962b3cbbdaSStefano Zampini /*@C
15972b3cbbdaSStefano Zampini   PCMGSetAdaptCoarseSpaceType - Set the type of adaptive coarse space.
15982b3cbbdaSStefano Zampini 
15992b3cbbdaSStefano 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.
16002b3cbbdaSStefano Zampini 
16012b3cbbdaSStefano Zampini   Logically Collective on PC
16022b3cbbdaSStefano Zampini 
16032b3cbbdaSStefano Zampini   Input Parameters:
16042b3cbbdaSStefano Zampini + pc    - the multigrid context
16052b3cbbdaSStefano Zampini - ctype - the type of coarse space
16062b3cbbdaSStefano Zampini 
16072b3cbbdaSStefano Zampini   Options Database Keys:
16082b3cbbdaSStefano Zampini + -pc_mg_adapt_interp_n <int>             - The number of modes to use
16092b3cbbdaSStefano Zampini - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: none, polynomial, harmonic, eigenvector, generalized_eigenvector, gdsw
16102b3cbbdaSStefano Zampini 
16112b3cbbdaSStefano Zampini   Level: intermediate
16122b3cbbdaSStefano Zampini 
16132b3cbbdaSStefano Zampini .keywords: MG, set, Galerkin
16142b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGGetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`
16152b3cbbdaSStefano Zampini @*/
16162b3cbbdaSStefano Zampini PetscErrorCode PCMGSetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType ctype)
16172b3cbbdaSStefano Zampini {
16182b3cbbdaSStefano Zampini   PetscFunctionBegin;
16192b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
16202b3cbbdaSStefano Zampini   PetscValidLogicalCollectiveEnum(pc,ctype,2);
16212b3cbbdaSStefano Zampini   PetscTryMethod(pc,"PCMGSetAdaptCoarseSpaceType_C",(PC,PCMGCoarseSpaceType),(pc,ctype));
16222b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
16232b3cbbdaSStefano Zampini }
16242b3cbbdaSStefano Zampini 
16252b3cbbdaSStefano Zampini /*@C
16262b3cbbdaSStefano Zampini   PCMGGetAdaptCoarseSpaceType - Get the type of adaptive coarse space.
16272b3cbbdaSStefano Zampini 
16282b3cbbdaSStefano Zampini   Not Collective
16292b3cbbdaSStefano Zampini 
16302b3cbbdaSStefano Zampini   Input Parameter:
16312b3cbbdaSStefano Zampini . pc    - the multigrid context
16322b3cbbdaSStefano Zampini 
16332b3cbbdaSStefano Zampini   Output Parameter:
16342b3cbbdaSStefano Zampini . ctype - the type of coarse space
16352b3cbbdaSStefano Zampini 
16362b3cbbdaSStefano Zampini   Level: intermediate
16372b3cbbdaSStefano Zampini 
16382b3cbbdaSStefano Zampini .keywords: MG, Get, Galerkin
16392b3cbbdaSStefano Zampini .seealso: `PCMGCoarseSpaceType`, `PCMGSetAdaptCoarseSpaceType()`, `PCMGSetGalerkin()`
16402b3cbbdaSStefano Zampini @*/
16412b3cbbdaSStefano Zampini PetscErrorCode PCMGGetAdaptCoarseSpaceType(PC pc, PCMGCoarseSpaceType *ctype)
16422b3cbbdaSStefano Zampini {
16432b3cbbdaSStefano Zampini   PetscFunctionBegin;
16442b3cbbdaSStefano Zampini   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
16452b3cbbdaSStefano Zampini   PetscValidPointer(ctype,2);
16462b3cbbdaSStefano Zampini   PetscUseMethod(pc,"PCMGGetAdaptCoarseSpaceType_C",(PC,PCMGCoarseSpaceType*),(pc,ctype));
16472b3cbbdaSStefano Zampini   PetscFunctionReturn(0);
16482b3cbbdaSStefano Zampini }
16492b3cbbdaSStefano Zampini 
16502b3cbbdaSStefano Zampini /* MATT: REMOVE? */
1651f3b08a26SMatthew G. Knepley /*@
1652f3b08a26SMatthew 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.
1653f3b08a26SMatthew G. Knepley 
1654f3b08a26SMatthew G. Knepley   Logically Collective on PC
1655f3b08a26SMatthew G. Knepley 
1656f3b08a26SMatthew G. Knepley   Input Parameters:
1657f3b08a26SMatthew G. Knepley + pc    - the multigrid context
1658f3b08a26SMatthew G. Knepley - adapt - flag for adaptation of the interpolator
1659f3b08a26SMatthew G. Knepley 
1660f3b08a26SMatthew G. Knepley   Options Database Keys:
1661f3b08a26SMatthew G. Knepley + -pc_mg_adapt_interp                     - Turn on adaptation
1662f3b08a26SMatthew G. Knepley . -pc_mg_adapt_interp_n <int>             - The number of modes to use, should be divisible by dimension
1663f3b08a26SMatthew G. Knepley - -pc_mg_adapt_interp_coarse_space <type> - The type of coarse space: polynomial, harmonic, eigenvector, generalized_eigenvector
1664f3b08a26SMatthew G. Knepley 
1665f3b08a26SMatthew G. Knepley   Level: intermediate
1666f3b08a26SMatthew G. Knepley 
1667f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin
1668db781477SPatrick Sanan .seealso: `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`
1669f3b08a26SMatthew G. Knepley @*/
1670f3b08a26SMatthew G. Knepley PetscErrorCode PCMGSetAdaptInterpolation(PC pc, PetscBool adapt)
1671f3b08a26SMatthew G. Knepley {
1672f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1673f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1674cac4c232SBarry Smith   PetscTryMethod(pc,"PCMGSetAdaptInterpolation_C",(PC,PetscBool),(pc,adapt));
1675f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1676f3b08a26SMatthew G. Knepley }
1677f3b08a26SMatthew G. Knepley 
1678f3b08a26SMatthew G. Knepley /*@
1679f3b08a26SMatthew G. Knepley   PCMGGetAdaptInterpolation - Get the flag to adapt the interpolator based upon a vector space which should be accurately captured by the next coarser mesh, and thus accurately interpolated.
1680f3b08a26SMatthew G. Knepley 
1681f3b08a26SMatthew G. Knepley   Not collective
1682f3b08a26SMatthew G. Knepley 
1683f3b08a26SMatthew G. Knepley   Input Parameter:
1684f3b08a26SMatthew G. Knepley . pc    - the multigrid context
1685f3b08a26SMatthew G. Knepley 
1686f3b08a26SMatthew G. Knepley   Output Parameter:
1687f3b08a26SMatthew G. Knepley . adapt - flag for adaptation of the interpolator
1688f3b08a26SMatthew G. Knepley 
1689f3b08a26SMatthew G. Knepley   Level: intermediate
1690f3b08a26SMatthew G. Knepley 
1691f3b08a26SMatthew G. Knepley .keywords: MG, set, Galerkin
1692db781477SPatrick Sanan .seealso: `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`
1693f3b08a26SMatthew G. Knepley @*/
1694f3b08a26SMatthew G. Knepley PetscErrorCode PCMGGetAdaptInterpolation(PC pc, PetscBool *adapt)
1695f3b08a26SMatthew G. Knepley {
1696f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
1697f3b08a26SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1698dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(adapt, 2);
1699cac4c232SBarry Smith   PetscUseMethod(pc,"PCMGGetAdaptInterpolation_C",(PC,PetscBool*),(pc,adapt));
1700f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1701f3b08a26SMatthew G. Knepley }
1702f3b08a26SMatthew G. Knepley 
17034b9ad928SBarry Smith /*@
170441b6fd38SMatthew G. Knepley   PCMGSetAdaptCR - Monitor the coarse space quality using an auxiliary solve with compatible relaxation.
170541b6fd38SMatthew G. Knepley 
170641b6fd38SMatthew G. Knepley   Logically Collective on PC
170741b6fd38SMatthew G. Knepley 
170841b6fd38SMatthew G. Knepley   Input Parameters:
170941b6fd38SMatthew G. Knepley + pc - the multigrid context
171041b6fd38SMatthew G. Knepley - cr - flag for compatible relaxation
171141b6fd38SMatthew G. Knepley 
171241b6fd38SMatthew G. Knepley   Options Database Keys:
171341b6fd38SMatthew G. Knepley . -pc_mg_adapt_cr - Turn on compatible relaxation
171441b6fd38SMatthew G. Knepley 
171541b6fd38SMatthew G. Knepley   Level: intermediate
171641b6fd38SMatthew G. Knepley 
171741b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin
1718db781477SPatrick Sanan .seealso: `PCMGGetAdaptCR()`, `PCMGSetAdaptInterpolation()`, `PCMGSetGalerkin()`
171941b6fd38SMatthew G. Knepley @*/
172041b6fd38SMatthew G. Knepley PetscErrorCode PCMGSetAdaptCR(PC pc, PetscBool cr)
172141b6fd38SMatthew G. Knepley {
172241b6fd38SMatthew G. Knepley   PetscFunctionBegin;
172341b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1724cac4c232SBarry Smith   PetscTryMethod(pc,"PCMGSetAdaptCR_C",(PC,PetscBool),(pc,cr));
172541b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
172641b6fd38SMatthew G. Knepley }
172741b6fd38SMatthew G. Knepley 
172841b6fd38SMatthew G. Knepley /*@
172941b6fd38SMatthew G. Knepley   PCMGGetAdaptCR - Get the flag to monitor coarse space quality using an auxiliary solve with compatible relaxation.
173041b6fd38SMatthew G. Knepley 
173141b6fd38SMatthew G. Knepley   Not collective
173241b6fd38SMatthew G. Knepley 
173341b6fd38SMatthew G. Knepley   Input Parameter:
173441b6fd38SMatthew G. Knepley . pc    - the multigrid context
173541b6fd38SMatthew G. Knepley 
173641b6fd38SMatthew G. Knepley   Output Parameter:
173741b6fd38SMatthew G. Knepley . cr - flag for compatible relaxaion
173841b6fd38SMatthew G. Knepley 
173941b6fd38SMatthew G. Knepley   Level: intermediate
174041b6fd38SMatthew G. Knepley 
174141b6fd38SMatthew G. Knepley .keywords: MG, set, Galerkin
1742db781477SPatrick Sanan .seealso: `PCMGSetAdaptCR()`, `PCMGGetAdaptInterpolation()`, `PCMGSetGalerkin()`
174341b6fd38SMatthew G. Knepley @*/
174441b6fd38SMatthew G. Knepley PetscErrorCode PCMGGetAdaptCR(PC pc, PetscBool *cr)
174541b6fd38SMatthew G. Knepley {
174641b6fd38SMatthew G. Knepley   PetscFunctionBegin;
174741b6fd38SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1748dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(cr, 2);
1749cac4c232SBarry Smith   PetscUseMethod(pc,"PCMGGetAdaptCR_C",(PC,PetscBool*),(pc,cr));
175041b6fd38SMatthew G. Knepley   PetscFunctionReturn(0);
175141b6fd38SMatthew G. Knepley }
175241b6fd38SMatthew G. Knepley 
175341b6fd38SMatthew G. Knepley /*@
175406792cafSBarry Smith    PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1755710315b6SLawrence Mitchell    on all levels.  Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of
1756710315b6SLawrence Mitchell    pre- and post-smoothing steps.
175706792cafSBarry Smith 
175806792cafSBarry Smith    Logically Collective on PC
175906792cafSBarry Smith 
176006792cafSBarry Smith    Input Parameters:
176106792cafSBarry Smith +  mg - the multigrid context
176206792cafSBarry Smith -  n - the number of smoothing steps
176306792cafSBarry Smith 
176406792cafSBarry Smith    Options Database Key:
1765a2b725a8SWilliam Gropp .  -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
176606792cafSBarry Smith 
176706792cafSBarry Smith    Level: advanced
176806792cafSBarry Smith 
176995452b02SPatrick Sanan    Notes:
177095452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
177106792cafSBarry Smith     there is no separate smooth up on the coarsest grid.
177206792cafSBarry Smith 
1773db781477SPatrick Sanan .seealso: `PCMGSetDistinctSmoothUp()`
177406792cafSBarry Smith @*/
177506792cafSBarry Smith PetscErrorCode  PCMGSetNumberSmooth(PC pc,PetscInt n)
177606792cafSBarry Smith {
177706792cafSBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
177806792cafSBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
177906792cafSBarry Smith   PetscInt       i,levels;
178006792cafSBarry Smith 
178106792cafSBarry Smith   PetscFunctionBegin;
178206792cafSBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
178306792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
178428b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
178506792cafSBarry Smith   levels = mglevels[0]->levels;
178606792cafSBarry Smith 
178706792cafSBarry Smith   for (i=1; i<levels; i++) {
17889566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n));
17899566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n));
179006792cafSBarry Smith     mg->default_smoothu = n;
179106792cafSBarry Smith     mg->default_smoothd = n;
179206792cafSBarry Smith   }
179306792cafSBarry Smith   PetscFunctionReturn(0);
179406792cafSBarry Smith }
179506792cafSBarry Smith 
1796f442ab6aSBarry Smith /*@
17978e5aa403SBarry Smith    PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a separate KSP from the down (pre) smoother on all levels
1798710315b6SLawrence Mitchell        and adds the suffix _up to the options name
1799f442ab6aSBarry Smith 
1800f442ab6aSBarry Smith    Logically Collective on PC
1801f442ab6aSBarry Smith 
1802f442ab6aSBarry Smith    Input Parameters:
1803f442ab6aSBarry Smith .  pc - the preconditioner context
1804f442ab6aSBarry Smith 
1805f442ab6aSBarry Smith    Options Database Key:
1806147403d9SBarry Smith .  -pc_mg_distinct_smoothup <bool> - use distinct smoothing objects
1807f442ab6aSBarry Smith 
1808f442ab6aSBarry Smith    Level: advanced
1809f442ab6aSBarry Smith 
181095452b02SPatrick Sanan    Notes:
181195452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
1812f442ab6aSBarry Smith     there is no separate smooth up on the coarsest grid.
1813f442ab6aSBarry Smith 
1814db781477SPatrick Sanan .seealso: `PCMGSetNumberSmooth()`
1815f442ab6aSBarry Smith @*/
1816f442ab6aSBarry Smith PetscErrorCode  PCMGSetDistinctSmoothUp(PC pc)
1817f442ab6aSBarry Smith {
1818f442ab6aSBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1819f442ab6aSBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
1820f442ab6aSBarry Smith   PetscInt       i,levels;
1821f442ab6aSBarry Smith   KSP            subksp;
1822f442ab6aSBarry Smith 
1823f442ab6aSBarry Smith   PetscFunctionBegin;
1824f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
182528b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
1826f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1827f442ab6aSBarry Smith 
1828f442ab6aSBarry Smith   for (i=1; i<levels; i++) {
1829710315b6SLawrence Mitchell     const char *prefix = NULL;
1830f442ab6aSBarry Smith     /* make sure smoother up and down are different */
18319566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmootherUp(pc,i,&subksp));
18329566063dSJacob Faibussowitsch     PetscCall(KSPGetOptionsPrefix(mglevels[i]->smoothd,&prefix));
18339566063dSJacob Faibussowitsch     PetscCall(KSPSetOptionsPrefix(subksp,prefix));
18349566063dSJacob Faibussowitsch     PetscCall(KSPAppendOptionsPrefix(subksp,"up_"));
1835f442ab6aSBarry Smith   }
1836f442ab6aSBarry Smith   PetscFunctionReturn(0);
1837f442ab6aSBarry Smith }
1838f442ab6aSBarry Smith 
183907a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
184007a4832bSFande Kong PetscErrorCode  PCGetInterpolations_MG(PC pc,PetscInt *num_levels,Mat *interpolations[])
184107a4832bSFande Kong {
184207a4832bSFande Kong   PC_MG          *mg        = (PC_MG*)pc->data;
184307a4832bSFande Kong   PC_MG_Levels   **mglevels = mg->levels;
184407a4832bSFande Kong   Mat            *mat;
184507a4832bSFande Kong   PetscInt       l;
184607a4832bSFande Kong 
184707a4832bSFande Kong   PetscFunctionBegin;
184828b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
18499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels,&mat));
185007a4832bSFande Kong   for (l=1; l< mg->nlevels; l++) {
185107a4832bSFande Kong     mat[l-1] = mglevels[l]->interpolate;
18529566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l-1]));
185307a4832bSFande Kong   }
185407a4832bSFande Kong   *num_levels = mg->nlevels;
185507a4832bSFande Kong   *interpolations = mat;
185607a4832bSFande Kong   PetscFunctionReturn(0);
185707a4832bSFande Kong }
185807a4832bSFande Kong 
185907a4832bSFande Kong /* No new matrices are created, and the coarse operator matrices are the references to the original ones */
186007a4832bSFande Kong PetscErrorCode  PCGetCoarseOperators_MG(PC pc,PetscInt *num_levels,Mat *coarseOperators[])
186107a4832bSFande Kong {
186207a4832bSFande Kong   PC_MG          *mg        = (PC_MG*)pc->data;
186307a4832bSFande Kong   PC_MG_Levels   **mglevels = mg->levels;
186407a4832bSFande Kong   PetscInt       l;
186507a4832bSFande Kong   Mat            *mat;
186607a4832bSFande Kong 
186707a4832bSFande Kong   PetscFunctionBegin;
186828b400f6SJacob Faibussowitsch   PetscCheck(mglevels,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
18699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mg->nlevels,&mat));
187007a4832bSFande Kong   for (l=0; l<mg->nlevels-1; l++) {
18719566063dSJacob Faibussowitsch     PetscCall(KSPGetOperators(mglevels[l]->smoothd,NULL,&(mat[l])));
18729566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)mat[l]));
187307a4832bSFande Kong   }
187407a4832bSFande Kong   *num_levels = mg->nlevels;
187507a4832bSFande Kong   *coarseOperators = mat;
187607a4832bSFande Kong   PetscFunctionReturn(0);
187707a4832bSFande Kong }
187807a4832bSFande Kong 
1879f3b08a26SMatthew G. Knepley /*@C
1880f3b08a26SMatthew G. Knepley   PCMGRegisterCoarseSpaceConstructor -  Adds a method to the PCMG package for coarse space construction.
1881f3b08a26SMatthew G. Knepley 
1882f3b08a26SMatthew G. Knepley   Not collective
1883f3b08a26SMatthew G. Knepley 
1884f3b08a26SMatthew G. Knepley   Input Parameters:
1885f3b08a26SMatthew G. Knepley + name     - name of the constructor
1886f3b08a26SMatthew G. Knepley - function - constructor routine
1887f3b08a26SMatthew G. Knepley 
1888f3b08a26SMatthew G. Knepley   Notes:
1889f3b08a26SMatthew G. Knepley   Calling sequence for the routine:
18902b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
1891f3b08a26SMatthew G. Knepley $   pc        - The PC object
1892f3b08a26SMatthew G. Knepley $   l         - The multigrid level, 0 is the coarse level
1893f3b08a26SMatthew G. Knepley $   dm        - The DM for this level
1894f3b08a26SMatthew G. Knepley $   smooth    - The level smoother
1895f3b08a26SMatthew G. Knepley $   Nc        - The size of the coarse space
1896f3b08a26SMatthew G. Knepley $   initGuess - Basis for an initial guess for the space
1897f3b08a26SMatthew G. Knepley $   coarseSp  - A basis for the computed coarse space
1898f3b08a26SMatthew G. Knepley 
1899f3b08a26SMatthew G. Knepley   Level: advanced
1900f3b08a26SMatthew G. Knepley 
1901db781477SPatrick Sanan .seealso: `PCMGGetCoarseSpaceConstructor()`, `PCRegister()`
1902f3b08a26SMatthew G. Knepley @*/
19032b3cbbdaSStefano Zampini PetscErrorCode PCMGRegisterCoarseSpaceConstructor(const char name[], PetscErrorCode (*function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat*))
1904f3b08a26SMatthew G. Knepley {
1905f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
19069566063dSJacob Faibussowitsch   PetscCall(PCInitializePackage());
19079566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PCMGCoarseList,name,function));
1908f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1909f3b08a26SMatthew G. Knepley }
1910f3b08a26SMatthew G. Knepley 
1911f3b08a26SMatthew G. Knepley /*@C
1912f3b08a26SMatthew G. Knepley   PCMGGetCoarseSpaceConstructor -  Returns the given coarse space construction method.
1913f3b08a26SMatthew G. Knepley 
1914f3b08a26SMatthew G. Knepley   Not collective
1915f3b08a26SMatthew G. Knepley 
1916f3b08a26SMatthew G. Knepley   Input Parameter:
1917f3b08a26SMatthew G. Knepley . name     - name of the constructor
1918f3b08a26SMatthew G. Knepley 
1919f3b08a26SMatthew G. Knepley   Output Parameter:
1920f3b08a26SMatthew G. Knepley . function - constructor routine
1921f3b08a26SMatthew G. Knepley 
1922f3b08a26SMatthew G. Knepley   Notes:
1923f3b08a26SMatthew G. Knepley   Calling sequence for the routine:
19242b3cbbdaSStefano Zampini $ my_csp(PC pc, PetscInt l, DM dm, KSP smooth, PetscInt Nc, Mat initGuess, Mat *coarseSp)
1925f3b08a26SMatthew G. Knepley $   pc        - The PC object
1926f3b08a26SMatthew G. Knepley $   l         - The multigrid level, 0 is the coarse level
1927f3b08a26SMatthew G. Knepley $   dm        - The DM for this level
1928f3b08a26SMatthew G. Knepley $   smooth    - The level smoother
1929f3b08a26SMatthew G. Knepley $   Nc        - The size of the coarse space
1930f3b08a26SMatthew G. Knepley $   initGuess - Basis for an initial guess for the space
1931f3b08a26SMatthew G. Knepley $   coarseSp  - A basis for the computed coarse space
1932f3b08a26SMatthew G. Knepley 
1933f3b08a26SMatthew G. Knepley   Level: advanced
1934f3b08a26SMatthew G. Knepley 
1935db781477SPatrick Sanan .seealso: `PCMGRegisterCoarseSpaceConstructor()`, `PCRegister()`
1936f3b08a26SMatthew G. Knepley @*/
19372b3cbbdaSStefano Zampini PetscErrorCode PCMGGetCoarseSpaceConstructor(const char name[], PetscErrorCode (**function)(PC, PetscInt, DM, KSP, PetscInt, Mat, Mat*))
1938f3b08a26SMatthew G. Knepley {
1939f3b08a26SMatthew G. Knepley   PetscFunctionBegin;
19409566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PCMGCoarseList,name,function));
1941f3b08a26SMatthew G. Knepley   PetscFunctionReturn(0);
1942f3b08a26SMatthew G. Knepley }
1943f3b08a26SMatthew G. Knepley 
19444b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
19454b9ad928SBarry Smith 
19463b09bd56SBarry Smith /*MC
1947ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
19483b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
19493b09bd56SBarry Smith 
19503b09bd56SBarry Smith    Options Database Keys:
19513b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
1952391689abSStefano Zampini .  -pc_mg_cycle_type <v,w> - provide the cycle desired
19538c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
19543b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
1955710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
19562134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
19578cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
19588cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1959e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
19608cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
19618cf6037eSBarry Smith                         to the binary output file called binaryoutput
19623b09bd56SBarry Smith 
196395452b02SPatrick Sanan    Notes:
19640b3c753eSRichard Tran Mills     If one uses a Krylov method such GMRES or CG as the smoother then one must use KSPFGMRES, KSPGCR, or KSPRICHARDSON as the outer Krylov method
19653b09bd56SBarry Smith 
19668cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
19678cf6037eSBarry Smith 
196823067569SBarry Smith        When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
196923067569SBarry Smith        is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
197023067569SBarry Smith        (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
197123067569SBarry Smith        residual is computed at the end of each cycle.
197223067569SBarry Smith 
19733b09bd56SBarry Smith    Level: intermediate
19743b09bd56SBarry Smith 
1975db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMGType`, `PCEXOTIC`, `PCGAMG`, `PCML`, `PCHYPRE`
1976db781477SPatrick Sanan           `PCMGSetLevels()`, `PCMGGetLevels()`, `PCMGSetType()`, `PCMGSetCycleType()`,
1977db781477SPatrick Sanan           `PCMGSetDistinctSmoothUp()`, `PCMGGetCoarseSolve()`, `PCMGSetResidual()`, `PCMGSetInterpolation()`,
1978db781477SPatrick Sanan           `PCMGSetRestriction()`, `PCMGGetSmoother()`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`,
1979db781477SPatrick Sanan           `PCMGSetCycleTypeOnLevel()`, `PCMGSetRhs()`, `PCMGSetX()`, `PCMGSetR()`
19803b09bd56SBarry Smith M*/
19813b09bd56SBarry Smith 
19828cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
19834b9ad928SBarry Smith {
1984f3fbd535SBarry Smith   PC_MG          *mg;
1985f3fbd535SBarry Smith 
19864b9ad928SBarry Smith   PetscFunctionBegin;
19879566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc,&mg));
19883ec1f749SStefano Zampini   pc->data     = mg;
1989f3fbd535SBarry Smith   mg->nlevels  = -1;
199010eca3edSLisandro Dalcin   mg->am       = PC_MG_MULTIPLICATIVE;
19912134b1e4SBarry Smith   mg->galerkin = PC_MG_GALERKIN_NONE;
1992f3b08a26SMatthew G. Knepley   mg->adaptInterpolation = PETSC_FALSE;
1993f3b08a26SMatthew G. Knepley   mg->Nc                 = -1;
1994f3b08a26SMatthew G. Knepley   mg->eigenvalue         = -1;
1995f3fbd535SBarry Smith 
199637a44384SMark Adams   pc->useAmat = PETSC_TRUE;
199737a44384SMark Adams 
19984b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
1999fcb023d4SJed Brown   pc->ops->applytranspose = PCApplyTranspose_MG;
200030b0564aSStefano Zampini   pc->ops->matapply       = PCMatApply_MG;
20014b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
2002a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
20034b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
20044b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
20054b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
2006fb15c04eSBarry Smith 
20079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposedDataRegister(&mg->eigenvalue));
20089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG));
20099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",PCMGGetLevels_MG));
20109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",PCMGSetLevels_MG));
20119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",PCGetInterpolations_MG));
20129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",PCGetCoarseOperators_MG));
20139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptInterpolation_C",PCMGSetAdaptInterpolation_MG));
20149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptInterpolation_C",PCMGGetAdaptInterpolation_MG));
20159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptCR_C",PCMGSetAdaptCR_MG));
20169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptCR_C",PCMGGetAdaptCR_MG));
20172b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGSetAdaptCoarseSpaceType_C",PCMGSetAdaptCoarseSpaceType_MG));
20182b3cbbdaSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGetAdaptCoarseSpaceType_C",PCMGGetAdaptCoarseSpaceType_MG));
20194b9ad928SBarry Smith   PetscFunctionReturn(0);
20204b9ad928SBarry Smith }
2021