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