xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision e952c529d6d48fb12ed857b0190b95607f733362)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith     Defines the multigrid preconditioner interface.
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h>                    /*I "petscksp.h" I*/
61e25c274SJed Brown #include <petscdm.h>
7391689abSStefano Zampini PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC,PetscBool*);
84b9ad928SBarry Smith 
931567311SBarry Smith PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PCRichardsonConvergedReason *reason)
104b9ad928SBarry Smith {
1131567311SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
1231567311SBarry Smith   PC_MG_Levels   *mgc,*mglevels = *mglevelsin;
136849ba73SBarry Smith   PetscErrorCode ierr;
1431567311SBarry Smith   PetscInt       cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles;
15a0808db4SHong Zhang   PC             subpc;
16a0808db4SHong Zhang   PCFailedReason pcreason;
174b9ad928SBarry Smith 
184b9ad928SBarry Smith   PetscFunctionBegin;
1963e6d426SJed Brown   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
2031567311SBarry Smith   ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr);  /* pre-smooth */
21a0808db4SHong Zhang   ierr = KSPGetPC(mglevels->smoothd,&subpc);CHKERRQ(ierr);
22a0808db4SHong Zhang   ierr = PCGetSetUpFailedReason(subpc,&pcreason);CHKERRQ(ierr);
23a0808db4SHong Zhang   if (pcreason) {
24a0808db4SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
25a0808db4SHong Zhang   }
2663e6d426SJed Brown   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
2731567311SBarry Smith   if (mglevels->level) {  /* not the coarsest grid */
2863e6d426SJed Brown     if (mglevels->eventresidual) {ierr = PetscLogEventBegin(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
2931567311SBarry Smith     ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr);
3063e6d426SJed Brown     if (mglevels->eventresidual) {ierr = PetscLogEventEnd(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
314b9ad928SBarry Smith 
324b9ad928SBarry Smith     /* if on finest level and have convergence criteria set */
3331567311SBarry Smith     if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) {
344b9ad928SBarry Smith       PetscReal rnorm;
3531567311SBarry Smith       ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr);
364b9ad928SBarry Smith       if (rnorm <= mg->ttol) {
3770441072SBarry Smith         if (rnorm < mg->abstol) {
384d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_ATOL;
3957622a8eSBarry Smith           ierr    = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol);CHKERRQ(ierr);
404b9ad928SBarry Smith         } else {
414d0a8057SBarry Smith           *reason = PCRICHARDSON_CONVERGED_RTOL;
4257622a8eSBarry Smith           ierr    = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than relative tolerance times initial residual norm %g\n",(double)rnorm,(double)mg->ttol);CHKERRQ(ierr);
434b9ad928SBarry Smith         }
444b9ad928SBarry Smith         PetscFunctionReturn(0);
454b9ad928SBarry Smith       }
464b9ad928SBarry Smith     }
474b9ad928SBarry Smith 
4831567311SBarry Smith     mgc = *(mglevelsin - 1);
4963e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5031567311SBarry Smith     ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr);
5163e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
52efb30889SBarry Smith     ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr);
534b9ad928SBarry Smith     while (cycles--) {
5431567311SBarry Smith       ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr);
554b9ad928SBarry Smith     }
5663e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5731567311SBarry Smith     ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr);
5863e6d426SJed Brown     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
5963e6d426SJed Brown     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
6031567311SBarry Smith     ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr);    /* post smooth */
6163e6d426SJed Brown     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
624b9ad928SBarry Smith   }
634b9ad928SBarry Smith   PetscFunctionReturn(0);
644b9ad928SBarry Smith }
654b9ad928SBarry Smith 
66ace3abfcSBarry 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)
674b9ad928SBarry Smith {
68f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
69f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
70dfbe8321SBarry Smith   PetscErrorCode ierr;
71391689abSStefano Zampini   PC             tpc;
72391689abSStefano Zampini   PetscBool      changeu,changed;
73f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
744b9ad928SBarry Smith 
754b9ad928SBarry Smith   PetscFunctionBegin;
76a762d673SBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
77a762d673SBarry Smith   for (i=0; i<levels; i++) {
78a762d673SBarry Smith     if (!mglevels[i]->A) {
79a762d673SBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr);
80a762d673SBarry Smith       ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr);
81a762d673SBarry Smith     }
82a762d673SBarry Smith   }
83391689abSStefano Zampini 
84391689abSStefano Zampini   ierr = KSPGetPC(mglevels[levels-1]->smoothd,&tpc);CHKERRQ(ierr);
85391689abSStefano Zampini   ierr = PCPreSolveChangeRHS(tpc,&changed);CHKERRQ(ierr);
86391689abSStefano Zampini   ierr = KSPGetPC(mglevels[levels-1]->smoothu,&tpc);CHKERRQ(ierr);
87391689abSStefano Zampini   ierr = PCPreSolveChangeRHS(tpc,&changeu);CHKERRQ(ierr);
88391689abSStefano Zampini   if (!changed && !changeu) {
89391689abSStefano Zampini     ierr = VecDestroy(&mglevels[levels-1]->b);CHKERRQ(ierr);
90f3fbd535SBarry Smith     mglevels[levels-1]->b = b;
91391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
92391689abSStefano Zampini     if (!mglevels[levels-1]->b) {
93391689abSStefano Zampini       Vec *vec;
94391689abSStefano Zampini 
95391689abSStefano Zampini       ierr = KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
96391689abSStefano Zampini       mglevels[levels-1]->b = *vec;
977ae21d43SStefano Zampini       ierr = PetscFree(vec);CHKERRQ(ierr);
98391689abSStefano Zampini     }
99391689abSStefano Zampini     ierr = VecCopy(b,mglevels[levels-1]->b);CHKERRQ(ierr);
100391689abSStefano Zampini   }
101f3fbd535SBarry Smith   mglevels[levels-1]->x = x;
1024b9ad928SBarry Smith 
10331567311SBarry Smith   mg->rtol   = rtol;
10431567311SBarry Smith   mg->abstol = abstol;
10531567311SBarry Smith   mg->dtol   = dtol;
1064b9ad928SBarry Smith   if (rtol) {
1074b9ad928SBarry Smith     /* compute initial residual norm for relative convergence test */
1084b9ad928SBarry Smith     PetscReal rnorm;
1097319c654SBarry Smith     if (zeroguess) {
1107319c654SBarry Smith       ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr);
1117319c654SBarry Smith     } else {
112f3fbd535SBarry Smith       ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr);
1134b9ad928SBarry Smith       ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr);
1147319c654SBarry Smith     }
11531567311SBarry Smith     mg->ttol = PetscMax(rtol*rnorm,abstol);
1162fa5cd67SKarl Rupp   } else if (abstol) mg->ttol = abstol;
1172fa5cd67SKarl Rupp   else mg->ttol = 0.0;
1184b9ad928SBarry Smith 
1194d0a8057SBarry Smith   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
120336babb1SJed Brown      stop prematurely due to small residual */
1214d0a8057SBarry Smith   for (i=1; i<levels; i++) {
122f3fbd535SBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
123f3fbd535SBarry Smith     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
12423067569SBarry Smith       /* For Richardson the initial guess is nonzero since it is solving in each cycle the original system not just applying as a preconditioner */
12523067569SBarry Smith       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
126f3fbd535SBarry Smith       ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
1274b9ad928SBarry Smith     }
1284d0a8057SBarry Smith   }
1294d0a8057SBarry Smith 
1304d0a8057SBarry Smith   *reason = (PCRichardsonConvergedReason)0;
1314d0a8057SBarry Smith   for (i=0; i<its; i++) {
132f3fbd535SBarry Smith     ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr);
1334d0a8057SBarry Smith     if (*reason) break;
1344d0a8057SBarry Smith   }
1354d0a8057SBarry Smith   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
1364d0a8057SBarry Smith   *outits = i;
137391689abSStefano Zampini   if (!changed && !changeu) mglevels[levels-1]->b = NULL;
1384b9ad928SBarry Smith   PetscFunctionReturn(0);
1394b9ad928SBarry Smith }
1404b9ad928SBarry Smith 
1413aeaf226SBarry Smith PetscErrorCode PCReset_MG(PC pc)
1423aeaf226SBarry Smith {
1433aeaf226SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1443aeaf226SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
1453aeaf226SBarry Smith   PetscErrorCode ierr;
1463aeaf226SBarry Smith   PetscInt       i,n;
1473aeaf226SBarry Smith 
1483aeaf226SBarry Smith   PetscFunctionBegin;
1493aeaf226SBarry Smith   if (mglevels) {
1503aeaf226SBarry Smith     n = mglevels[0]->levels;
1513aeaf226SBarry Smith     for (i=0; i<n-1; i++) {
1523aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i+1]->r);CHKERRQ(ierr);
1533aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i]->b);CHKERRQ(ierr);
1543aeaf226SBarry Smith       ierr = VecDestroy(&mglevels[i]->x);CHKERRQ(ierr);
1553aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i+1]->restrct);CHKERRQ(ierr);
1563aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i+1]->interpolate);CHKERRQ(ierr);
1570de8493bSLawrence Mitchell       ierr = MatDestroy(&mglevels[i+1]->inject);CHKERRQ(ierr);
15873250ac0SBarry Smith       ierr = VecDestroy(&mglevels[i+1]->rscale);CHKERRQ(ierr);
1593aeaf226SBarry Smith     }
160391689abSStefano Zampini     /* this is not null only if the smoother on the finest level
161391689abSStefano Zampini        changes the rhs during PreSolve */
162391689abSStefano Zampini     ierr = VecDestroy(&mglevels[n-1]->b);CHKERRQ(ierr);
1633aeaf226SBarry Smith 
1643aeaf226SBarry Smith     for (i=0; i<n; i++) {
1653aeaf226SBarry Smith       ierr = MatDestroy(&mglevels[i]->A);CHKERRQ(ierr);
1663aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
1673aeaf226SBarry Smith         ierr = KSPReset(mglevels[i]->smoothd);CHKERRQ(ierr);
1683aeaf226SBarry Smith       }
1693aeaf226SBarry Smith       ierr = KSPReset(mglevels[i]->smoothu);CHKERRQ(ierr);
1703aeaf226SBarry Smith     }
1713aeaf226SBarry Smith   }
1723aeaf226SBarry Smith   PetscFunctionReturn(0);
1733aeaf226SBarry Smith }
1743aeaf226SBarry Smith 
1754b9ad928SBarry Smith /*@C
17697177400SBarry Smith    PCMGSetLevels - Sets the number of levels to use with MG.
1774b9ad928SBarry Smith    Must be called before any other MG routine.
1784b9ad928SBarry Smith 
179ad4df100SBarry Smith    Logically Collective on PC
1804b9ad928SBarry Smith 
1814b9ad928SBarry Smith    Input Parameters:
1824b9ad928SBarry Smith +  pc - the preconditioner context
1834b9ad928SBarry Smith .  levels - the number of levels
1844b9ad928SBarry Smith -  comms - optional communicators for each level; this is to allow solving the coarser problems
1852bf68e3eSBarry Smith            on smaller sets of processors.
1864b9ad928SBarry Smith 
1874b9ad928SBarry Smith    Level: intermediate
1884b9ad928SBarry Smith 
1894b9ad928SBarry Smith    Notes:
1904b9ad928SBarry Smith      If the number of levels is one then the multigrid uses the -mg_levels prefix
1914b9ad928SBarry Smith   for setting the level options rather than the -mg_coarse prefix.
1924b9ad928SBarry Smith 
1934b9ad928SBarry Smith .keywords: MG, set, levels, multigrid
1944b9ad928SBarry Smith 
19597177400SBarry Smith .seealso: PCMGSetType(), PCMGGetLevels()
1964b9ad928SBarry Smith @*/
1977087cfbeSBarry Smith PetscErrorCode  PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
1984b9ad928SBarry Smith {
199dfbe8321SBarry Smith   PetscErrorCode ierr;
200f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
201ce94432eSBarry Smith   MPI_Comm       comm;
2023aeaf226SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
20310eca3edSLisandro Dalcin   PCMGType       mgtype     = mg->am;
20410167fecSBarry Smith   PetscInt       mgctype    = (PetscInt) PC_MG_CYCLE_V;
205f3fbd535SBarry Smith   PetscInt       i;
206f3fbd535SBarry Smith   PetscMPIInt    size;
207f3fbd535SBarry Smith   const char     *prefix;
208f3fbd535SBarry Smith   PC             ipc;
209*e952c529SMatthew G. Knepley   PetscBool      ismg;
2103aeaf226SBarry Smith   PetscInt       n;
2114b9ad928SBarry Smith 
2124b9ad928SBarry Smith   PetscFunctionBegin;
2130700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
214548767e0SJed Brown   PetscValidLogicalCollectiveInt(pc,levels,2);
215*e952c529SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) pc, PCMG, &ismg);CHKERRQ(ierr);
216*e952c529SMatthew G. Knepley   if (!ismg) PetscFunctionReturn(0);
217548767e0SJed Brown   if (mg->nlevels == levels) PetscFunctionReturn(0);
2181a97d7b6SStefano Zampini   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
2193aeaf226SBarry Smith   if (mglevels) {
22010eca3edSLisandro Dalcin     mgctype = mglevels[0]->cycles;
2213aeaf226SBarry Smith     /* changing the number of levels so free up the previous stuff */
2223aeaf226SBarry Smith     ierr = PCReset_MG(pc);CHKERRQ(ierr);
2233aeaf226SBarry Smith     n    = mglevels[0]->levels;
2243aeaf226SBarry Smith     for (i=0; i<n; i++) {
2253aeaf226SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
2263aeaf226SBarry Smith         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
2273aeaf226SBarry Smith       }
2283aeaf226SBarry Smith       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
2293aeaf226SBarry Smith       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
2303aeaf226SBarry Smith     }
2313aeaf226SBarry Smith     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
2323aeaf226SBarry Smith   }
233f3fbd535SBarry Smith 
234f3fbd535SBarry Smith   mg->nlevels = levels;
235f3fbd535SBarry Smith 
236785e854fSJed Brown   ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr);
2373bb1ff40SBarry Smith   ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr);
238f3fbd535SBarry Smith 
239f3fbd535SBarry Smith   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
240f3fbd535SBarry Smith 
241a9db87a2SMatthew G Knepley   mg->stageApply = 0;
242f3fbd535SBarry Smith   for (i=0; i<levels; i++) {
243b00a9115SJed Brown     ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr);
2442fa5cd67SKarl Rupp 
245f3fbd535SBarry Smith     mglevels[i]->level               = i;
246f3fbd535SBarry Smith     mglevels[i]->levels              = levels;
24710eca3edSLisandro Dalcin     mglevels[i]->cycles              = mgctype;
248336babb1SJed Brown     mg->default_smoothu              = 2;
249336babb1SJed Brown     mg->default_smoothd              = 2;
25063e6d426SJed Brown     mglevels[i]->eventsmoothsetup    = 0;
25163e6d426SJed Brown     mglevels[i]->eventsmoothsolve    = 0;
25263e6d426SJed Brown     mglevels[i]->eventresidual       = 0;
25363e6d426SJed Brown     mglevels[i]->eventinterprestrict = 0;
254f3fbd535SBarry Smith 
255f3fbd535SBarry Smith     if (comms) comm = comms[i];
256f3fbd535SBarry Smith     ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr);
257422a814eSBarry Smith     ierr = KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure);CHKERRQ(ierr);
2580ee9a668SBarry Smith     ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr);
2590ee9a668SBarry Smith     ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr);
2600ee9a668SBarry Smith     ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level);CHKERRQ(ierr);
2610ee9a668SBarry Smith     if (i || levels == 1) {
2620ee9a668SBarry Smith       char tprefix[128];
2630ee9a668SBarry Smith 
264336babb1SJed Brown       ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr);
2650059c7bdSJed Brown       ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr);
266336babb1SJed Brown       ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr);
267336babb1SJed Brown       ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr);
268336babb1SJed Brown       ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr);
2690ee9a668SBarry Smith       ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);CHKERRQ(ierr);
270f3fbd535SBarry Smith 
2710ee9a668SBarry Smith       sprintf(tprefix,"mg_levels_%d_",(int)i);
2720ee9a668SBarry Smith       ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr);
2730ee9a668SBarry Smith     } else {
274f3fbd535SBarry Smith       ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr);
275f3fbd535SBarry Smith 
2769dbfc187SHong Zhang       /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
277f3fbd535SBarry Smith       ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr);
278f3fbd535SBarry Smith       ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr);
279f3fbd535SBarry Smith       ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
280f3fbd535SBarry Smith       if (size > 1) {
281f3fbd535SBarry Smith         ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr);
282f3fbd535SBarry Smith       } else {
283f3fbd535SBarry Smith         ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr);
284f3fbd535SBarry Smith       }
285753b7fb9SBarry Smith       ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr);
286f3fbd535SBarry Smith     }
2873bb1ff40SBarry Smith     ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr);
2882fa5cd67SKarl Rupp 
289f3fbd535SBarry Smith     mglevels[i]->smoothu = mglevels[i]->smoothd;
29031567311SBarry Smith     mg->rtol             = 0.0;
29131567311SBarry Smith     mg->abstol           = 0.0;
29231567311SBarry Smith     mg->dtol             = 0.0;
29331567311SBarry Smith     mg->ttol             = 0.0;
29431567311SBarry Smith     mg->cyclesperpcapply = 1;
295f3fbd535SBarry Smith   }
296f3fbd535SBarry Smith   mg->levels = mglevels;
29710eca3edSLisandro Dalcin   ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
2984b9ad928SBarry Smith   PetscFunctionReturn(0);
2994b9ad928SBarry Smith }
3004b9ad928SBarry Smith 
301c07bf074SBarry Smith 
302c07bf074SBarry Smith PetscErrorCode PCDestroy_MG(PC pc)
303c07bf074SBarry Smith {
304c07bf074SBarry Smith   PetscErrorCode ierr;
305a06653b4SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
306a06653b4SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
307a06653b4SBarry Smith   PetscInt       i,n;
308c07bf074SBarry Smith 
309c07bf074SBarry Smith   PetscFunctionBegin;
310a06653b4SBarry Smith   ierr = PCReset_MG(pc);CHKERRQ(ierr);
311a06653b4SBarry Smith   if (mglevels) {
312a06653b4SBarry Smith     n = mglevels[0]->levels;
313a06653b4SBarry Smith     for (i=0; i<n; i++) {
314a06653b4SBarry Smith       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
3156bf464f9SBarry Smith         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
316a06653b4SBarry Smith       }
3176bf464f9SBarry Smith       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
318a06653b4SBarry Smith       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
319a06653b4SBarry Smith     }
320a06653b4SBarry Smith     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
321a06653b4SBarry Smith   }
322c31cb41cSBarry Smith   ierr = PetscFree(pc->data);CHKERRQ(ierr);
323f3fbd535SBarry Smith   PetscFunctionReturn(0);
324f3fbd535SBarry Smith }
325f3fbd535SBarry Smith 
326f3fbd535SBarry Smith 
327f3fbd535SBarry Smith 
32809573ac7SBarry Smith extern PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**);
32909573ac7SBarry Smith extern PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**);
33009573ac7SBarry Smith extern PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**);
331f3fbd535SBarry Smith 
332f3fbd535SBarry Smith /*
333f3fbd535SBarry Smith    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
334f3fbd535SBarry Smith              or full cycle of multigrid.
335f3fbd535SBarry Smith 
336f3fbd535SBarry Smith   Note:
337f3fbd535SBarry Smith   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
338f3fbd535SBarry Smith */
339f3fbd535SBarry Smith static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
340f3fbd535SBarry Smith {
341f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
342f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
343f3fbd535SBarry Smith   PetscErrorCode ierr;
344391689abSStefano Zampini   PC             tpc;
345f3fbd535SBarry Smith   PetscInt       levels = mglevels[0]->levels,i;
346391689abSStefano Zampini   PetscBool      changeu,changed;
347f3fbd535SBarry Smith 
348f3fbd535SBarry Smith   PetscFunctionBegin;
349a9db87a2SMatthew G Knepley   if (mg->stageApply) {ierr = PetscLogStagePush(mg->stageApply);CHKERRQ(ierr);}
350e1d8e5deSBarry Smith   /* When the DM is supplying the matrix then it will not exist until here */
351298cc208SBarry Smith   for (i=0; i<levels; i++) {
352e1d8e5deSBarry Smith     if (!mglevels[i]->A) {
35323ee1639SBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr);
354298cc208SBarry Smith       ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr);
355e1d8e5deSBarry Smith     }
356e1d8e5deSBarry Smith   }
357e1d8e5deSBarry Smith 
358391689abSStefano Zampini   ierr = KSPGetPC(mglevels[levels-1]->smoothd,&tpc);CHKERRQ(ierr);
359391689abSStefano Zampini   ierr = PCPreSolveChangeRHS(tpc,&changed);CHKERRQ(ierr);
360391689abSStefano Zampini   ierr = KSPGetPC(mglevels[levels-1]->smoothu,&tpc);CHKERRQ(ierr);
361391689abSStefano Zampini   ierr = PCPreSolveChangeRHS(tpc,&changeu);CHKERRQ(ierr);
362391689abSStefano Zampini   if (!changeu && !changed) {
363391689abSStefano Zampini     ierr = VecDestroy(&mglevels[levels-1]->b);CHKERRQ(ierr);
364f3fbd535SBarry Smith     mglevels[levels-1]->b = b;
365391689abSStefano Zampini   } else { /* if the smoother changes the rhs during PreSolve, we cannot use the input vector */
366391689abSStefano Zampini     if (!mglevels[levels-1]->b) {
367391689abSStefano Zampini       Vec *vec;
368391689abSStefano Zampini 
369391689abSStefano Zampini       ierr = KSPCreateVecs(mglevels[levels-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
370391689abSStefano Zampini       mglevels[levels-1]->b = *vec;
3717ae21d43SStefano Zampini       ierr = PetscFree(vec);CHKERRQ(ierr);
372391689abSStefano Zampini     }
373391689abSStefano Zampini     ierr = VecCopy(b,mglevels[levels-1]->b);CHKERRQ(ierr);
374391689abSStefano Zampini   }
375f3fbd535SBarry Smith   mglevels[levels-1]->x = x;
376391689abSStefano Zampini 
37731567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
378f3fbd535SBarry Smith     ierr = VecSet(x,0.0);CHKERRQ(ierr);
37931567311SBarry Smith     for (i=0; i<mg->cyclesperpcapply; i++) {
3800298fd71SBarry Smith       ierr = PCMGMCycle_Private(pc,mglevels+levels-1,NULL);CHKERRQ(ierr);
381f3fbd535SBarry Smith     }
3822fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_ADDITIVE) {
38331567311SBarry Smith     ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr);
3842fa5cd67SKarl Rupp   } else if (mg->am == PC_MG_KASKADE) {
38531567311SBarry Smith     ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr);
3862fa5cd67SKarl Rupp   } else {
387f3fbd535SBarry Smith     ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr);
388f3fbd535SBarry Smith   }
389a9db87a2SMatthew G Knepley   if (mg->stageApply) {ierr = PetscLogStagePop();CHKERRQ(ierr);}
390391689abSStefano Zampini   if (!changeu && !changed) mglevels[levels-1]->b = NULL;
391f3fbd535SBarry Smith   PetscFunctionReturn(0);
392f3fbd535SBarry Smith }
393f3fbd535SBarry Smith 
394f3fbd535SBarry Smith 
3954416b707SBarry Smith PetscErrorCode PCSetFromOptions_MG(PetscOptionItems *PetscOptionsObject,PC pc)
396f3fbd535SBarry Smith {
397f3fbd535SBarry Smith   PetscErrorCode   ierr;
398710315b6SLawrence Mitchell   PetscInt         levels,cycles;
3992134b1e4SBarry Smith   PetscBool        flg;
400f3fbd535SBarry Smith   PC_MG            *mg = (PC_MG*)pc->data;
4013d3eaba7SBarry Smith   PC_MG_Levels     **mglevels;
402f3fbd535SBarry Smith   PCMGType         mgtype;
403f3fbd535SBarry Smith   PCMGCycleType    mgctype;
4042134b1e4SBarry Smith   PCMGGalerkinType gtype;
405f3fbd535SBarry Smith 
406f3fbd535SBarry Smith   PetscFunctionBegin;
4071d743356SStefano Zampini   levels = PetscMax(mg->nlevels,1);
408e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"Multigrid options");CHKERRQ(ierr);
409f3fbd535SBarry Smith   ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr);
4101a97d7b6SStefano Zampini   if (!flg && !mg->levels && pc->dm) {
411eb3f98d2SBarry Smith     ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
412eb3f98d2SBarry Smith     levels++;
4133aeaf226SBarry Smith     mg->usedmfornumberoflevels = PETSC_TRUE;
414eb3f98d2SBarry Smith   }
4150298fd71SBarry Smith   ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
4163aeaf226SBarry Smith   mglevels = mg->levels;
4173aeaf226SBarry Smith 
418f3fbd535SBarry Smith   mgctype = (PCMGCycleType) mglevels[0]->cycles;
419f3fbd535SBarry Smith   ierr    = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
420f3fbd535SBarry Smith   if (flg) {
421f3fbd535SBarry Smith     ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr);
4222fa5cd67SKarl Rupp   }
4232134b1e4SBarry Smith   gtype = mg->galerkin;
4242134b1e4SBarry Smith   ierr = PetscOptionsEnum("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",PCMGGalerkinTypes,(PetscEnum)gtype,(PetscEnum*)&gtype,&flg);CHKERRQ(ierr);
4252134b1e4SBarry Smith   if (flg) {
4262134b1e4SBarry Smith     ierr = PCMGSetGalerkin(pc,gtype);CHKERRQ(ierr);
427f3fbd535SBarry Smith   }
428f56b1265SBarry Smith   flg = PETSC_FALSE;
429f442ab6aSBarry Smith   ierr = PetscOptionsBool("-pc_mg_distinct_smoothup","Create seperate smoothup KSP and append the prefix _up","PCMGSetDistinctSmoothUp",PETSC_FALSE,&flg,NULL);CHKERRQ(ierr);
430f442ab6aSBarry Smith   if (flg) {
431f442ab6aSBarry Smith     ierr = PCMGSetDistinctSmoothUp(pc);CHKERRQ(ierr);
432f442ab6aSBarry Smith   }
43331567311SBarry Smith   mgtype = mg->am;
434f3fbd535SBarry Smith   ierr   = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr);
435f3fbd535SBarry Smith   if (flg) {
436f3fbd535SBarry Smith     ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
437f3fbd535SBarry Smith   }
43831567311SBarry Smith   if (mg->am == PC_MG_MULTIPLICATIVE) {
4395363c1e0SLisandro Dalcin     ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGMultiplicativeSetCycles",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr);
440f3fbd535SBarry Smith     if (flg) {
441f3fbd535SBarry Smith       ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr);
442f3fbd535SBarry Smith     }
443f3fbd535SBarry Smith   }
444f3fbd535SBarry Smith   flg  = PETSC_FALSE;
4450298fd71SBarry Smith   ierr = PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL);CHKERRQ(ierr);
446f3fbd535SBarry Smith   if (flg) {
447f3fbd535SBarry Smith     PetscInt i;
448f3fbd535SBarry Smith     char     eventname[128];
4491a97d7b6SStefano Zampini 
450f3fbd535SBarry Smith     levels = mglevels[0]->levels;
451f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
452f3fbd535SBarry Smith       sprintf(eventname,"MGSetup Level %d",(int)i);
45363e6d426SJed Brown       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup);CHKERRQ(ierr);
454f3fbd535SBarry Smith       sprintf(eventname,"MGSmooth Level %d",(int)i);
45563e6d426SJed Brown       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve);CHKERRQ(ierr);
456f3fbd535SBarry Smith       if (i) {
457f3fbd535SBarry Smith         sprintf(eventname,"MGResid Level %d",(int)i);
45863e6d426SJed Brown         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual);CHKERRQ(ierr);
459f3fbd535SBarry Smith         sprintf(eventname,"MGInterp Level %d",(int)i);
46063e6d426SJed Brown         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict);CHKERRQ(ierr);
461f3fbd535SBarry Smith       }
462f3fbd535SBarry Smith     }
463eec35531SMatthew G Knepley 
464ec60ca73SSatish Balay #if defined(PETSC_USE_LOG)
465eec35531SMatthew G Knepley     {
466eec35531SMatthew G Knepley       const char    *sname = "MG Apply";
467eec35531SMatthew G Knepley       PetscStageLog stageLog;
468eec35531SMatthew G Knepley       PetscInt      st;
469eec35531SMatthew G Knepley 
470eec35531SMatthew G Knepley       ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
471eec35531SMatthew G Knepley       for (st = 0; st < stageLog->numStages; ++st) {
472eec35531SMatthew G Knepley         PetscBool same;
473eec35531SMatthew G Knepley 
474eec35531SMatthew G Knepley         ierr = PetscStrcmp(stageLog->stageInfo[st].name, sname, &same);CHKERRQ(ierr);
4752fa5cd67SKarl Rupp         if (same) mg->stageApply = st;
476eec35531SMatthew G Knepley       }
477eec35531SMatthew G Knepley       if (!mg->stageApply) {
478eec35531SMatthew G Knepley         ierr = PetscLogStageRegister(sname, &mg->stageApply);CHKERRQ(ierr);
479eec35531SMatthew G Knepley       }
480eec35531SMatthew G Knepley     }
481ec60ca73SSatish Balay #endif
482f3fbd535SBarry Smith   }
483f3fbd535SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
484f3fbd535SBarry Smith   PetscFunctionReturn(0);
485f3fbd535SBarry Smith }
486f3fbd535SBarry Smith 
4876a6fc655SJed Brown const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
4886a6fc655SJed Brown const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
4892134b1e4SBarry Smith const char *const PCMGGalerkinTypes[] = {"both","pmat","mat","none","external","PCMGGalerkinType","PC_MG_GALERKIN",0};
490f3fbd535SBarry Smith 
4919804daf3SBarry Smith #include <petscdraw.h>
492f3fbd535SBarry Smith PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
493f3fbd535SBarry Smith {
494f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
495f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
496f3fbd535SBarry Smith   PetscErrorCode ierr;
497e3deeeafSJed Brown   PetscInt       levels = mglevels ? mglevels[0]->levels : 0,i;
498219b1045SBarry Smith   PetscBool      iascii,isbinary,isdraw;
499f3fbd535SBarry Smith 
500f3fbd535SBarry Smith   PetscFunctionBegin;
501251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
5025b0b0462SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
503219b1045SBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
504f3fbd535SBarry Smith   if (iascii) {
505e3deeeafSJed Brown     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
506efd4aadfSBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename);CHKERRQ(ierr);
50731567311SBarry Smith     if (mg->am == PC_MG_MULTIPLICATIVE) {
50831567311SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr);
509f3fbd535SBarry Smith     }
5102134b1e4SBarry Smith     if (mg->galerkin == PC_MG_GALERKIN_BOTH) {
511f3fbd535SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
5122134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_PMAT) {
5132134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for pmat\n");CHKERRQ(ierr);
5142134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_MAT) {
5152134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices for mat\n");CHKERRQ(ierr);
5162134b1e4SBarry Smith     } else if (mg->galerkin == PC_MG_GALERKIN_EXTERNAL) {
5172134b1e4SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Using externally compute Galerkin coarse grid matrices\n");CHKERRQ(ierr);
5184f66f45eSBarry Smith     } else {
5194f66f45eSBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
520f3fbd535SBarry Smith     }
5215adeb434SBarry Smith     if (mg->view){
5225adeb434SBarry Smith       ierr = (*mg->view)(pc,viewer);CHKERRQ(ierr);
5235adeb434SBarry Smith     }
524f3fbd535SBarry Smith     for (i=0; i<levels; i++) {
525f3fbd535SBarry Smith       if (!i) {
52689cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i);CHKERRQ(ierr);
527f3fbd535SBarry Smith       } else {
52889cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
529f3fbd535SBarry Smith       }
530f3fbd535SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
531f3fbd535SBarry Smith       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
532f3fbd535SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
533f3fbd535SBarry Smith       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
534f3fbd535SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
535f3fbd535SBarry Smith       } else if (i) {
53689cce641SBarry Smith         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
537f3fbd535SBarry Smith         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
538f3fbd535SBarry Smith         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
539f3fbd535SBarry Smith         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
540f3fbd535SBarry Smith       }
541f3fbd535SBarry Smith     }
5425b0b0462SBarry Smith   } else if (isbinary) {
5435b0b0462SBarry Smith     for (i=levels-1; i>=0; i--) {
5445b0b0462SBarry Smith       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
5455b0b0462SBarry Smith       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) {
5465b0b0462SBarry Smith         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
5475b0b0462SBarry Smith       }
5485b0b0462SBarry Smith     }
549219b1045SBarry Smith   } else if (isdraw) {
550219b1045SBarry Smith     PetscDraw draw;
551b4375e8dSPeter Brune     PetscReal x,w,y,bottom,th;
552219b1045SBarry Smith     ierr   = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
553219b1045SBarry Smith     ierr   = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
5540298fd71SBarry Smith     ierr   = PetscDrawStringGetSize(draw,NULL,&th);CHKERRQ(ierr);
555219b1045SBarry Smith     bottom = y - th;
556219b1045SBarry Smith     for (i=levels-1; i>=0; i--) {
557b4375e8dSPeter Brune       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
558219b1045SBarry Smith         ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
559219b1045SBarry Smith         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
560219b1045SBarry Smith         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
561b4375e8dSPeter Brune       } else {
562b4375e8dSPeter Brune         w    = 0.5*PetscMin(1.0-x,x);
563b4375e8dSPeter Brune         ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr);
564b4375e8dSPeter Brune         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
565b4375e8dSPeter Brune         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
566b4375e8dSPeter Brune         ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr);
567b4375e8dSPeter Brune         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
568b4375e8dSPeter Brune         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
569b4375e8dSPeter Brune       }
5700298fd71SBarry Smith       ierr    = PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL);CHKERRQ(ierr);
5711cd381d6SBarry Smith       bottom -= th;
572219b1045SBarry Smith     }
5735b0b0462SBarry Smith   }
574f3fbd535SBarry Smith   PetscFunctionReturn(0);
575f3fbd535SBarry Smith }
576f3fbd535SBarry Smith 
577af0996ceSBarry Smith #include <petsc/private/dmimpl.h>
578af0996ceSBarry Smith #include <petsc/private/kspimpl.h>
579cab2e9ccSBarry Smith 
580f3fbd535SBarry Smith /*
581f3fbd535SBarry Smith     Calls setup for the KSP on each level
582f3fbd535SBarry Smith */
583f3fbd535SBarry Smith PetscErrorCode PCSetUp_MG(PC pc)
584f3fbd535SBarry Smith {
585f3fbd535SBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
586f3fbd535SBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
587f3fbd535SBarry Smith   PetscErrorCode ierr;
5881a97d7b6SStefano Zampini   PetscInt       i,n;
58998e04984SBarry Smith   PC             cpc;
5903db492dfSBarry Smith   PetscBool      dump = PETSC_FALSE,opsset,use_amat,missinginterpolate = PETSC_FALSE;
591f3fbd535SBarry Smith   Mat            dA,dB;
592f3fbd535SBarry Smith   Vec            tvec;
593218a07d4SBarry Smith   DM             *dms;
594649052a6SBarry Smith   PetscViewer    viewer = 0;
5952134b1e4SBarry Smith   PetscBool      dAeqdB = PETSC_FALSE, needRestricts = PETSC_FALSE;
596f3fbd535SBarry Smith 
597f3fbd535SBarry Smith   PetscFunctionBegin;
5981a97d7b6SStefano Zampini   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels with PCMGSetLevels() before setting up");
5991a97d7b6SStefano Zampini   n = mglevels[0]->levels;
60001bc414fSDmitry Karpeev   /* FIX: Move this to PCSetFromOptions_MG? */
6013aeaf226SBarry Smith   if (mg->usedmfornumberoflevels) {
6023aeaf226SBarry Smith     PetscInt levels;
6033aeaf226SBarry Smith     ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
6043aeaf226SBarry Smith     levels++;
6053aeaf226SBarry Smith     if (levels > n) { /* the problem is now being solved on a finer grid */
6060298fd71SBarry Smith       ierr     = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
6073aeaf226SBarry Smith       n        = levels;
6083aeaf226SBarry Smith       ierr     = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
6093aeaf226SBarry Smith       mglevels =  mg->levels;
6103aeaf226SBarry Smith     }
6113aeaf226SBarry Smith   }
61298e04984SBarry Smith   ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr);
6133aeaf226SBarry Smith 
614f3fbd535SBarry Smith 
615f3fbd535SBarry Smith   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
616f3fbd535SBarry Smith   /* so use those from global PC */
617f3fbd535SBarry Smith   /* Is this what we always want? What if user wants to keep old one? */
6180298fd71SBarry Smith   ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr);
61998e04984SBarry Smith   if (opsset) {
62098e04984SBarry Smith     Mat mmat;
62123ee1639SBarry Smith     ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat);CHKERRQ(ierr);
62298e04984SBarry Smith     if (mmat == pc->pmat) opsset = PETSC_FALSE;
62398e04984SBarry Smith   }
6244a5f07a5SMark F. Adams 
6254a5f07a5SMark F. Adams   if (!opsset) {
62671b23a65SMark F. Adams     ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr);
6274a5f07a5SMark F. Adams     if(use_amat){
628f3fbd535SBarry Smith       ierr = PetscInfo(pc,"Using outer operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr);
62923ee1639SBarry Smith       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat);CHKERRQ(ierr);
630f3fbd535SBarry Smith     }
6314a5f07a5SMark F. Adams     else {
6324a5f07a5SMark F. Adams       ierr = PetscInfo(pc,"Using matrix (pmat) operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");CHKERRQ(ierr);
63323ee1639SBarry Smith       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat);CHKERRQ(ierr);
6344a5f07a5SMark F. Adams     }
6354a5f07a5SMark F. Adams   }
636f3fbd535SBarry Smith 
6379c7ffb39SBarry Smith   for (i=n-1; i>0; i--) {
6389c7ffb39SBarry Smith     if (!(mglevels[i]->interpolate || mglevels[i]->restrct)) {
6399c7ffb39SBarry Smith       missinginterpolate = PETSC_TRUE;
6409c7ffb39SBarry Smith       continue;
6419c7ffb39SBarry Smith     }
6429c7ffb39SBarry Smith   }
6432134b1e4SBarry Smith 
6442134b1e4SBarry Smith   ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB);CHKERRQ(ierr);
6452134b1e4SBarry Smith   if (dA == dB) dAeqdB = PETSC_TRUE;
6462134b1e4SBarry Smith   if ((mg->galerkin == PC_MG_GALERKIN_NONE) || (((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_MAT)) && !dAeqdB)) {
6472134b1e4SBarry Smith     needRestricts = PETSC_TRUE;  /* user must compute either mat, pmat, or both so must restrict x to coarser levels */
6482134b1e4SBarry Smith   }
6492134b1e4SBarry Smith 
6502134b1e4SBarry Smith 
6519c7ffb39SBarry Smith   /*
6529c7ffb39SBarry Smith    Skipping if user has provided all interpolation/restriction needed (since DM might not be able to produce them (when coming from SNES/TS)
6539c7ffb39SBarry Smith    Skipping for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs?
6549c7ffb39SBarry Smith   */
6552134b1e4SBarry Smith   if (missinginterpolate && pc->dm && mg->galerkin != PC_MG_GALERKIN_EXTERNAL && !pc->setupcalled) {
6562d2b81a6SBarry Smith 	/* construct the interpolation from the DMs */
6572e499ae9SBarry Smith     Mat p;
65873250ac0SBarry Smith     Vec rscale;
659785e854fSJed Brown     ierr     = PetscMalloc1(n,&dms);CHKERRQ(ierr);
660218a07d4SBarry Smith     dms[n-1] = pc->dm;
661ef1267afSMatthew G. Knepley     /* Separately create them so we do not get DMKSP interference between levels */
662ef1267afSMatthew G. Knepley     for (i=n-2; i>-1; i--) {ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr);}
66341fce8fdSHong Zhang 	/*
66441fce8fdSHong Zhang 	   Force the mat type of coarse level operator to be AIJ because usually we want to use LU for coarse level.
66541fce8fdSHong Zhang 	   Notice that it can be overwritten by -mat_type because KSPSetUp() reads command line options.
66641fce8fdSHong Zhang 	   But it is safe to use -dm_mat_type.
66741fce8fdSHong Zhang 
66841fce8fdSHong Zhang 	   The mat type should not be hardcoded like this, we need to find a better way.
66941fce8fdSHong Zhang     ierr = DMSetMatType(dms[0],MATAIJ);CHKERRQ(ierr);
67041fce8fdSHong Zhang     */
671218a07d4SBarry Smith     for (i=n-2; i>-1; i--) {
672942e3340SBarry Smith       DMKSP     kdm;
673eab52d2bSLawrence Mitchell       PetscBool dmhasrestrict, dmhasinject;
6743c0c59f3SBarry Smith       ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr);
6752134b1e4SBarry Smith       if (!needRestricts) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);}
676942e3340SBarry Smith       ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr);
677d1a3e677SJed Brown       /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
678d1a3e677SJed Brown        * a bitwise OR of computing the matrix, RHS, and initial iterate. */
6790298fd71SBarry Smith       kdm->ops->computerhs = NULL;
6800298fd71SBarry Smith       kdm->rhsctx          = NULL;
68124c3aa18SBarry Smith       if (!mglevels[i+1]->interpolate) {
682e727c939SJed Brown         ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr);
6832d2b81a6SBarry Smith         ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr);
68400ac8be1SBarry Smith         if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);}
68573250ac0SBarry Smith         ierr = VecDestroy(&rscale);CHKERRQ(ierr);
6866bf464f9SBarry Smith         ierr = MatDestroy(&p);CHKERRQ(ierr);
687218a07d4SBarry Smith       }
6883ad4599aSBarry Smith       ierr = DMHasCreateRestriction(dms[i],&dmhasrestrict);CHKERRQ(ierr);
6893ad4599aSBarry Smith       if (dmhasrestrict && !mglevels[i+1]->restrct){
6903ad4599aSBarry Smith         ierr = DMCreateRestriction(dms[i],dms[i+1],&p);CHKERRQ(ierr);
6913ad4599aSBarry Smith         ierr = PCMGSetRestriction(pc,i+1,p);CHKERRQ(ierr);
6923ad4599aSBarry Smith         ierr = MatDestroy(&p);CHKERRQ(ierr);
6933ad4599aSBarry Smith       }
694eab52d2bSLawrence Mitchell       ierr = DMHasCreateInjection(dms[i],&dmhasinject);CHKERRQ(ierr);
695eab52d2bSLawrence Mitchell       if (dmhasinject && !mglevels[i+1]->inject){
696eab52d2bSLawrence Mitchell         ierr = DMCreateInjection(dms[i],dms[i+1],&p);CHKERRQ(ierr);
697eab52d2bSLawrence Mitchell         ierr = PCMGSetInjection(pc,i+1,p);CHKERRQ(ierr);
698eab52d2bSLawrence Mitchell         ierr = MatDestroy(&p);CHKERRQ(ierr);
699eab52d2bSLawrence Mitchell       }
70024c3aa18SBarry Smith     }
7012d2b81a6SBarry Smith 
702ef1267afSMatthew G. Knepley     for (i=n-2; i>-1; i--) {ierr = DMDestroy(&dms[i]);CHKERRQ(ierr);}
7032d2b81a6SBarry Smith     ierr = PetscFree(dms);CHKERRQ(ierr);
704ce4cda84SJed Brown   }
705cab2e9ccSBarry Smith 
706ce4cda84SJed Brown   if (pc->dm && !pc->setupcalled) {
7072134b1e4SBarry Smith     /* finest smoother also gets DM but it is not active, independent of whether galerkin==PC_MG_GALERKIN_EXTERNAL */
708cab2e9ccSBarry Smith     ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr);
709cab2e9ccSBarry Smith     ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr);
710218a07d4SBarry Smith   }
711218a07d4SBarry Smith 
7122134b1e4SBarry Smith   if (mg->galerkin < PC_MG_GALERKIN_NONE) {
7132134b1e4SBarry Smith     Mat       A,B;
7142134b1e4SBarry Smith     PetscBool doA = PETSC_FALSE,doB = PETSC_FALSE;
7152134b1e4SBarry Smith     MatReuse  reuse = MAT_INITIAL_MATRIX;
7162134b1e4SBarry Smith 
7172134b1e4SBarry Smith     if ((mg->galerkin == PC_MG_GALERKIN_PMAT) || (mg->galerkin == PC_MG_GALERKIN_BOTH)) doB = PETSC_TRUE;
7182134b1e4SBarry Smith     if ((mg->galerkin == PC_MG_GALERKIN_MAT) || ((mg->galerkin == PC_MG_GALERKIN_BOTH) && (dA != dB))) doA = PETSC_TRUE;
7192134b1e4SBarry Smith     if (pc->setupcalled) reuse = MAT_REUSE_MATRIX;
720f3fbd535SBarry Smith     for (i=n-2; i>-1; i--) {
721b9367914SBarry Smith       if (!mglevels[i+1]->restrct && !mglevels[i+1]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must provide interpolation or restriction for each MG level except level 0");
722b9367914SBarry Smith       if (!mglevels[i+1]->interpolate) {
723b9367914SBarry Smith         ierr = PCMGSetInterpolation(pc,i+1,mglevels[i+1]->restrct);CHKERRQ(ierr);
724b9367914SBarry Smith       }
725b9367914SBarry Smith       if (!mglevels[i+1]->restrct) {
726b9367914SBarry Smith         ierr = PCMGSetRestriction(pc,i+1,mglevels[i+1]->interpolate);CHKERRQ(ierr);
727b9367914SBarry Smith       }
7282134b1e4SBarry Smith       if (reuse == MAT_REUSE_MATRIX) {
7292134b1e4SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&A,&B);CHKERRQ(ierr);
7302134b1e4SBarry Smith       }
7312134b1e4SBarry Smith       if (doA) {
7322df6c5c3SPatrick Farrell         ierr = MatGalerkin(mglevels[i+1]->restrct,dA,mglevels[i+1]->interpolate,reuse,1.0,&A);CHKERRQ(ierr);
7332134b1e4SBarry Smith       }
7342134b1e4SBarry Smith       if (doB) {
7352df6c5c3SPatrick Farrell         ierr = MatGalerkin(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,reuse,1.0,&B);CHKERRQ(ierr);
736b9367914SBarry Smith       }
7372134b1e4SBarry Smith       /* the management of the PetscObjectReference() and PetscObjecDereference() below is rather delicate */
7382134b1e4SBarry Smith       if (!doA && dAeqdB) {
7392134b1e4SBarry Smith         if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);}
7402134b1e4SBarry Smith         A = B;
7412134b1e4SBarry Smith       } else if (!doA && reuse == MAT_INITIAL_MATRIX ) {
7422134b1e4SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&A,NULL);CHKERRQ(ierr);
7432134b1e4SBarry Smith         ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
744b9367914SBarry Smith       }
7452134b1e4SBarry Smith       if (!doB && dAeqdB) {
7462134b1e4SBarry Smith         if (reuse == MAT_INITIAL_MATRIX) {ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);}
7472134b1e4SBarry Smith         B = A;
7482134b1e4SBarry Smith       } else if (!doB && reuse == MAT_INITIAL_MATRIX) {
74923ee1639SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B);CHKERRQ(ierr);
7502134b1e4SBarry Smith         ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
7517d537d92SJed Brown       }
7522134b1e4SBarry Smith       if (reuse == MAT_INITIAL_MATRIX) {
7532134b1e4SBarry Smith         ierr = KSPSetOperators(mglevels[i]->smoothd,A,B);CHKERRQ(ierr);
7542134b1e4SBarry Smith         ierr = PetscObjectDereference((PetscObject)A);CHKERRQ(ierr);
7552134b1e4SBarry Smith         ierr = PetscObjectDereference((PetscObject)B);CHKERRQ(ierr);
7562134b1e4SBarry Smith       }
7572134b1e4SBarry Smith       dA = A;
758f3fbd535SBarry Smith       dB = B;
759f3fbd535SBarry Smith     }
760f3fbd535SBarry Smith   }
7612134b1e4SBarry Smith   if (needRestricts && pc->dm && pc->dm->x) {
762cab2e9ccSBarry Smith     /* need to restrict Jacobian location to coarser meshes for evaluation */
763cab2e9ccSBarry Smith     for (i=n-2; i>-1; i--) {
764c88c5224SJed Brown       Mat R;
765c88c5224SJed Brown       Vec rscale;
766cab2e9ccSBarry Smith       if (!mglevels[i]->smoothd->dm->x) {
767cab2e9ccSBarry Smith         Vec *vecs;
7682a7a6963SBarry Smith         ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr);
769cab2e9ccSBarry Smith         mglevels[i]->smoothd->dm->x = vecs[0];
770cab2e9ccSBarry Smith         ierr = PetscFree(vecs);CHKERRQ(ierr);
771cab2e9ccSBarry Smith       }
772c88c5224SJed Brown       ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr);
773c88c5224SJed Brown       ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
774c88c5224SJed Brown       ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr);
775c88c5224SJed Brown       ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr);
776cab2e9ccSBarry Smith     }
777f3fbd535SBarry Smith   }
7782134b1e4SBarry Smith   if (needRestricts && pc->dm) {
779caa4e7f2SJed Brown     for (i=n-2; i>=0; i--) {
780ccceb50cSJed Brown       DM  dmfine,dmcoarse;
781caa4e7f2SJed Brown       Mat Restrict,Inject;
782caa4e7f2SJed Brown       Vec rscale;
783ccceb50cSJed Brown       ierr   = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr);
784ccceb50cSJed Brown       ierr   = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr);
785caa4e7f2SJed Brown       ierr   = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr);
786caa4e7f2SJed Brown       ierr   = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
787eab52d2bSLawrence Mitchell       ierr   = PCMGGetInjection(pc,i+1,&Inject);CHKERRQ(ierr);
788caa4e7f2SJed Brown       ierr   = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr);
789caa4e7f2SJed Brown     }
790caa4e7f2SJed Brown   }
791f3fbd535SBarry Smith 
792f3fbd535SBarry Smith   if (!pc->setupcalled) {
793f3fbd535SBarry Smith     for (i=0; i<n; i++) {
794f3fbd535SBarry Smith       ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr);
795f3fbd535SBarry Smith     }
796f3fbd535SBarry Smith     for (i=1; i<n; i++) {
797f3fbd535SBarry Smith       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
798f3fbd535SBarry Smith         ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr);
799f3fbd535SBarry Smith       }
800f3fbd535SBarry Smith     }
8013ad4599aSBarry Smith     /* insure that if either interpolation or restriction is set the other other one is set */
802f3fbd535SBarry Smith     for (i=1; i<n; i++) {
8033ad4599aSBarry Smith       ierr = PCMGGetInterpolation(pc,i,NULL);CHKERRQ(ierr);
8043ad4599aSBarry Smith       ierr = PCMGGetRestriction(pc,i,NULL);CHKERRQ(ierr);
805f3fbd535SBarry Smith     }
806f3fbd535SBarry Smith     for (i=0; i<n-1; i++) {
807f3fbd535SBarry Smith       if (!mglevels[i]->b) {
808f3fbd535SBarry Smith         Vec *vec;
8092a7a6963SBarry Smith         ierr = KSPCreateVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
810f3fbd535SBarry Smith         ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr);
8116bf464f9SBarry Smith         ierr = VecDestroy(vec);CHKERRQ(ierr);
812f3fbd535SBarry Smith         ierr = PetscFree(vec);CHKERRQ(ierr);
813f3fbd535SBarry Smith       }
814f3fbd535SBarry Smith       if (!mglevels[i]->r && i) {
815f3fbd535SBarry Smith         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
816f3fbd535SBarry Smith         ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr);
8176bf464f9SBarry Smith         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
818f3fbd535SBarry Smith       }
819f3fbd535SBarry Smith       if (!mglevels[i]->x) {
820f3fbd535SBarry Smith         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
821f3fbd535SBarry Smith         ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr);
8226bf464f9SBarry Smith         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
823f3fbd535SBarry Smith       }
824f3fbd535SBarry Smith     }
825f3fbd535SBarry Smith     if (n != 1 && !mglevels[n-1]->r) {
826f3fbd535SBarry Smith       /* PCMGSetR() on the finest level if user did not supply it */
827f3fbd535SBarry Smith       Vec *vec;
8282a7a6963SBarry Smith       ierr = KSPCreateVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
829f3fbd535SBarry Smith       ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr);
8306bf464f9SBarry Smith       ierr = VecDestroy(vec);CHKERRQ(ierr);
831f3fbd535SBarry Smith       ierr = PetscFree(vec);CHKERRQ(ierr);
832f3fbd535SBarry Smith     }
833f3fbd535SBarry Smith   }
834f3fbd535SBarry Smith 
83598e04984SBarry Smith   if (pc->dm) {
83698e04984SBarry Smith     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
83798e04984SBarry Smith     for (i=0; i<n-1; i++) {
83898e04984SBarry Smith       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
83998e04984SBarry Smith     }
84098e04984SBarry Smith   }
841f3fbd535SBarry Smith 
842f3fbd535SBarry Smith   for (i=1; i<n; i++) {
8432a21e185SBarry Smith     if (mglevels[i]->smoothu == mglevels[i]->smoothd || mg->am == PC_MG_FULL || mg->am == PC_MG_KASKADE || mg->cyclesperpcapply > 1){
844f3fbd535SBarry Smith       /* if doing only down then initial guess is zero */
845f3fbd535SBarry Smith       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
846f3fbd535SBarry Smith     }
84763e6d426SJed Brown     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
848f3fbd535SBarry Smith     ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr);
849899639b0SHong Zhang     if (mglevels[i]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) {
850899639b0SHong Zhang       pc->failedreason = PC_SUBPC_ERROR;
851899639b0SHong Zhang     }
85263e6d426SJed Brown     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
853d42688cbSBarry Smith     if (!mglevels[i]->residual) {
854d42688cbSBarry Smith       Mat mat;
85513842ffbSBarry Smith       ierr = KSPGetOperators(mglevels[i]->smoothd,&mat,NULL);CHKERRQ(ierr);
85654b2cd4bSJed Brown       ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr);
857d42688cbSBarry Smith     }
858f3fbd535SBarry Smith   }
859f3fbd535SBarry Smith   for (i=1; i<n; i++) {
860f3fbd535SBarry Smith     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
861f3fbd535SBarry Smith       Mat downmat,downpmat;
862f3fbd535SBarry Smith 
863f3fbd535SBarry Smith       /* check if operators have been set for up, if not use down operators to set them */
8640298fd71SBarry Smith       ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr);
865f3fbd535SBarry Smith       if (!opsset) {
86623ee1639SBarry Smith         ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr);
86723ee1639SBarry Smith         ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr);
868f3fbd535SBarry Smith       }
869f3fbd535SBarry Smith 
870f3fbd535SBarry Smith       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr);
87163e6d426SJed Brown       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
872f3fbd535SBarry Smith       ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr);
873899639b0SHong Zhang       if (mglevels[i]->smoothu->reason == KSP_DIVERGED_PCSETUP_FAILED) {
874899639b0SHong Zhang         pc->failedreason = PC_SUBPC_ERROR;
875899639b0SHong Zhang       }
87663e6d426SJed Brown       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
877f3fbd535SBarry Smith     }
878f3fbd535SBarry Smith   }
879f3fbd535SBarry Smith 
88063e6d426SJed Brown   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
881f3fbd535SBarry Smith   ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr);
882899639b0SHong Zhang   if (mglevels[0]->smoothd->reason == KSP_DIVERGED_PCSETUP_FAILED) {
883899639b0SHong Zhang     pc->failedreason = PC_SUBPC_ERROR;
884899639b0SHong Zhang   }
88563e6d426SJed Brown   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
886f3fbd535SBarry Smith 
887f3fbd535SBarry Smith   /*
888f3fbd535SBarry Smith      Dump the interpolation/restriction matrices plus the
889e3c5b3baSBarry Smith    Jacobian/stiffness on each level. This allows MATLAB users to
890f3fbd535SBarry Smith    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
891f3fbd535SBarry Smith 
892f3fbd535SBarry Smith    Only support one or the other at the same time.
893f3fbd535SBarry Smith   */
894f3fbd535SBarry Smith #if defined(PETSC_USE_SOCKET_VIEWER)
895c5929fdfSBarry Smith   ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr);
896ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
897f3fbd535SBarry Smith   dump = PETSC_FALSE;
898f3fbd535SBarry Smith #endif
899c5929fdfSBarry Smith   ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr);
900ce94432eSBarry Smith   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
901f3fbd535SBarry Smith 
902f3fbd535SBarry Smith   if (viewer) {
903f3fbd535SBarry Smith     for (i=1; i<n; i++) {
904f3fbd535SBarry Smith       ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr);
905f3fbd535SBarry Smith     }
906f3fbd535SBarry Smith     for (i=0; i<n; i++) {
907f3fbd535SBarry Smith       ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr);
908f3fbd535SBarry Smith       ierr = MatView(pc->mat,viewer);CHKERRQ(ierr);
909f3fbd535SBarry Smith     }
910f3fbd535SBarry Smith   }
911f3fbd535SBarry Smith   PetscFunctionReturn(0);
912f3fbd535SBarry Smith }
913f3fbd535SBarry Smith 
914f3fbd535SBarry Smith /* -------------------------------------------------------------------------------------*/
915f3fbd535SBarry Smith 
9164b9ad928SBarry Smith /*@
91797177400SBarry Smith    PCMGGetLevels - Gets the number of levels to use with MG.
9184b9ad928SBarry Smith 
9194b9ad928SBarry Smith    Not Collective
9204b9ad928SBarry Smith 
9214b9ad928SBarry Smith    Input Parameter:
9224b9ad928SBarry Smith .  pc - the preconditioner context
9234b9ad928SBarry Smith 
9244b9ad928SBarry Smith    Output parameter:
9254b9ad928SBarry Smith .  levels - the number of levels
9264b9ad928SBarry Smith 
9274b9ad928SBarry Smith    Level: advanced
9284b9ad928SBarry Smith 
9294b9ad928SBarry Smith .keywords: MG, get, levels, multigrid
9304b9ad928SBarry Smith 
93197177400SBarry Smith .seealso: PCMGSetLevels()
9324b9ad928SBarry Smith @*/
9337087cfbeSBarry Smith PetscErrorCode  PCMGGetLevels(PC pc,PetscInt *levels)
9344b9ad928SBarry Smith {
935f3fbd535SBarry Smith   PC_MG         *mg = (PC_MG*)pc->data;
936*e952c529SMatthew G. Knepley   PetscBool      ismg;
937*e952c529SMatthew G. Knepley   PetscErrorCode ierr;
9384b9ad928SBarry Smith 
9394b9ad928SBarry Smith   PetscFunctionBegin;
9400700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
9414482741eSBarry Smith   PetscValidIntPointer(levels,2);
942*e952c529SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) pc, PCMG, &ismg);CHKERRQ(ierr);
943*e952c529SMatthew G. Knepley   if (ismg) {*levels = mg->nlevels;}
944*e952c529SMatthew G. Knepley   else      {*levels = 0;}
9454b9ad928SBarry Smith   PetscFunctionReturn(0);
9464b9ad928SBarry Smith }
9474b9ad928SBarry Smith 
9484b9ad928SBarry Smith /*@
94997177400SBarry Smith    PCMGSetType - Determines the form of multigrid to use:
9504b9ad928SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
9514b9ad928SBarry Smith 
952ad4df100SBarry Smith    Logically Collective on PC
9534b9ad928SBarry Smith 
9544b9ad928SBarry Smith    Input Parameters:
9554b9ad928SBarry Smith +  pc - the preconditioner context
9569dcbbd2bSBarry Smith -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
9579dcbbd2bSBarry Smith    PC_MG_FULL, PC_MG_KASKADE
9584b9ad928SBarry Smith 
9594b9ad928SBarry Smith    Options Database Key:
9604b9ad928SBarry Smith .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
9614b9ad928SBarry Smith    additive, full, kaskade
9624b9ad928SBarry Smith 
9634b9ad928SBarry Smith    Level: advanced
9644b9ad928SBarry Smith 
9654b9ad928SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
9664b9ad928SBarry Smith 
96797177400SBarry Smith .seealso: PCMGSetLevels()
9684b9ad928SBarry Smith @*/
9697087cfbeSBarry Smith PetscErrorCode  PCMGSetType(PC pc,PCMGType form)
9704b9ad928SBarry Smith {
971f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
9724b9ad928SBarry Smith 
9734b9ad928SBarry Smith   PetscFunctionBegin;
9740700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
975c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,form,2);
97631567311SBarry Smith   mg->am = form;
9779dcbbd2bSBarry Smith   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
978c60c7ad4SBarry Smith   else pc->ops->applyrichardson = NULL;
979c60c7ad4SBarry Smith   PetscFunctionReturn(0);
980c60c7ad4SBarry Smith }
981c60c7ad4SBarry Smith 
982c60c7ad4SBarry Smith /*@
983c60c7ad4SBarry Smith    PCMGGetType - Determines the form of multigrid to use:
984c60c7ad4SBarry Smith    multiplicative, additive, full, or the Kaskade algorithm.
985c60c7ad4SBarry Smith 
986c60c7ad4SBarry Smith    Logically Collective on PC
987c60c7ad4SBarry Smith 
988c60c7ad4SBarry Smith    Input Parameter:
989c60c7ad4SBarry Smith .  pc - the preconditioner context
990c60c7ad4SBarry Smith 
991c60c7ad4SBarry Smith    Output Parameter:
992c60c7ad4SBarry Smith .  type - one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,PC_MG_FULL, PC_MG_KASKADE
993c60c7ad4SBarry Smith 
994c60c7ad4SBarry Smith 
995c60c7ad4SBarry Smith    Level: advanced
996c60c7ad4SBarry Smith 
997c60c7ad4SBarry Smith .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
998c60c7ad4SBarry Smith 
999c60c7ad4SBarry Smith .seealso: PCMGSetLevels()
1000c60c7ad4SBarry Smith @*/
1001c60c7ad4SBarry Smith PetscErrorCode  PCMGGetType(PC pc,PCMGType *type)
1002c60c7ad4SBarry Smith {
1003c60c7ad4SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
1004c60c7ad4SBarry Smith 
1005c60c7ad4SBarry Smith   PetscFunctionBegin;
1006c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1007c60c7ad4SBarry Smith   *type = mg->am;
10084b9ad928SBarry Smith   PetscFunctionReturn(0);
10094b9ad928SBarry Smith }
10104b9ad928SBarry Smith 
10114b9ad928SBarry Smith /*@
10120d353602SBarry Smith    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
10134b9ad928SBarry Smith    complicated cycling.
10144b9ad928SBarry Smith 
1015ad4df100SBarry Smith    Logically Collective on PC
10164b9ad928SBarry Smith 
10174b9ad928SBarry Smith    Input Parameters:
1018c2be2410SBarry Smith +  pc - the multigrid context
1019c1cbb1deSBarry Smith -  n - either PC_MG_CYCLE_V or PC_MG_CYCLE_W
10204b9ad928SBarry Smith 
10214b9ad928SBarry Smith    Options Database Key:
1022c1cbb1deSBarry Smith .  -pc_mg_cycle_type <v,w> - provide the cycle desired
10234b9ad928SBarry Smith 
10244b9ad928SBarry Smith    Level: advanced
10254b9ad928SBarry Smith 
10264b9ad928SBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
10274b9ad928SBarry Smith 
10280d353602SBarry Smith .seealso: PCMGSetCycleTypeOnLevel()
10294b9ad928SBarry Smith @*/
10307087cfbeSBarry Smith PetscErrorCode  PCMGSetCycleType(PC pc,PCMGCycleType n)
10314b9ad928SBarry Smith {
1032f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
1033f3fbd535SBarry Smith   PC_MG_Levels **mglevels = mg->levels;
103479416396SBarry Smith   PetscInt     i,levels;
10354b9ad928SBarry Smith 
10364b9ad928SBarry Smith   PetscFunctionBegin;
10370700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
103869fbec6eSBarry Smith   PetscValidLogicalCollectiveEnum(pc,n,2);
10391a97d7b6SStefano Zampini   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
1040f3fbd535SBarry Smith   levels = mglevels[0]->levels;
10412fa5cd67SKarl Rupp   for (i=0; i<levels; i++) mglevels[i]->cycles = n;
10424b9ad928SBarry Smith   PetscFunctionReturn(0);
10434b9ad928SBarry Smith }
10444b9ad928SBarry Smith 
10458cc2d5dfSBarry Smith /*@
10468cc2d5dfSBarry Smith    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
10478cc2d5dfSBarry Smith          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
10488cc2d5dfSBarry Smith 
1049ad4df100SBarry Smith    Logically Collective on PC
10508cc2d5dfSBarry Smith 
10518cc2d5dfSBarry Smith    Input Parameters:
10528cc2d5dfSBarry Smith +  pc - the multigrid context
10538cc2d5dfSBarry Smith -  n - number of cycles (default is 1)
10548cc2d5dfSBarry Smith 
10558cc2d5dfSBarry Smith    Options Database Key:
1056e1bc860dSBarry Smith .  -pc_mg_multiplicative_cycles n
10578cc2d5dfSBarry Smith 
10588cc2d5dfSBarry Smith    Level: advanced
10598cc2d5dfSBarry Smith 
106095452b02SPatrick Sanan    Notes:
106195452b02SPatrick Sanan     This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
10628cc2d5dfSBarry Smith 
10638cc2d5dfSBarry Smith .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
10648cc2d5dfSBarry Smith 
10658cc2d5dfSBarry Smith .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
10668cc2d5dfSBarry Smith @*/
10677087cfbeSBarry Smith PetscErrorCode  PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
10688cc2d5dfSBarry Smith {
1069f3fbd535SBarry Smith   PC_MG        *mg        = (PC_MG*)pc->data;
10708cc2d5dfSBarry Smith 
10718cc2d5dfSBarry Smith   PetscFunctionBegin;
10720700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1073c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
10742a21e185SBarry Smith   mg->cyclesperpcapply = n;
10758cc2d5dfSBarry Smith   PetscFunctionReturn(0);
10768cc2d5dfSBarry Smith }
10778cc2d5dfSBarry Smith 
10782134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin_MG(PC pc,PCMGGalerkinType use)
1079fb15c04eSBarry Smith {
1080fb15c04eSBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
1081fb15c04eSBarry Smith 
1082fb15c04eSBarry Smith   PetscFunctionBegin;
10832134b1e4SBarry Smith   mg->galerkin = use;
1084fb15c04eSBarry Smith   PetscFunctionReturn(0);
1085fb15c04eSBarry Smith }
1086fb15c04eSBarry Smith 
1087c2be2410SBarry Smith /*@
108897177400SBarry Smith    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
108982b87d87SMatthew G. Knepley       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
1090c2be2410SBarry Smith 
1091ad4df100SBarry Smith    Logically Collective on PC
1092c2be2410SBarry Smith 
1093c2be2410SBarry Smith    Input Parameters:
1094c91913d3SJed Brown +  pc - the multigrid context
10952134b1e4SBarry Smith -  use - one of PC_MG_GALERKIN_BOTH,PC_MG_GALERKIN_PMAT,PC_MG_GALERKIN_MAT, or PC_MG_GALERKIN_NONE
1096c2be2410SBarry Smith 
1097c2be2410SBarry Smith    Options Database Key:
10982134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none>
1099c2be2410SBarry Smith 
1100c2be2410SBarry Smith    Level: intermediate
1101c2be2410SBarry Smith 
110295452b02SPatrick Sanan    Notes:
110395452b02SPatrick Sanan     Some codes that use PCMG such as PCGAMG use Galerkin internally while constructing the hierarchy and thus do not
11041c1aac46SBarry Smith      use the PCMG construction of the coarser grids.
11051c1aac46SBarry Smith 
1106c2be2410SBarry Smith .keywords: MG, set, Galerkin
1107c2be2410SBarry Smith 
11082134b1e4SBarry Smith .seealso: PCMGGetGalerkin(), PCMGGalerkinType
11093fc8bf9cSBarry Smith 
1110c2be2410SBarry Smith @*/
11112134b1e4SBarry Smith PetscErrorCode PCMGSetGalerkin(PC pc,PCMGGalerkinType use)
1112c2be2410SBarry Smith {
1113fb15c04eSBarry Smith   PetscErrorCode ierr;
1114c2be2410SBarry Smith 
1115c2be2410SBarry Smith   PetscFunctionBegin;
11160700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
11172134b1e4SBarry Smith   ierr = PetscTryMethod(pc,"PCMGSetGalerkin_C",(PC,PCMGGalerkinType),(pc,use));CHKERRQ(ierr);
1118c2be2410SBarry Smith   PetscFunctionReturn(0);
1119c2be2410SBarry Smith }
1120c2be2410SBarry Smith 
11213fc8bf9cSBarry Smith /*@
11223fc8bf9cSBarry Smith    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
112382b87d87SMatthew G. Knepley       A_i-1 = r_i * A_i * p_i
11243fc8bf9cSBarry Smith 
11253fc8bf9cSBarry Smith    Not Collective
11263fc8bf9cSBarry Smith 
11273fc8bf9cSBarry Smith    Input Parameter:
11283fc8bf9cSBarry Smith .  pc - the multigrid context
11293fc8bf9cSBarry Smith 
11303fc8bf9cSBarry Smith    Output Parameter:
11312134b1e4SBarry 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
11323fc8bf9cSBarry Smith 
11333fc8bf9cSBarry Smith    Level: intermediate
11343fc8bf9cSBarry Smith 
11353fc8bf9cSBarry Smith .keywords: MG, set, Galerkin
11363fc8bf9cSBarry Smith 
11372134b1e4SBarry Smith .seealso: PCMGSetGalerkin(), PCMGGalerkinType
11383fc8bf9cSBarry Smith 
11393fc8bf9cSBarry Smith @*/
11402134b1e4SBarry Smith PetscErrorCode  PCMGGetGalerkin(PC pc,PCMGGalerkinType  *galerkin)
11413fc8bf9cSBarry Smith {
1142f3fbd535SBarry Smith   PC_MG *mg = (PC_MG*)pc->data;
11433fc8bf9cSBarry Smith 
11443fc8bf9cSBarry Smith   PetscFunctionBegin;
11450700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
11462134b1e4SBarry Smith   *galerkin = mg->galerkin;
11473fc8bf9cSBarry Smith   PetscFunctionReturn(0);
11483fc8bf9cSBarry Smith }
11493fc8bf9cSBarry Smith 
11504b9ad928SBarry Smith /*@
115106792cafSBarry Smith    PCMGSetNumberSmooth - Sets the number of pre and post-smoothing steps to use
1152710315b6SLawrence Mitchell    on all levels.  Use PCMGDistinctSmoothUp() to create separate up and down smoothers if you want different numbers of
1153710315b6SLawrence Mitchell    pre- and post-smoothing steps.
115406792cafSBarry Smith 
115506792cafSBarry Smith    Logically Collective on PC
115606792cafSBarry Smith 
115706792cafSBarry Smith    Input Parameters:
115806792cafSBarry Smith +  mg - the multigrid context
115906792cafSBarry Smith -  n - the number of smoothing steps
116006792cafSBarry Smith 
116106792cafSBarry Smith    Options Database Key:
116206792cafSBarry Smith +  -mg_levels_ksp_max_it <n> - Sets number of pre and post-smoothing steps
116306792cafSBarry Smith 
116406792cafSBarry Smith    Level: advanced
116506792cafSBarry Smith 
116695452b02SPatrick Sanan    Notes:
116795452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
116806792cafSBarry Smith     there is no separate smooth up on the coarsest grid.
116906792cafSBarry Smith 
117006792cafSBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
117106792cafSBarry Smith 
1172710315b6SLawrence Mitchell .seealso: PCMGSetDistinctSmoothUp()
117306792cafSBarry Smith @*/
117406792cafSBarry Smith PetscErrorCode  PCMGSetNumberSmooth(PC pc,PetscInt n)
117506792cafSBarry Smith {
117606792cafSBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
117706792cafSBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
117806792cafSBarry Smith   PetscErrorCode ierr;
117906792cafSBarry Smith   PetscInt       i,levels;
118006792cafSBarry Smith 
118106792cafSBarry Smith   PetscFunctionBegin;
118206792cafSBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
118306792cafSBarry Smith   PetscValidLogicalCollectiveInt(pc,n,2);
11841a97d7b6SStefano Zampini   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
118506792cafSBarry Smith   levels = mglevels[0]->levels;
118606792cafSBarry Smith 
118706792cafSBarry Smith   for (i=1; i<levels; i++) {
118806792cafSBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
118906792cafSBarry Smith     ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
119006792cafSBarry Smith     mg->default_smoothu = n;
119106792cafSBarry Smith     mg->default_smoothd = n;
119206792cafSBarry Smith   }
119306792cafSBarry Smith   PetscFunctionReturn(0);
119406792cafSBarry Smith }
119506792cafSBarry Smith 
1196f442ab6aSBarry Smith /*@
1197f442ab6aSBarry Smith    PCMGSetDistinctSmoothUp - sets the up (post) smoother to be a seperate KSP from the down (pre) smoother on all levels
1198710315b6SLawrence Mitchell        and adds the suffix _up to the options name
1199f442ab6aSBarry Smith 
1200f442ab6aSBarry Smith    Logically Collective on PC
1201f442ab6aSBarry Smith 
1202f442ab6aSBarry Smith    Input Parameters:
1203f442ab6aSBarry Smith .  pc - the preconditioner context
1204f442ab6aSBarry Smith 
1205f442ab6aSBarry Smith    Options Database Key:
1206f442ab6aSBarry Smith .  -pc_mg_distinct_smoothup
1207f442ab6aSBarry Smith 
1208f442ab6aSBarry Smith    Level: advanced
1209f442ab6aSBarry Smith 
121095452b02SPatrick Sanan    Notes:
121195452b02SPatrick Sanan     this does not set a value on the coarsest grid, since we assume that
1212f442ab6aSBarry Smith     there is no separate smooth up on the coarsest grid.
1213f442ab6aSBarry Smith 
1214f442ab6aSBarry Smith .keywords: MG, smooth, up, post-smoothing, steps, multigrid
1215f442ab6aSBarry Smith 
1216710315b6SLawrence Mitchell .seealso: PCMGSetNumberSmooth()
1217f442ab6aSBarry Smith @*/
1218f442ab6aSBarry Smith PetscErrorCode  PCMGSetDistinctSmoothUp(PC pc)
1219f442ab6aSBarry Smith {
1220f442ab6aSBarry Smith   PC_MG          *mg        = (PC_MG*)pc->data;
1221f442ab6aSBarry Smith   PC_MG_Levels   **mglevels = mg->levels;
1222f442ab6aSBarry Smith   PetscErrorCode ierr;
1223f442ab6aSBarry Smith   PetscInt       i,levels;
1224f442ab6aSBarry Smith   KSP            subksp;
1225f442ab6aSBarry Smith 
1226f442ab6aSBarry Smith   PetscFunctionBegin;
1227f442ab6aSBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1228f442ab6aSBarry Smith   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Must set MG levels with PCMGSetLevels() before calling");
1229f442ab6aSBarry Smith   levels = mglevels[0]->levels;
1230f442ab6aSBarry Smith 
1231f442ab6aSBarry Smith   for (i=1; i<levels; i++) {
1232710315b6SLawrence Mitchell     const char *prefix = NULL;
1233f442ab6aSBarry Smith     /* make sure smoother up and down are different */
1234f442ab6aSBarry Smith     ierr = PCMGGetSmootherUp(pc,i,&subksp);CHKERRQ(ierr);
1235710315b6SLawrence Mitchell     ierr = KSPGetOptionsPrefix(mglevels[i]->smoothd,&prefix);CHKERRQ(ierr);
1236710315b6SLawrence Mitchell     ierr = KSPSetOptionsPrefix(subksp,prefix);CHKERRQ(ierr);
1237f442ab6aSBarry Smith     ierr = KSPAppendOptionsPrefix(subksp,"up_");CHKERRQ(ierr);
1238f442ab6aSBarry Smith   }
1239f442ab6aSBarry Smith   PetscFunctionReturn(0);
1240f442ab6aSBarry Smith }
1241f442ab6aSBarry Smith 
12424b9ad928SBarry Smith /* ----------------------------------------------------------------------------------------*/
12434b9ad928SBarry Smith 
12443b09bd56SBarry Smith /*MC
1245ccb205f8SBarry Smith    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
12463b09bd56SBarry Smith     information about the coarser grid matrices and restriction/interpolation operators.
12473b09bd56SBarry Smith 
12483b09bd56SBarry Smith    Options Database Keys:
12493b09bd56SBarry Smith +  -pc_mg_levels <nlevels> - number of levels including finest
1250391689abSStefano Zampini .  -pc_mg_cycle_type <v,w> - provide the cycle desired
12518c1c2452SJed Brown .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
12523b09bd56SBarry Smith .  -pc_mg_log - log information about time spent on each level of the solver
1253710315b6SLawrence Mitchell .  -pc_mg_distinct_smoothup - configure up (after interpolation) and down (before restriction) smoothers separately (with different options prefixes)
12542134b1e4SBarry Smith .  -pc_mg_galerkin <both,pmat,mat,none> - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
12558cf6037eSBarry Smith .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
12568cf6037eSBarry Smith .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1257e3c5b3baSBarry Smith                         to the Socket viewer for reading from MATLAB.
12588cf6037eSBarry Smith -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
12598cf6037eSBarry Smith                         to the binary output file called binaryoutput
12603b09bd56SBarry Smith 
126195452b02SPatrick Sanan    Notes:
12620b3c753eSRichard 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
12633b09bd56SBarry Smith 
12648cf6037eSBarry Smith        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
12658cf6037eSBarry Smith 
126623067569SBarry Smith        When run with KSPRICHARDSON the convergence test changes slightly if monitor is turned on. The iteration count may change slightly. This
126723067569SBarry Smith        is because without monitoring the residual norm is computed WITHIN each multigrid cycle on the finest level after the pre-smoothing
126823067569SBarry Smith        (because the residual has just been computed for the multigrid algorithm and is hence available for free) while with monitoring the
126923067569SBarry Smith        residual is computed at the end of each cycle.
127023067569SBarry Smith 
12713b09bd56SBarry Smith    Level: intermediate
12723b09bd56SBarry Smith 
12738f87f92bSBarry Smith    Concepts: multigrid/multilevel
12743b09bd56SBarry Smith 
12758cf6037eSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE
1276710315b6SLawrence Mitchell            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(),
1277710315b6SLawrence Mitchell            PCMGSetDistinctSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
127897177400SBarry Smith            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
12790d353602SBarry Smith            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
12803b09bd56SBarry Smith M*/
12813b09bd56SBarry Smith 
12828cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
12834b9ad928SBarry Smith {
1284f3fbd535SBarry Smith   PC_MG          *mg;
1285f3fbd535SBarry Smith   PetscErrorCode ierr;
1286f3fbd535SBarry Smith 
12874b9ad928SBarry Smith   PetscFunctionBegin;
1288b00a9115SJed Brown   ierr         = PetscNewLog(pc,&mg);CHKERRQ(ierr);
1289f3fbd535SBarry Smith   pc->data     = (void*)mg;
1290f3fbd535SBarry Smith   mg->nlevels  = -1;
129110eca3edSLisandro Dalcin   mg->am       = PC_MG_MULTIPLICATIVE;
12922134b1e4SBarry Smith   mg->galerkin = PC_MG_GALERKIN_NONE;
1293f3fbd535SBarry Smith 
129437a44384SMark Adams   pc->useAmat = PETSC_TRUE;
129537a44384SMark Adams 
12964b9ad928SBarry Smith   pc->ops->apply          = PCApply_MG;
12974b9ad928SBarry Smith   pc->ops->setup          = PCSetUp_MG;
1298a06653b4SBarry Smith   pc->ops->reset          = PCReset_MG;
12994b9ad928SBarry Smith   pc->ops->destroy        = PCDestroy_MG;
13004b9ad928SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_MG;
13014b9ad928SBarry Smith   pc->ops->view           = PCView_MG;
1302fb15c04eSBarry Smith 
1303fb15c04eSBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetGalerkin_C",PCMGSetGalerkin_MG);CHKERRQ(ierr);
13044b9ad928SBarry Smith   PetscFunctionReturn(0);
13054b9ad928SBarry Smith }
1306