xref: /petsc/src/ksp/pc/impls/mg/mg.c (revision 3e211508f432c794d02abab0170fc5dd4e0e02d5)
1 
2 /*
3     Defines the multigrid preconditioner interface.
4 */
5 #include <../src/ksp/pc/impls/mg/mgimpl.h>                    /*I "petscksp.h" I*/
6 #include <petscdm.h>
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "PCMGMCycle_Private"
10 PetscErrorCode PCMGMCycle_Private(PC pc,PC_MG_Levels **mglevelsin,PCRichardsonConvergedReason *reason)
11 {
12   PC_MG          *mg = (PC_MG*)pc->data;
13   PC_MG_Levels   *mgc,*mglevels = *mglevelsin;
14   PetscErrorCode ierr;
15   PetscInt       cycles = (mglevels->level == 1) ? 1 : (PetscInt) mglevels->cycles;
16 
17   PetscFunctionBegin;
18   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
19   ierr = KSPSolve(mglevels->smoothd,mglevels->b,mglevels->x);CHKERRQ(ierr);  /* pre-smooth */
20   if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
21   if (mglevels->level) {  /* not the coarsest grid */
22     if (mglevels->eventresidual) {ierr = PetscLogEventBegin(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
23     ierr = (*mglevels->residual)(mglevels->A,mglevels->b,mglevels->x,mglevels->r);CHKERRQ(ierr);
24     if (mglevels->eventresidual) {ierr = PetscLogEventEnd(mglevels->eventresidual,0,0,0,0);CHKERRQ(ierr);}
25 
26     /* if on finest level and have convergence criteria set */
27     if (mglevels->level == mglevels->levels-1 && mg->ttol && reason) {
28       PetscReal rnorm;
29       ierr = VecNorm(mglevels->r,NORM_2,&rnorm);CHKERRQ(ierr);
30       if (rnorm <= mg->ttol) {
31         if (rnorm < mg->abstol) {
32           *reason = PCRICHARDSON_CONVERGED_ATOL;
33           ierr    = PetscInfo2(pc,"Linear solver has converged. Residual norm %g is less than absolute tolerance %g\n",(double)rnorm,(double)mg->abstol);CHKERRQ(ierr);
34         } else {
35           *reason = PCRICHARDSON_CONVERGED_RTOL;
36           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);
37         }
38         PetscFunctionReturn(0);
39       }
40     }
41 
42     mgc = *(mglevelsin - 1);
43     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
44     ierr = MatRestrict(mglevels->restrct,mglevels->r,mgc->b);CHKERRQ(ierr);
45     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
46     ierr = VecSet(mgc->x,0.0);CHKERRQ(ierr);
47     while (cycles--) {
48       ierr = PCMGMCycle_Private(pc,mglevelsin-1,reason);CHKERRQ(ierr);
49     }
50     if (mglevels->eventinterprestrict) {ierr = PetscLogEventBegin(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
51     ierr = MatInterpolateAdd(mglevels->interpolate,mgc->x,mglevels->x,mglevels->x);CHKERRQ(ierr);
52     if (mglevels->eventinterprestrict) {ierr = PetscLogEventEnd(mglevels->eventinterprestrict,0,0,0,0);CHKERRQ(ierr);}
53     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventBegin(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
54     ierr = KSPSolve(mglevels->smoothu,mglevels->b,mglevels->x);CHKERRQ(ierr);    /* post smooth */
55     if (mglevels->eventsmoothsolve) {ierr = PetscLogEventEnd(mglevels->eventsmoothsolve,0,0,0,0);CHKERRQ(ierr);}
56   }
57   PetscFunctionReturn(0);
58 }
59 
60 #undef __FUNCT__
61 #define __FUNCT__ "PCApplyRichardson_MG"
62 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)
63 {
64   PC_MG          *mg        = (PC_MG*)pc->data;
65   PC_MG_Levels   **mglevels = mg->levels;
66   PetscErrorCode ierr;
67   PetscInt       levels = mglevels[0]->levels,i;
68 
69   PetscFunctionBegin;
70   mglevels[levels-1]->b = b;
71   mglevels[levels-1]->x = x;
72 
73   mg->rtol   = rtol;
74   mg->abstol = abstol;
75   mg->dtol   = dtol;
76   if (rtol) {
77     /* compute initial residual norm for relative convergence test */
78     PetscReal rnorm;
79     if (zeroguess) {
80       ierr = VecNorm(b,NORM_2,&rnorm);CHKERRQ(ierr);
81     } else {
82       ierr = (*mglevels[levels-1]->residual)(mglevels[levels-1]->A,b,x,w);CHKERRQ(ierr);
83       ierr = VecNorm(w,NORM_2,&rnorm);CHKERRQ(ierr);
84     }
85     mg->ttol = PetscMax(rtol*rnorm,abstol);
86   } else if (abstol) mg->ttol = abstol;
87   else mg->ttol = 0.0;
88 
89   /* since smoother is applied to full system, not just residual we need to make sure that smoothers don't
90      stop prematurely due to small residual */
91   for (i=1; i<levels; i++) {
92     ierr = KSPSetTolerances(mglevels[i]->smoothu,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
93     if (mglevels[i]->smoothu != mglevels[i]->smoothd) {
94       ierr = KSPSetTolerances(mglevels[i]->smoothd,0,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
95     }
96   }
97 
98   *reason = (PCRichardsonConvergedReason)0;
99   for (i=0; i<its; i++) {
100     ierr = PCMGMCycle_Private(pc,mglevels+levels-1,reason);CHKERRQ(ierr);
101     if (*reason) break;
102   }
103   if (!*reason) *reason = PCRICHARDSON_CONVERGED_ITS;
104   *outits = i;
105   PetscFunctionReturn(0);
106 }
107 
108 #undef __FUNCT__
109 #define __FUNCT__ "PCReset_MG"
110 PetscErrorCode PCReset_MG(PC pc)
111 {
112   PC_MG          *mg        = (PC_MG*)pc->data;
113   PC_MG_Levels   **mglevels = mg->levels;
114   PetscErrorCode ierr;
115   PetscInt       i,n;
116 
117   PetscFunctionBegin;
118   if (mglevels) {
119     n = mglevels[0]->levels;
120     for (i=0; i<n-1; i++) {
121       ierr = VecDestroy(&mglevels[i+1]->r);CHKERRQ(ierr);
122       ierr = VecDestroy(&mglevels[i]->b);CHKERRQ(ierr);
123       ierr = VecDestroy(&mglevels[i]->x);CHKERRQ(ierr);
124       ierr = MatDestroy(&mglevels[i+1]->restrct);CHKERRQ(ierr);
125       ierr = MatDestroy(&mglevels[i+1]->interpolate);CHKERRQ(ierr);
126       ierr = VecDestroy(&mglevels[i+1]->rscale);CHKERRQ(ierr);
127     }
128 
129     for (i=0; i<n; i++) {
130       ierr = MatDestroy(&mglevels[i]->A);CHKERRQ(ierr);
131       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
132         ierr = KSPReset(mglevels[i]->smoothd);CHKERRQ(ierr);
133       }
134       ierr = KSPReset(mglevels[i]->smoothu);CHKERRQ(ierr);
135     }
136   }
137   PetscFunctionReturn(0);
138 }
139 
140 #undef __FUNCT__
141 #define __FUNCT__ "PCMGSetLevels"
142 /*@C
143    PCMGSetLevels - Sets the number of levels to use with MG.
144    Must be called before any other MG routine.
145 
146    Logically Collective on PC
147 
148    Input Parameters:
149 +  pc - the preconditioner context
150 .  levels - the number of levels
151 -  comms - optional communicators for each level; this is to allow solving the coarser problems
152            on smaller sets of processors. Use NULL_OBJECT for default in Fortran
153 
154    Level: intermediate
155 
156    Notes:
157      If the number of levels is one then the multigrid uses the -mg_levels prefix
158   for setting the level options rather than the -mg_coarse prefix.
159 
160 .keywords: MG, set, levels, multigrid
161 
162 .seealso: PCMGSetType(), PCMGGetLevels()
163 @*/
164 PetscErrorCode  PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms)
165 {
166   PetscErrorCode ierr;
167   PC_MG          *mg        = (PC_MG*)pc->data;
168   MPI_Comm       comm;
169   PC_MG_Levels   **mglevels = mg->levels;
170   PetscInt       i;
171   PetscMPIInt    size;
172   const char     *prefix;
173   PC             ipc;
174   PetscInt       n;
175 
176   PetscFunctionBegin;
177   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
178   PetscValidLogicalCollectiveInt(pc,levels,2);
179   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
180   if (mg->nlevels == levels) PetscFunctionReturn(0);
181   if (mglevels) {
182     /* changing the number of levels so free up the previous stuff */
183     ierr = PCReset_MG(pc);CHKERRQ(ierr);
184     n    = mglevels[0]->levels;
185     for (i=0; i<n; i++) {
186       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
187         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
188       }
189       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
190       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
191     }
192     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
193   }
194 
195   mg->nlevels = levels;
196 
197   ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr);
198   ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr);
199 
200   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
201 
202   mg->stageApply = 0;
203   for (i=0; i<levels; i++) {
204     ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr);
205 
206     mglevels[i]->level               = i;
207     mglevels[i]->levels              = levels;
208     mglevels[i]->cycles              = PC_MG_CYCLE_V;
209     mg->default_smoothu              = 2;
210     mg->default_smoothd              = 2;
211     mglevels[i]->eventsmoothsetup    = 0;
212     mglevels[i]->eventsmoothsolve    = 0;
213     mglevels[i]->eventresidual       = 0;
214     mglevels[i]->eventinterprestrict = 0;
215 
216     if (comms) comm = comms[i];
217     ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr);
218     ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr);
219     ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr);
220     ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr);
221     ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr);
222     ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr);
223     ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr);
224     ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, i ? mg->default_smoothd : 1);CHKERRQ(ierr);
225     ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr);
226 
227     /* do special stuff for coarse grid */
228     if (!i && levels > 1) {
229       ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr);
230 
231       /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */
232       ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr);
233       ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr);
234       ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
235       if (size > 1) {
236         KSP innerksp;
237         PC  innerpc;
238         ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr);
239         ierr = PCRedundantGetKSP(ipc,&innerksp);CHKERRQ(ierr);
240         ierr = KSPGetPC(innerksp,&innerpc);CHKERRQ(ierr);
241         ierr = PCFactorSetShiftType(innerpc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr);
242       } else {
243         ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr);
244         ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr);
245       }
246     } else {
247       char tprefix[128];
248       sprintf(tprefix,"mg_levels_%d_",(int)i);
249       ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr);
250     }
251     ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr);
252 
253     mglevels[i]->smoothu = mglevels[i]->smoothd;
254     mg->rtol             = 0.0;
255     mg->abstol           = 0.0;
256     mg->dtol             = 0.0;
257     mg->ttol             = 0.0;
258     mg->cyclesperpcapply = 1;
259   }
260   mg->am                   = PC_MG_MULTIPLICATIVE;
261   mg->levels               = mglevels;
262   pc->ops->applyrichardson = PCApplyRichardson_MG;
263   PetscFunctionReturn(0);
264 }
265 
266 
267 #undef __FUNCT__
268 #define __FUNCT__ "PCDestroy_MG"
269 PetscErrorCode PCDestroy_MG(PC pc)
270 {
271   PetscErrorCode ierr;
272   PC_MG          *mg        = (PC_MG*)pc->data;
273   PC_MG_Levels   **mglevels = mg->levels;
274   PetscInt       i,n;
275 
276   PetscFunctionBegin;
277   ierr = PCReset_MG(pc);CHKERRQ(ierr);
278   if (mglevels) {
279     n = mglevels[0]->levels;
280     for (i=0; i<n; i++) {
281       if (mglevels[i]->smoothd != mglevels[i]->smoothu) {
282         ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr);
283       }
284       ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr);
285       ierr = PetscFree(mglevels[i]);CHKERRQ(ierr);
286     }
287     ierr = PetscFree(mg->levels);CHKERRQ(ierr);
288   }
289   ierr = PetscFree(pc->data);CHKERRQ(ierr);
290   PetscFunctionReturn(0);
291 }
292 
293 
294 
295 extern PetscErrorCode PCMGACycle_Private(PC,PC_MG_Levels**);
296 extern PetscErrorCode PCMGFCycle_Private(PC,PC_MG_Levels**);
297 extern PetscErrorCode PCMGKCycle_Private(PC,PC_MG_Levels**);
298 
299 /*
300    PCApply_MG - Runs either an additive, multiplicative, Kaskadic
301              or full cycle of multigrid.
302 
303   Note:
304   A simple wrapper which calls PCMGMCycle(),PCMGACycle(), or PCMGFCycle().
305 */
306 #undef __FUNCT__
307 #define __FUNCT__ "PCApply_MG"
308 static PetscErrorCode PCApply_MG(PC pc,Vec b,Vec x)
309 {
310   PC_MG          *mg        = (PC_MG*)pc->data;
311   PC_MG_Levels   **mglevels = mg->levels;
312   PetscErrorCode ierr;
313   PetscInt       levels = mglevels[0]->levels,i;
314 
315   PetscFunctionBegin;
316   if (mg->stageApply) {ierr = PetscLogStagePush(mg->stageApply);CHKERRQ(ierr);}
317   /* When the DM is supplying the matrix then it will not exist until here */
318   for (i=0; i<levels; i++) {
319     if (!mglevels[i]->A) {
320       ierr = KSPGetOperators(mglevels[i]->smoothu,&mglevels[i]->A,NULL);CHKERRQ(ierr);
321       ierr = PetscObjectReference((PetscObject)mglevels[i]->A);CHKERRQ(ierr);
322     }
323   }
324 
325   mglevels[levels-1]->b = b;
326   mglevels[levels-1]->x = x;
327   if (mg->am == PC_MG_MULTIPLICATIVE) {
328     ierr = VecSet(x,0.0);CHKERRQ(ierr);
329     for (i=0; i<mg->cyclesperpcapply; i++) {
330       ierr = PCMGMCycle_Private(pc,mglevels+levels-1,NULL);CHKERRQ(ierr);
331     }
332   } else if (mg->am == PC_MG_ADDITIVE) {
333     ierr = PCMGACycle_Private(pc,mglevels);CHKERRQ(ierr);
334   } else if (mg->am == PC_MG_KASKADE) {
335     ierr = PCMGKCycle_Private(pc,mglevels);CHKERRQ(ierr);
336   } else {
337     ierr = PCMGFCycle_Private(pc,mglevels);CHKERRQ(ierr);
338   }
339   if (mg->stageApply) {ierr = PetscLogStagePop();CHKERRQ(ierr);}
340   PetscFunctionReturn(0);
341 }
342 
343 
344 #undef __FUNCT__
345 #define __FUNCT__ "PCSetFromOptions_MG"
346 PetscErrorCode PCSetFromOptions_MG(PC pc)
347 {
348   PetscErrorCode ierr;
349   PetscInt       m,levels = 1,cycles;
350   PetscBool      flg,set;
351   PC_MG          *mg        = (PC_MG*)pc->data;
352   PC_MG_Levels   **mglevels = mg->levels;
353   PCMGType       mgtype;
354   PCMGCycleType  mgctype;
355 
356   PetscFunctionBegin;
357   ierr = PetscOptionsHead("Multigrid options");CHKERRQ(ierr);
358   if (!mg->levels) {
359     ierr = PetscOptionsInt("-pc_mg_levels","Number of Levels","PCMGSetLevels",levels,&levels,&flg);CHKERRQ(ierr);
360     if (!flg && pc->dm) {
361       ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
362       levels++;
363       mg->usedmfornumberoflevels = PETSC_TRUE;
364     }
365     ierr = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
366   }
367   mglevels = mg->levels;
368 
369   mgctype = (PCMGCycleType) mglevels[0]->cycles;
370   ierr    = PetscOptionsEnum("-pc_mg_cycle_type","V cycle or for W-cycle","PCMGSetCycleType",PCMGCycleTypes,(PetscEnum)mgctype,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
371   if (flg) {
372     ierr = PCMGSetCycleType(pc,mgctype);CHKERRQ(ierr);
373   }
374   flg  = PETSC_FALSE;
375   ierr = PetscOptionsBool("-pc_mg_galerkin","Use Galerkin process to compute coarser operators","PCMGSetGalerkin",flg,&flg,&set);CHKERRQ(ierr);
376   if (set) {
377     ierr = PCMGSetGalerkin(pc,flg);CHKERRQ(ierr);
378   }
379   ierr = PetscOptionsInt("-pc_mg_smoothup","Number of post-smoothing steps","PCMGSetNumberSmoothUp",1,&m,&flg);CHKERRQ(ierr);
380   if (flg) {
381     ierr = PCMGSetNumberSmoothUp(pc,m);CHKERRQ(ierr);
382   }
383   ierr = PetscOptionsInt("-pc_mg_smoothdown","Number of pre-smoothing steps","PCMGSetNumberSmoothDown",1,&m,&flg);CHKERRQ(ierr);
384   if (flg) {
385     ierr = PCMGSetNumberSmoothDown(pc,m);CHKERRQ(ierr);
386   }
387   mgtype = mg->am;
388   ierr   = PetscOptionsEnum("-pc_mg_type","Multigrid type","PCMGSetType",PCMGTypes,(PetscEnum)mgtype,(PetscEnum*)&mgtype,&flg);CHKERRQ(ierr);
389   if (flg) {
390     ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr);
391   }
392   if (mg->am == PC_MG_MULTIPLICATIVE) {
393     ierr = PetscOptionsInt("-pc_mg_multiplicative_cycles","Number of cycles for each preconditioner step","PCMGSetLevels",mg->cyclesperpcapply,&cycles,&flg);CHKERRQ(ierr);
394     if (flg) {
395       ierr = PCMGMultiplicativeSetCycles(pc,cycles);CHKERRQ(ierr);
396     }
397   }
398   flg  = PETSC_FALSE;
399   ierr = PetscOptionsBool("-pc_mg_log","Log times for each multigrid level","None",flg,&flg,NULL);CHKERRQ(ierr);
400   if (flg) {
401     PetscInt i;
402     char     eventname[128];
403     if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
404     levels = mglevels[0]->levels;
405     for (i=0; i<levels; i++) {
406       sprintf(eventname,"MGSetup Level %d",(int)i);
407       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsetup);CHKERRQ(ierr);
408       sprintf(eventname,"MGSmooth Level %d",(int)i);
409       ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventsmoothsolve);CHKERRQ(ierr);
410       if (i) {
411         sprintf(eventname,"MGResid Level %d",(int)i);
412         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventresidual);CHKERRQ(ierr);
413         sprintf(eventname,"MGInterp Level %d",(int)i);
414         ierr = PetscLogEventRegister(eventname,((PetscObject)pc)->classid,&mglevels[i]->eventinterprestrict);CHKERRQ(ierr);
415       }
416     }
417 
418 #if defined(PETSC_USE_LOG)
419     {
420       const char    *sname = "MG Apply";
421       PetscStageLog stageLog;
422       PetscInt      st;
423 
424       PetscFunctionBegin;
425       ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
426       for (st = 0; st < stageLog->numStages; ++st) {
427         PetscBool same;
428 
429         ierr = PetscStrcmp(stageLog->stageInfo[st].name, sname, &same);CHKERRQ(ierr);
430         if (same) mg->stageApply = st;
431       }
432       if (!mg->stageApply) {
433         ierr = PetscLogStageRegister(sname, &mg->stageApply);CHKERRQ(ierr);
434       }
435     }
436 #endif
437   }
438   ierr = PetscOptionsTail();CHKERRQ(ierr);
439   PetscFunctionReturn(0);
440 }
441 
442 const char *const PCMGTypes[] = {"MULTIPLICATIVE","ADDITIVE","FULL","KASKADE","PCMGType","PC_MG",0};
443 const char *const PCMGCycleTypes[] = {"invalid","v","w","PCMGCycleType","PC_MG_CYCLE",0};
444 
445 #include <petscdraw.h>
446 #undef __FUNCT__
447 #define __FUNCT__ "PCView_MG"
448 PetscErrorCode PCView_MG(PC pc,PetscViewer viewer)
449 {
450   PC_MG          *mg        = (PC_MG*)pc->data;
451   PC_MG_Levels   **mglevels = mg->levels;
452   PetscErrorCode ierr;
453   PetscInt       levels = mglevels ? mglevels[0]->levels : 0,i;
454   PetscBool      iascii,isbinary,isdraw;
455 
456   PetscFunctionBegin;
457   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
458   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
459   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
460   if (iascii) {
461     const char *cyclename = levels ? (mglevels[0]->cycles == PC_MG_CYCLE_V ? "v" : "w") : "unknown";
462     ierr = PetscViewerASCIIPrintf(viewer,"  MG: type is %s, levels=%D cycles=%s\n", PCMGTypes[mg->am],levels,cyclename);CHKERRQ(ierr);
463     if (mg->am == PC_MG_MULTIPLICATIVE) {
464       ierr = PetscViewerASCIIPrintf(viewer,"    Cycles per PCApply=%d\n",mg->cyclesperpcapply);CHKERRQ(ierr);
465     }
466     if (mg->galerkin) {
467       ierr = PetscViewerASCIIPrintf(viewer,"    Using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
468     } else {
469       ierr = PetscViewerASCIIPrintf(viewer,"    Not using Galerkin computed coarse grid matrices\n");CHKERRQ(ierr);
470     }
471     for (i=0; i<levels; i++) {
472       if (!i) {
473         ierr = PetscViewerASCIIPrintf(viewer,"Coarse grid solver -- level -------------------------------\n",i);CHKERRQ(ierr);
474       } else {
475         ierr = PetscViewerASCIIPrintf(viewer,"Down solver (pre-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
476       }
477       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
478       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
479       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
480       if (i && mglevels[i]->smoothd == mglevels[i]->smoothu) {
481         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) same as down solver (pre-smoother)\n");CHKERRQ(ierr);
482       } else if (i) {
483         ierr = PetscViewerASCIIPrintf(viewer,"Up solver (post-smoother) on level %D -------------------------------\n",i);CHKERRQ(ierr);
484         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
485         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
486         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
487       }
488     }
489   } else if (isbinary) {
490     for (i=levels-1; i>=0; i--) {
491       ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
492       if (i && mglevels[i]->smoothd != mglevels[i]->smoothu) {
493         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
494       }
495     }
496   } else if (isdraw) {
497     PetscDraw draw;
498     PetscReal x,w,y,bottom,th;
499     ierr   = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
500     ierr   = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
501     ierr   = PetscDrawStringGetSize(draw,NULL,&th);CHKERRQ(ierr);
502     bottom = y - th;
503     for (i=levels-1; i>=0; i--) {
504       if (!mglevels[i]->smoothu || (mglevels[i]->smoothu == mglevels[i]->smoothd)) {
505         ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
506         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
507         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
508       } else {
509         w    = 0.5*PetscMin(1.0-x,x);
510         ierr = PetscDrawPushCurrentPoint(draw,x+w,bottom);CHKERRQ(ierr);
511         ierr = KSPView(mglevels[i]->smoothd,viewer);CHKERRQ(ierr);
512         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
513         ierr = PetscDrawPushCurrentPoint(draw,x-w,bottom);CHKERRQ(ierr);
514         ierr = KSPView(mglevels[i]->smoothu,viewer);CHKERRQ(ierr);
515         ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr);
516       }
517       ierr    = PetscDrawGetBoundingBox(draw,NULL,&bottom,NULL,NULL);CHKERRQ(ierr);
518       bottom -= th;
519     }
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 #include <petsc-private/dmimpl.h>
525 #include <petsc-private/kspimpl.h>
526 
527 /*
528     Calls setup for the KSP on each level
529 */
530 #undef __FUNCT__
531 #define __FUNCT__ "PCSetUp_MG"
532 PetscErrorCode PCSetUp_MG(PC pc)
533 {
534   PC_MG          *mg        = (PC_MG*)pc->data;
535   PC_MG_Levels   **mglevels = mg->levels;
536   PetscErrorCode ierr;
537   PetscInt       i,n = mglevels[0]->levels;
538   PC             cpc;
539   PetscBool      preonly,lu,redundant,cholesky,svd,dump = PETSC_FALSE,opsset,use_amat;
540   Mat            dA,dB;
541   Vec            tvec;
542   DM             *dms;
543   PetscViewer    viewer = 0;
544 
545   PetscFunctionBegin;
546   /* FIX: Move this to PCSetFromOptions_MG? */
547   if (mg->usedmfornumberoflevels) {
548     PetscInt levels;
549     ierr = DMGetRefineLevel(pc->dm,&levels);CHKERRQ(ierr);
550     levels++;
551     if (levels > n) { /* the problem is now being solved on a finer grid */
552       ierr     = PCMGSetLevels(pc,levels,NULL);CHKERRQ(ierr);
553       n        = levels;
554       ierr     = PCSetFromOptions(pc);CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
555       mglevels =  mg->levels;
556     }
557   }
558   ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);CHKERRQ(ierr);
559 
560 
561   /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
562   /* so use those from global PC */
563   /* Is this what we always want? What if user wants to keep old one? */
564   ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);CHKERRQ(ierr);
565   if (opsset) {
566     Mat mmat;
567     ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat);CHKERRQ(ierr);
568     if (mmat == pc->pmat) opsset = PETSC_FALSE;
569   }
570 
571   if (!opsset) {
572     ierr = PCGetUseAmat(pc,&use_amat);CHKERRQ(ierr);
573     if(use_amat){
574       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);
575       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat);CHKERRQ(ierr);
576     }
577     else {
578       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);
579       ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat);CHKERRQ(ierr);
580     }
581   }
582 
583   /* Skipping this for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? */
584   if (pc->dm && mg->galerkin != 2 && !pc->setupcalled) {
585     /* construct the interpolation from the DMs */
586     Mat p;
587     Vec rscale;
588     ierr     = PetscMalloc1(n,&dms);CHKERRQ(ierr);
589     dms[n-1] = pc->dm;
590     for (i=n-2; i>-1; i--) {
591       DMKSP kdm;
592       ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);CHKERRQ(ierr);
593       ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);CHKERRQ(ierr);
594       if (mg->galerkin) {ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);CHKERRQ(ierr);}
595       ierr = DMGetDMKSPWrite(dms[i],&kdm);CHKERRQ(ierr);
596       /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
597        * a bitwise OR of computing the matrix, RHS, and initial iterate. */
598       kdm->ops->computerhs = NULL;
599       kdm->rhsctx          = NULL;
600       if (!mglevels[i+1]->interpolate) {
601         ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);CHKERRQ(ierr);
602         ierr = PCMGSetInterpolation(pc,i+1,p);CHKERRQ(ierr);
603         if (rscale) {ierr = PCMGSetRScale(pc,i+1,rscale);CHKERRQ(ierr);}
604         ierr = VecDestroy(&rscale);CHKERRQ(ierr);
605         ierr = MatDestroy(&p);CHKERRQ(ierr);
606       }
607     }
608 
609     for (i=n-2; i>-1; i--) {
610       ierr = DMDestroy(&dms[i]);CHKERRQ(ierr);
611     }
612     ierr = PetscFree(dms);CHKERRQ(ierr);
613   }
614 
615   if (pc->dm && !pc->setupcalled) {
616     /* finest smoother also gets DM but it is not active, independent of whether galerkin==2 */
617     ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);CHKERRQ(ierr);
618     ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);CHKERRQ(ierr);
619   }
620 
621   if (mg->galerkin == 1) {
622     Mat B;
623     /* currently only handle case where mat and pmat are the same on coarser levels */
624     ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB);CHKERRQ(ierr);
625     if (!pc->setupcalled) {
626       for (i=n-2; i>-1; i--) {
627         if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct || !mglevels[i+1]->restrct) {
628           ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr);
629         } else {
630           ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);CHKERRQ(ierr);
631         }
632         ierr = KSPSetOperators(mglevels[i]->smoothd,B,B);CHKERRQ(ierr);
633         if (i != n-2) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);}
634         dB = B;
635       }
636       if (n > 1) {ierr = PetscObjectDereference((PetscObject)dB);CHKERRQ(ierr);}
637     } else {
638       for (i=n-2; i>-1; i--) {
639         ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B);CHKERRQ(ierr);
640         if (mglevels[i+1]->interpolate == mglevels[i+1]->restrct || !mglevels[i+1]->restrct) {
641           ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr);
642         } else {
643           ierr = MatMatMatMult(mglevels[i+1]->restrct,dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr);
644         }
645         ierr = KSPSetOperators(mglevels[i]->smoothd,B,B);CHKERRQ(ierr);
646         dB   = B;
647       }
648     }
649   } else if (!mg->galerkin && pc->dm && pc->dm->x) {
650     /* need to restrict Jacobian location to coarser meshes for evaluation */
651     for (i=n-2; i>-1; i--) {
652       Mat R;
653       Vec rscale;
654       if (!mglevels[i]->smoothd->dm->x) {
655         Vec *vecs;
656         ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);CHKERRQ(ierr);
657 
658         mglevels[i]->smoothd->dm->x = vecs[0];
659 
660         ierr = PetscFree(vecs);CHKERRQ(ierr);
661       }
662       ierr = PCMGGetRestriction(pc,i+1,&R);CHKERRQ(ierr);
663       ierr = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
664       ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);CHKERRQ(ierr);
665       ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);CHKERRQ(ierr);
666     }
667   }
668   if (!mg->galerkin && pc->dm) {
669     for (i=n-2; i>=0; i--) {
670       DM  dmfine,dmcoarse;
671       Mat Restrict,Inject;
672       Vec rscale;
673       ierr   = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);CHKERRQ(ierr);
674       ierr   = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);CHKERRQ(ierr);
675       ierr   = PCMGGetRestriction(pc,i+1,&Restrict);CHKERRQ(ierr);
676       ierr   = PCMGGetRScale(pc,i+1,&rscale);CHKERRQ(ierr);
677       Inject = NULL;      /* Callback should create it if it needs Injection */
678       ierr   = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);CHKERRQ(ierr);
679     }
680   }
681 
682   if (!pc->setupcalled) {
683     for (i=0; i<n; i++) {
684       ierr = KSPSetFromOptions(mglevels[i]->smoothd);CHKERRQ(ierr);
685     }
686     for (i=1; i<n; i++) {
687       if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
688         ierr = KSPSetFromOptions(mglevels[i]->smoothu);CHKERRQ(ierr);
689       }
690     }
691     for (i=1; i<n; i++) {
692       ierr = PCMGGetInterpolation(pc,i,&mglevels[i]->interpolate);CHKERRQ(ierr);
693       ierr = PCMGGetRestriction(pc,i,&mglevels[i]->restrct);CHKERRQ(ierr);
694     }
695     for (i=0; i<n-1; i++) {
696       if (!mglevels[i]->b) {
697         Vec *vec;
698         ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
699         ierr = PCMGSetRhs(pc,i,*vec);CHKERRQ(ierr);
700         ierr = VecDestroy(vec);CHKERRQ(ierr);
701         ierr = PetscFree(vec);CHKERRQ(ierr);
702       }
703       if (!mglevels[i]->r && i) {
704         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
705         ierr = PCMGSetR(pc,i,tvec);CHKERRQ(ierr);
706         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
707       }
708       if (!mglevels[i]->x) {
709         ierr = VecDuplicate(mglevels[i]->b,&tvec);CHKERRQ(ierr);
710         ierr = PCMGSetX(pc,i,tvec);CHKERRQ(ierr);
711         ierr = VecDestroy(&tvec);CHKERRQ(ierr);
712       }
713     }
714     if (n != 1 && !mglevels[n-1]->r) {
715       /* PCMGSetR() on the finest level if user did not supply it */
716       Vec *vec;
717       ierr = KSPGetVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);CHKERRQ(ierr);
718       ierr = PCMGSetR(pc,n-1,*vec);CHKERRQ(ierr);
719       ierr = VecDestroy(vec);CHKERRQ(ierr);
720       ierr = PetscFree(vec);CHKERRQ(ierr);
721     }
722   }
723 
724   if (pc->dm) {
725     /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
726     for (i=0; i<n-1; i++) {
727       if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
728     }
729   }
730 
731   for (i=1; i<n; i++) {
732     if (mglevels[i]->smoothu == mglevels[i]->smoothd) {
733       /* if doing only down then initial guess is zero */
734       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);CHKERRQ(ierr);
735     }
736     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
737     ierr = KSPSetUp(mglevels[i]->smoothd);CHKERRQ(ierr);
738     if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
739     if (!mglevels[i]->residual) {
740       Mat mat;
741       ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&mat);CHKERRQ(ierr);
742       ierr = PCMGSetResidual(pc,i,PCMGResidualDefault,mat);CHKERRQ(ierr);
743     }
744   }
745   for (i=1; i<n; i++) {
746     if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
747       Mat          downmat,downpmat;
748 
749       /* check if operators have been set for up, if not use down operators to set them */
750       ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);CHKERRQ(ierr);
751       if (!opsset) {
752         ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat);CHKERRQ(ierr);
753         ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat);CHKERRQ(ierr);
754       }
755 
756       ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);CHKERRQ(ierr);
757       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
758       ierr = KSPSetUp(mglevels[i]->smoothu);CHKERRQ(ierr);
759       if (mglevels[i]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
760     }
761   }
762 
763   /*
764       If coarse solver is not direct method then DO NOT USE preonly
765   */
766   ierr = PetscObjectTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);CHKERRQ(ierr);
767   if (preonly) {
768     ierr = PetscObjectTypeCompare((PetscObject)cpc,PCLU,&lu);CHKERRQ(ierr);
769     ierr = PetscObjectTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);CHKERRQ(ierr);
770     ierr = PetscObjectTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);CHKERRQ(ierr);
771     ierr = PetscObjectTypeCompare((PetscObject)cpc,PCSVD,&svd);CHKERRQ(ierr);
772     if (!lu && !redundant && !cholesky && !svd) {
773       ierr = KSPSetType(mglevels[0]->smoothd,KSPGMRES);CHKERRQ(ierr);
774     }
775   }
776 
777   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
778   ierr = KSPSetUp(mglevels[0]->smoothd);CHKERRQ(ierr);
779   if (mglevels[0]->eventsmoothsetup) {ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);CHKERRQ(ierr);}
780 
781   /*
782      Dump the interpolation/restriction matrices plus the
783    Jacobian/stiffness on each level. This allows MATLAB users to
784    easily check if the Galerkin condition A_c = R A_f R^T is satisfied.
785 
786    Only support one or the other at the same time.
787   */
788 #if defined(PETSC_USE_SOCKET_VIEWER)
789   ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);CHKERRQ(ierr);
790   if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
791   dump = PETSC_FALSE;
792 #endif
793   ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);CHKERRQ(ierr);
794   if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));
795 
796   if (viewer) {
797     for (i=1; i<n; i++) {
798       ierr = MatView(mglevels[i]->restrct,viewer);CHKERRQ(ierr);
799     }
800     for (i=0; i<n; i++) {
801       ierr = KSPGetPC(mglevels[i]->smoothd,&pc);CHKERRQ(ierr);
802       ierr = MatView(pc->mat,viewer);CHKERRQ(ierr);
803     }
804   }
805   PetscFunctionReturn(0);
806 }
807 
808 /* -------------------------------------------------------------------------------------*/
809 
810 #undef __FUNCT__
811 #define __FUNCT__ "PCMGGetLevels"
812 /*@
813    PCMGGetLevels - Gets the number of levels to use with MG.
814 
815    Not Collective
816 
817    Input Parameter:
818 .  pc - the preconditioner context
819 
820    Output parameter:
821 .  levels - the number of levels
822 
823    Level: advanced
824 
825 .keywords: MG, get, levels, multigrid
826 
827 .seealso: PCMGSetLevels()
828 @*/
829 PetscErrorCode  PCMGGetLevels(PC pc,PetscInt *levels)
830 {
831   PC_MG *mg = (PC_MG*)pc->data;
832 
833   PetscFunctionBegin;
834   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
835   PetscValidIntPointer(levels,2);
836   *levels = mg->nlevels;
837   PetscFunctionReturn(0);
838 }
839 
840 #undef __FUNCT__
841 #define __FUNCT__ "PCMGSetType"
842 /*@
843    PCMGSetType - Determines the form of multigrid to use:
844    multiplicative, additive, full, or the Kaskade algorithm.
845 
846    Logically Collective on PC
847 
848    Input Parameters:
849 +  pc - the preconditioner context
850 -  form - multigrid form, one of PC_MG_MULTIPLICATIVE, PC_MG_ADDITIVE,
851    PC_MG_FULL, PC_MG_KASKADE
852 
853    Options Database Key:
854 .  -pc_mg_type <form> - Sets <form>, one of multiplicative,
855    additive, full, kaskade
856 
857    Level: advanced
858 
859 .keywords: MG, set, method, multiplicative, additive, full, Kaskade, multigrid
860 
861 .seealso: PCMGSetLevels()
862 @*/
863 PetscErrorCode  PCMGSetType(PC pc,PCMGType form)
864 {
865   PC_MG *mg = (PC_MG*)pc->data;
866 
867   PetscFunctionBegin;
868   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
869   PetscValidLogicalCollectiveEnum(pc,form,2);
870   mg->am = form;
871   if (form == PC_MG_MULTIPLICATIVE) pc->ops->applyrichardson = PCApplyRichardson_MG;
872   else pc->ops->applyrichardson = 0;
873   PetscFunctionReturn(0);
874 }
875 
876 #undef __FUNCT__
877 #define __FUNCT__ "PCMGSetCycleType"
878 /*@
879    PCMGSetCycleType - Sets the type cycles to use.  Use PCMGSetCycleTypeOnLevel() for more
880    complicated cycling.
881 
882    Logically Collective on PC
883 
884    Input Parameters:
885 +  pc - the multigrid context
886 -  PC_MG_CYCLE_V or PC_MG_CYCLE_W
887 
888    Options Database Key:
889 $  -pc_mg_cycle_type v or w
890 
891    Level: advanced
892 
893 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
894 
895 .seealso: PCMGSetCycleTypeOnLevel()
896 @*/
897 PetscErrorCode  PCMGSetCycleType(PC pc,PCMGCycleType n)
898 {
899   PC_MG        *mg        = (PC_MG*)pc->data;
900   PC_MG_Levels **mglevels = mg->levels;
901   PetscInt     i,levels;
902 
903   PetscFunctionBegin;
904   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
905   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
906   PetscValidLogicalCollectiveInt(pc,n,2);
907   levels = mglevels[0]->levels;
908 
909   for (i=0; i<levels; i++) mglevels[i]->cycles = n;
910   PetscFunctionReturn(0);
911 }
912 
913 #undef __FUNCT__
914 #define __FUNCT__ "PCMGMultiplicativeSetCycles"
915 /*@
916    PCMGMultiplicativeSetCycles - Sets the number of cycles to use for each preconditioner step
917          of multigrid when PCMGType of PC_MG_MULTIPLICATIVE is used
918 
919    Logically Collective on PC
920 
921    Input Parameters:
922 +  pc - the multigrid context
923 -  n - number of cycles (default is 1)
924 
925    Options Database Key:
926 $  -pc_mg_multiplicative_cycles n
927 
928    Level: advanced
929 
930    Notes: This is not associated with setting a v or w cycle, that is set with PCMGSetCycleType()
931 
932 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid
933 
934 .seealso: PCMGSetCycleTypeOnLevel(), PCMGSetCycleType()
935 @*/
936 PetscErrorCode  PCMGMultiplicativeSetCycles(PC pc,PetscInt n)
937 {
938   PC_MG        *mg        = (PC_MG*)pc->data;
939   PC_MG_Levels **mglevels = mg->levels;
940   PetscInt     i,levels;
941 
942   PetscFunctionBegin;
943   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
944   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
945   PetscValidLogicalCollectiveInt(pc,n,2);
946   levels = mglevels[0]->levels;
947 
948   for (i=0; i<levels; i++) mg->cyclesperpcapply = n;
949   PetscFunctionReturn(0);
950 }
951 
952 #undef __FUNCT__
953 #define __FUNCT__ "PCMGSetGalerkin"
954 /*@
955    PCMGSetGalerkin - Causes the coarser grid matrices to be computed from the
956       finest grid via the Galerkin process: A_i-1 = r_i * A_i * p_i
957 
958    Logically Collective on PC
959 
960    Input Parameters:
961 +  pc - the multigrid context
962 -  use - PETSC_TRUE to use the Galerkin process to compute coarse-level operators
963 
964    Options Database Key:
965 $  -pc_mg_galerkin
966 
967    Level: intermediate
968 
969 .keywords: MG, set, Galerkin
970 
971 .seealso: PCMGGetGalerkin()
972 
973 @*/
974 PetscErrorCode PCMGSetGalerkin(PC pc,PetscBool use)
975 {
976   PC_MG *mg = (PC_MG*)pc->data;
977 
978   PetscFunctionBegin;
979   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
980   mg->galerkin = use ? 1 : 0;
981   PetscFunctionReturn(0);
982 }
983 
984 #undef __FUNCT__
985 #define __FUNCT__ "PCMGGetGalerkin"
986 /*@
987    PCMGGetGalerkin - Checks if Galerkin multigrid is being used, i.e.
988       A_i-1 = r_i * A_i * p_i
989 
990    Not Collective
991 
992    Input Parameter:
993 .  pc - the multigrid context
994 
995    Output Parameter:
996 .  gelerkin - PETSC_TRUE or PETSC_FALSE
997 
998    Options Database Key:
999 $  -pc_mg_galerkin
1000 
1001    Level: intermediate
1002 
1003 .keywords: MG, set, Galerkin
1004 
1005 .seealso: PCMGSetGalerkin()
1006 
1007 @*/
1008 PetscErrorCode  PCMGGetGalerkin(PC pc,PetscBool  *galerkin)
1009 {
1010   PC_MG *mg = (PC_MG*)pc->data;
1011 
1012   PetscFunctionBegin;
1013   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1014   *galerkin = (PetscBool)mg->galerkin;
1015   PetscFunctionReturn(0);
1016 }
1017 
1018 #undef __FUNCT__
1019 #define __FUNCT__ "PCMGSetNumberSmoothDown"
1020 /*@
1021    PCMGSetNumberSmoothDown - Sets the number of pre-smoothing steps to
1022    use on all levels. Use PCMGGetSmootherDown() to set different
1023    pre-smoothing steps on different levels.
1024 
1025    Logically Collective on PC
1026 
1027    Input Parameters:
1028 +  mg - the multigrid context
1029 -  n - the number of smoothing steps
1030 
1031    Options Database Key:
1032 .  -pc_mg_smoothdown <n> - Sets number of pre-smoothing steps
1033 
1034    Level: advanced
1035 
1036 .keywords: MG, smooth, down, pre-smoothing, steps, multigrid
1037 
1038 .seealso: PCMGSetNumberSmoothUp()
1039 @*/
1040 PetscErrorCode  PCMGSetNumberSmoothDown(PC pc,PetscInt n)
1041 {
1042   PC_MG          *mg        = (PC_MG*)pc->data;
1043   PC_MG_Levels   **mglevels = mg->levels;
1044   PetscErrorCode ierr;
1045   PetscInt       i,levels;
1046 
1047   PetscFunctionBegin;
1048   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1049   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
1050   PetscValidLogicalCollectiveInt(pc,n,2);
1051   levels = mglevels[0]->levels;
1052 
1053   for (i=1; i<levels; i++) {
1054     /* make sure smoother up and down are different */
1055     ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr);
1056     ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
1057 
1058     mg->default_smoothd = n;
1059   }
1060   PetscFunctionReturn(0);
1061 }
1062 
1063 #undef __FUNCT__
1064 #define __FUNCT__ "PCMGSetNumberSmoothUp"
1065 /*@
1066    PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use
1067    on all levels. Use PCMGGetSmootherUp() to set different numbers of
1068    post-smoothing steps on different levels.
1069 
1070    Logically Collective on PC
1071 
1072    Input Parameters:
1073 +  mg - the multigrid context
1074 -  n - the number of smoothing steps
1075 
1076    Options Database Key:
1077 .  -pc_mg_smoothup <n> - Sets number of post-smoothing steps
1078 
1079    Level: advanced
1080 
1081    Note: this does not set a value on the coarsest grid, since we assume that
1082     there is no separate smooth up on the coarsest grid.
1083 
1084 .keywords: MG, smooth, up, post-smoothing, steps, multigrid
1085 
1086 .seealso: PCMGSetNumberSmoothDown()
1087 @*/
1088 PetscErrorCode  PCMGSetNumberSmoothUp(PC pc,PetscInt n)
1089 {
1090   PC_MG          *mg        = (PC_MG*)pc->data;
1091   PC_MG_Levels   **mglevels = mg->levels;
1092   PetscErrorCode ierr;
1093   PetscInt       i,levels;
1094 
1095   PetscFunctionBegin;
1096   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1097   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
1098   PetscValidLogicalCollectiveInt(pc,n,2);
1099   levels = mglevels[0]->levels;
1100 
1101   for (i=1; i<levels; i++) {
1102     /* make sure smoother up and down are different */
1103     ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr);
1104     ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr);
1105 
1106     mg->default_smoothu = n;
1107   }
1108   PetscFunctionReturn(0);
1109 }
1110 
1111 /* ----------------------------------------------------------------------------------------*/
1112 
1113 /*MC
1114    PCMG - Use multigrid preconditioning. This preconditioner requires you provide additional
1115     information about the coarser grid matrices and restriction/interpolation operators.
1116 
1117    Options Database Keys:
1118 +  -pc_mg_levels <nlevels> - number of levels including finest
1119 .  -pc_mg_cycles v or w
1120 .  -pc_mg_smoothup <n> - number of smoothing steps after interpolation
1121 .  -pc_mg_smoothdown <n> - number of smoothing steps before applying restriction operator
1122 .  -pc_mg_type <additive,multiplicative,full,kaskade> - multiplicative is the default
1123 .  -pc_mg_log - log information about time spent on each level of the solver
1124 .  -pc_mg_monitor - print information on the multigrid convergence
1125 .  -pc_mg_galerkin - use Galerkin process to compute coarser operators, i.e. Acoarse = R A R'
1126 .  -pc_mg_multiplicative_cycles - number of cycles to use as the preconditioner (defaults to 1)
1127 .  -pc_mg_dump_matlab - dumps the matrices for each level and the restriction/interpolation matrices
1128                         to the Socket viewer for reading from MATLAB.
1129 -  -pc_mg_dump_binary - dumps the matrices for each level and the restriction/interpolation matrices
1130                         to the binary output file called binaryoutput
1131 
1132    Notes: By default this uses GMRES on the fine grid smoother so this should be used with KSPFGMRES or the smoother changed to not use GMRES
1133 
1134        When run with a single level the smoother options are used on that level NOT the coarse grid solver options
1135 
1136    Level: intermediate
1137 
1138    Concepts: multigrid/multilevel
1139 
1140 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType, PCEXOTIC, PCGAMG, PCML, PCHYPRE
1141            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), PCMGSetCycleType(), PCMGSetNumberSmoothDown(),
1142            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
1143            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
1144            PCMGSetCycleTypeOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
1145 M*/
1146 
1147 #undef __FUNCT__
1148 #define __FUNCT__ "PCCreate_MG"
1149 PETSC_EXTERN PetscErrorCode PCCreate_MG(PC pc)
1150 {
1151   PC_MG          *mg;
1152   PetscErrorCode ierr;
1153 
1154   PetscFunctionBegin;
1155   ierr        = PetscNewLog(pc,&mg);CHKERRQ(ierr);
1156   pc->data    = (void*)mg;
1157   mg->nlevels = -1;
1158 
1159   pc->useAmat = PETSC_TRUE;
1160 
1161   pc->ops->apply          = PCApply_MG;
1162   pc->ops->setup          = PCSetUp_MG;
1163   pc->ops->reset          = PCReset_MG;
1164   pc->ops->destroy        = PCDestroy_MG;
1165   pc->ops->setfromoptions = PCSetFromOptions_MG;
1166   pc->ops->view           = PCView_MG;
1167   PetscFunctionReturn(0);
1168 }
1169