xref: /petsc/src/ksp/pc/impls/mg/mgfunc.c (revision bebe2cf65d55febe21a5af8db2bd2e168caaa2e7)
1 
2 #include <petsc/private/pcmgimpl.h>       /*I "petscksp.h" I*/
3 
4 /* ---------------------------------------------------------------------------*/
5 #undef __FUNCT__
6 #define __FUNCT__ "PCMGResidualDefault"
7 /*@C
8    PCMGResidualDefault - Default routine to calculate the residual.
9 
10    Collective on Mat and Vec
11 
12    Input Parameters:
13 +  mat - the matrix
14 .  b   - the right-hand-side
15 -  x   - the approximate solution
16 
17    Output Parameter:
18 .  r - location to store the residual
19 
20    Level: developer
21 
22 .keywords: MG, default, multigrid, residual
23 
24 .seealso: PCMGSetResidual()
25 @*/
26 PetscErrorCode  PCMGResidualDefault(Mat mat,Vec b,Vec x,Vec r)
27 {
28   PetscErrorCode ierr;
29 
30   PetscFunctionBegin;
31   ierr = MatResidual(mat,b,x,r);CHKERRQ(ierr);
32   PetscFunctionReturn(0);
33 }
34 
35 #undef __FUNCT__
36 #define __FUNCT__ "PCMGGetCoarseSolve"
37 /*@
38    PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.
39 
40    Not Collective
41 
42    Input Parameter:
43 .  pc - the multigrid context
44 
45    Output Parameter:
46 .  ksp - the coarse grid solver context
47 
48    Level: advanced
49 
50 .keywords: MG, multigrid, get, coarse grid
51 @*/
52 PetscErrorCode  PCMGGetCoarseSolve(PC pc,KSP *ksp)
53 {
54   PC_MG        *mg        = (PC_MG*)pc->data;
55   PC_MG_Levels **mglevels = mg->levels;
56 
57   PetscFunctionBegin;
58   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
59   *ksp =  mglevels[0]->smoothd;
60   PetscFunctionReturn(0);
61 }
62 
63 #undef __FUNCT__
64 #define __FUNCT__ "PCMGSetResidual"
65 /*@C
66    PCMGSetResidual - Sets the function to be used to calculate the residual
67    on the lth level.
68 
69    Logically Collective on PC and Mat
70 
71    Input Parameters:
72 +  pc       - the multigrid context
73 .  l        - the level (0 is coarsest) to supply
74 .  residual - function used to form residual, if none is provided the previously provide one is used, if no
75               previous one were provided then a default is used
76 -  mat      - matrix associated with residual
77 
78    Level: advanced
79 
80 .keywords:  MG, set, multigrid, residual, level
81 
82 .seealso: PCMGResidualDefault()
83 @*/
84 PetscErrorCode  PCMGSetResidual(PC pc,PetscInt l,PetscErrorCode (*residual)(Mat,Vec,Vec,Vec),Mat mat)
85 {
86   PC_MG          *mg        = (PC_MG*)pc->data;
87   PC_MG_Levels   **mglevels = mg->levels;
88   PetscErrorCode ierr;
89 
90   PetscFunctionBegin;
91   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
92   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
93   if (residual) mglevels[l]->residual = residual;
94   if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
95   if (mat) {ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);}
96   ierr = MatDestroy(&mglevels[l]->A);CHKERRQ(ierr);
97   mglevels[l]->A = mat;
98   PetscFunctionReturn(0);
99 }
100 
101 #undef __FUNCT__
102 #define __FUNCT__ "PCMGSetInterpolation"
103 /*@
104    PCMGSetInterpolation - Sets the function to be used to calculate the
105    interpolation from l-1 to the lth level
106 
107    Logically Collective on PC and Mat
108 
109    Input Parameters:
110 +  pc  - the multigrid context
111 .  mat - the interpolation operator
112 -  l   - the level (0 is coarsest) to supply [do not supply 0]
113 
114    Level: advanced
115 
116    Notes:
117           Usually this is the same matrix used also to set the restriction
118     for the same level.
119 
120           One can pass in the interpolation matrix or its transpose; PETSc figures
121     out from the matrix size which one it is.
122 
123 .keywords:  multigrid, set, interpolate, level
124 
125 .seealso: PCMGSetRestriction()
126 @*/
127 PetscErrorCode  PCMGSetInterpolation(PC pc,PetscInt l,Mat mat)
128 {
129   PC_MG          *mg        = (PC_MG*)pc->data;
130   PC_MG_Levels   **mglevels = mg->levels;
131   PetscErrorCode ierr;
132 
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
135   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
136   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set interpolation routine for coarsest level");
137   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
138   ierr = MatDestroy(&mglevels[l]->interpolate);CHKERRQ(ierr);
139 
140   mglevels[l]->interpolate = mat;
141   PetscFunctionReturn(0);
142 }
143 
144 #undef __FUNCT__
145 #define __FUNCT__ "PCMGGetInterpolation"
146 /*@
147    PCMGGetInterpolation - Gets the function to be used to calculate the
148    interpolation from l-1 to the lth level
149 
150    Logically Collective on PC
151 
152    Input Parameters:
153 +  pc - the multigrid context
154 -  l - the level (0 is coarsest) to supply [Do not supply 0]
155 
156    Output Parameter:
157 .  mat - the interpolation matrix
158 
159    Level: advanced
160 
161 .keywords: MG, get, multigrid, interpolation, level
162 
163 .seealso: PCMGGetRestriction(), PCMGSetInterpolation(), PCMGGetRScale()
164 @*/
165 PetscErrorCode  PCMGGetInterpolation(PC pc,PetscInt l,Mat *mat)
166 {
167   PC_MG          *mg        = (PC_MG*)pc->data;
168   PC_MG_Levels   **mglevels = mg->levels;
169   PetscErrorCode ierr;
170 
171   PetscFunctionBegin;
172   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
173   PetscValidPointer(mat,3);
174   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
175   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
176   if (!mglevels[l]->interpolate) {
177     if (!mglevels[l]->restrct) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetInterpolation() or PCMGSetInterpolation()");
178     ierr = PCMGSetInterpolation(pc,l,mglevels[l]->restrct);CHKERRQ(ierr);
179   }
180   *mat = mglevels[l]->interpolate;
181   PetscFunctionReturn(0);
182 }
183 
184 #undef __FUNCT__
185 #define __FUNCT__ "PCMGSetRestriction"
186 /*@
187    PCMGSetRestriction - Sets the function to be used to restrict vector
188    from level l to l-1.
189 
190    Logically Collective on PC and Mat
191 
192    Input Parameters:
193 +  pc - the multigrid context
194 .  l - the level (0 is coarsest) to supply [Do not supply 0]
195 -  mat - the restriction matrix
196 
197    Level: advanced
198 
199    Notes:
200           Usually this is the same matrix used also to set the interpolation
201     for the same level.
202 
203           One can pass in the interpolation matrix or its transpose; PETSc figures
204     out from the matrix size which one it is.
205 
206          If you do not set this, the transpose of the Mat set with PCMGSetInterpolation()
207     is used.
208 
209 .keywords: MG, set, multigrid, restriction, level
210 
211 .seealso: PCMGSetInterpolation()
212 @*/
213 PetscErrorCode  PCMGSetRestriction(PC pc,PetscInt l,Mat mat)
214 {
215   PetscErrorCode ierr;
216   PC_MG          *mg        = (PC_MG*)pc->data;
217   PC_MG_Levels   **mglevels = mg->levels;
218 
219   PetscFunctionBegin;
220   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
221   PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
222   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
223   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set restriction routine for coarsest level");
224   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
225   ierr = MatDestroy(&mglevels[l]->restrct);CHKERRQ(ierr);
226 
227   mglevels[l]->restrct = mat;
228   PetscFunctionReturn(0);
229 }
230 
231 #undef __FUNCT__
232 #define __FUNCT__ "PCMGGetRestriction"
233 /*@
234    PCMGGetRestriction - Gets the function to be used to restrict vector
235    from level l to l-1.
236 
237    Logically Collective on PC and Mat
238 
239    Input Parameters:
240 +  pc - the multigrid context
241 -  l - the level (0 is coarsest) to supply [Do not supply 0]
242 
243    Output Parameter:
244 .  mat - the restriction matrix
245 
246    Level: advanced
247 
248 .keywords: MG, get, multigrid, restriction, level
249 
250 .seealso: PCMGGetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
251 @*/
252 PetscErrorCode  PCMGGetRestriction(PC pc,PetscInt l,Mat *mat)
253 {
254   PC_MG          *mg        = (PC_MG*)pc->data;
255   PC_MG_Levels   **mglevels = mg->levels;
256   PetscErrorCode ierr;
257 
258   PetscFunctionBegin;
259   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
260   PetscValidPointer(mat,3);
261   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
262   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
263   if (!mglevels[l]->restrct) {
264     if (!mglevels[l]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetRestriction() or PCMGSetInterpolation()");
265     ierr = PCMGSetRestriction(pc,l,mglevels[l]->interpolate);CHKERRQ(ierr);
266   }
267   *mat = mglevels[l]->restrct;
268   PetscFunctionReturn(0);
269 }
270 
271 #undef __FUNCT__
272 #define __FUNCT__ "PCMGSetRScale"
273 /*@
274    PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
275 
276    Logically Collective on PC and Vec
277 
278    Input Parameters:
279 +  pc - the multigrid context
280 -  l - the level (0 is coarsest) to supply [Do not supply 0]
281 .  rscale - the scaling
282 
283    Level: advanced
284 
285    Notes:
286        When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
287 
288 .keywords: MG, set, multigrid, restriction, level
289 
290 .seealso: PCMGSetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
291 @*/
292 PetscErrorCode  PCMGSetRScale(PC pc,PetscInt l,Vec rscale)
293 {
294   PetscErrorCode ierr;
295   PC_MG          *mg        = (PC_MG*)pc->data;
296   PC_MG_Levels   **mglevels = mg->levels;
297 
298   PetscFunctionBegin;
299   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
300   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
301   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
302   ierr = PetscObjectReference((PetscObject)rscale);CHKERRQ(ierr);
303   ierr = VecDestroy(&mglevels[l]->rscale);CHKERRQ(ierr);
304 
305   mglevels[l]->rscale = rscale;
306   PetscFunctionReturn(0);
307 }
308 
309 #undef __FUNCT__
310 #define __FUNCT__ "PCMGGetRScale"
311 /*@
312    PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
313 
314    Collective on PC
315 
316    Input Parameters:
317 +  pc - the multigrid context
318 .  rscale - the scaling
319 -  l - the level (0 is coarsest) to supply [Do not supply 0]
320 
321    Level: advanced
322 
323    Notes:
324        When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
325 
326 .keywords: MG, set, multigrid, restriction, level
327 
328 .seealso: PCMGSetInterpolation(), PCMGGetRestriction()
329 @*/
330 PetscErrorCode PCMGGetRScale(PC pc,PetscInt l,Vec *rscale)
331 {
332   PetscErrorCode ierr;
333   PC_MG          *mg        = (PC_MG*)pc->data;
334   PC_MG_Levels   **mglevels = mg->levels;
335 
336   PetscFunctionBegin;
337   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
338   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
339   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
340   if (!mglevels[l]->rscale) {
341     Mat      R;
342     Vec      X,Y,coarse,fine;
343     PetscInt M,N;
344     ierr = PCMGGetRestriction(pc,l,&R);CHKERRQ(ierr);
345     ierr = MatCreateVecs(R,&X,&Y);CHKERRQ(ierr);
346     ierr = MatGetSize(R,&M,&N);CHKERRQ(ierr);
347     if (M < N) {
348       fine = X;
349       coarse = Y;
350     } else if (N < M) {
351       fine = Y; coarse = X;
352     } else SETERRQ(PetscObjectComm((PetscObject)R),PETSC_ERR_SUP,"Restriction matrix is square, cannot determine which Vec is coarser");
353     ierr = VecSet(fine,1.);CHKERRQ(ierr);
354     ierr = MatRestrict(R,fine,coarse);CHKERRQ(ierr);
355     ierr = VecDestroy(&fine);CHKERRQ(ierr);
356     ierr = VecReciprocal(coarse);CHKERRQ(ierr);
357     mglevels[l]->rscale = coarse;
358   }
359   *rscale = mglevels[l]->rscale;
360   PetscFunctionReturn(0);
361 }
362 
363 #undef __FUNCT__
364 #define __FUNCT__ "PCMGGetSmoother"
365 /*@
366    PCMGGetSmoother - Gets the KSP context to be used as smoother for
367    both pre- and post-smoothing.  Call both PCMGGetSmootherUp() and
368    PCMGGetSmootherDown() to use different functions for pre- and
369    post-smoothing.
370 
371    Not Collective, KSP returned is parallel if PC is
372 
373    Input Parameters:
374 +  pc - the multigrid context
375 -  l - the level (0 is coarsest) to supply
376 
377    Ouput Parameters:
378 .  ksp - the smoother
379 
380    Notes:
381    Once you have called this routine, you can call KSPSetOperators(ksp,...) on the resulting ksp to provide the operators for the smoother for this level.
382    You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call KSPGetPC(ksp,&pc)
383    and modify PC options for the smoother; for example PCSetType(pc,PCSOR); to use SOR smoothing.
384 
385    Level: advanced
386 
387 .keywords: MG, get, multigrid, level, smoother, pre-smoother, post-smoother
388 
389 .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
390 @*/
391 PetscErrorCode  PCMGGetSmoother(PC pc,PetscInt l,KSP *ksp)
392 {
393   PC_MG        *mg        = (PC_MG*)pc->data;
394   PC_MG_Levels **mglevels = mg->levels;
395 
396   PetscFunctionBegin;
397   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
398   *ksp = mglevels[l]->smoothd;
399   PetscFunctionReturn(0);
400 }
401 
402 #undef __FUNCT__
403 #define __FUNCT__ "PCMGGetSmootherUp"
404 /*@
405    PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
406    coarse grid correction (post-smoother).
407 
408    Not Collective, KSP returned is parallel if PC is
409 
410    Input Parameters:
411 +  pc - the multigrid context
412 -  l  - the level (0 is coarsest) to supply
413 
414    Ouput Parameters:
415 .  ksp - the smoother
416 
417    Level: advanced
418 
419    Notes: calling this will result in a different pre and post smoother so you may need to
420          set options on the pre smoother also
421 
422 .keywords: MG, multigrid, get, smoother, up, post-smoother, level
423 
424 .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
425 @*/
426 PetscErrorCode  PCMGGetSmootherUp(PC pc,PetscInt l,KSP *ksp)
427 {
428   PC_MG          *mg        = (PC_MG*)pc->data;
429   PC_MG_Levels   **mglevels = mg->levels;
430   PetscErrorCode ierr;
431   const char     *prefix;
432   MPI_Comm       comm;
433 
434   PetscFunctionBegin;
435   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
436   /*
437      This is called only if user wants a different pre-smoother from post.
438      Thus we check if a different one has already been allocated,
439      if not we allocate it.
440   */
441   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"There is no such thing as a up smoother on the coarse grid");
442   if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
443     KSPType     ksptype;
444     PCType      pctype;
445     PC          ipc;
446     PetscReal   rtol,abstol,dtol;
447     PetscInt    maxits;
448     KSPNormType normtype;
449     ierr = PetscObjectGetComm((PetscObject)mglevels[l]->smoothd,&comm);CHKERRQ(ierr);
450     ierr = KSPGetOptionsPrefix(mglevels[l]->smoothd,&prefix);CHKERRQ(ierr);
451     ierr = KSPGetTolerances(mglevels[l]->smoothd,&rtol,&abstol,&dtol,&maxits);CHKERRQ(ierr);
452     ierr = KSPGetType(mglevels[l]->smoothd,&ksptype);CHKERRQ(ierr);
453     ierr = KSPGetNormType(mglevels[l]->smoothd,&normtype);CHKERRQ(ierr);
454     ierr = KSPGetPC(mglevels[l]->smoothd,&ipc);CHKERRQ(ierr);
455     ierr = PCGetType(ipc,&pctype);CHKERRQ(ierr);
456 
457     ierr = KSPCreate(comm,&mglevels[l]->smoothu);CHKERRQ(ierr);
458     ierr = KSPSetErrorIfNotConverged(mglevels[l]->smoothu,pc->erroriffailure);CHKERRQ(ierr);
459     ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu,(PetscObject)pc,mglevels[0]->levels-l);CHKERRQ(ierr);
460     ierr = KSPSetOptionsPrefix(mglevels[l]->smoothu,prefix);CHKERRQ(ierr);
461     ierr = KSPSetTolerances(mglevels[l]->smoothu,rtol,abstol,dtol,maxits);CHKERRQ(ierr);
462     ierr = KSPSetType(mglevels[l]->smoothu,ksptype);CHKERRQ(ierr);
463     ierr = KSPSetNormType(mglevels[l]->smoothu,normtype);CHKERRQ(ierr);
464     ierr = KSPSetConvergenceTest(mglevels[l]->smoothu,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr);
465     ierr = KSPGetPC(mglevels[l]->smoothu,&ipc);CHKERRQ(ierr);
466     ierr = PCSetType(ipc,pctype);CHKERRQ(ierr);
467     ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[l]->smoothu);CHKERRQ(ierr);
468   }
469   if (ksp) *ksp = mglevels[l]->smoothu;
470   PetscFunctionReturn(0);
471 }
472 
473 #undef __FUNCT__
474 #define __FUNCT__ "PCMGGetSmootherDown"
475 /*@
476    PCMGGetSmootherDown - Gets the KSP context to be used as smoother before
477    coarse grid correction (pre-smoother).
478 
479    Not Collective, KSP returned is parallel if PC is
480 
481    Input Parameters:
482 +  pc - the multigrid context
483 -  l  - the level (0 is coarsest) to supply
484 
485    Ouput Parameters:
486 .  ksp - the smoother
487 
488    Level: advanced
489 
490    Notes: calling this will result in a different pre and post smoother so you may need to
491          set options on the post smoother also
492 
493 .keywords: MG, multigrid, get, smoother, down, pre-smoother, level
494 
495 .seealso: PCMGGetSmootherUp(), PCMGGetSmoother()
496 @*/
497 PetscErrorCode  PCMGGetSmootherDown(PC pc,PetscInt l,KSP *ksp)
498 {
499   PetscErrorCode ierr;
500   PC_MG          *mg        = (PC_MG*)pc->data;
501   PC_MG_Levels   **mglevels = mg->levels;
502 
503   PetscFunctionBegin;
504   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
505   /* make sure smoother up and down are different */
506   if (l) {
507     ierr = PCMGGetSmootherUp(pc,l,NULL);CHKERRQ(ierr);
508   }
509   *ksp = mglevels[l]->smoothd;
510   PetscFunctionReturn(0);
511 }
512 
513 #undef __FUNCT__
514 #define __FUNCT__ "PCMGSetCyclesOnLevel"
515 /*@
516    PCMGSetCyclesOnLevel - Sets the number of cycles to run on this level.
517 
518    Logically Collective on PC
519 
520    Input Parameters:
521 +  pc - the multigrid context
522 .  l  - the level (0 is coarsest) this is to be used for
523 -  n  - the number of cycles
524 
525    Level: advanced
526 
527 .keywords: MG, multigrid, set, cycles, V-cycle, W-cycle, level
528 
529 .seealso: PCMGSetCycles()
530 @*/
531 PetscErrorCode  PCMGSetCyclesOnLevel(PC pc,PetscInt l,PetscInt c)
532 {
533   PC_MG        *mg        = (PC_MG*)pc->data;
534   PC_MG_Levels **mglevels = mg->levels;
535 
536   PetscFunctionBegin;
537   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
538   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
539   PetscValidLogicalCollectiveInt(pc,l,2);
540   PetscValidLogicalCollectiveInt(pc,c,3);
541   mglevels[l]->cycles = c;
542   PetscFunctionReturn(0);
543 }
544 
545 #undef __FUNCT__
546 #define __FUNCT__ "PCMGSetRhs"
547 /*@
548    PCMGSetRhs - Sets the vector space to be used to store the right-hand side
549    on a particular level.
550 
551    Logically Collective on PC and Vec
552 
553    Input Parameters:
554 +  pc - the multigrid context
555 .  l  - the level (0 is coarsest) this is to be used for
556 -  c  - the space
557 
558    Level: advanced
559 
560    Notes: If this is not provided PETSc will automatically generate one.
561 
562           You do not need to keep a reference to this vector if you do
563           not need it PCDestroy() will properly free it.
564 
565 .keywords: MG, multigrid, set, right-hand-side, rhs, level
566 
567 .seealso: PCMGSetX(), PCMGSetR()
568 @*/
569 PetscErrorCode  PCMGSetRhs(PC pc,PetscInt l,Vec c)
570 {
571   PetscErrorCode ierr;
572   PC_MG          *mg        = (PC_MG*)pc->data;
573   PC_MG_Levels   **mglevels = mg->levels;
574 
575   PetscFunctionBegin;
576   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
577   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
578   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set rhs for finest level");
579   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
580   ierr = VecDestroy(&mglevels[l]->b);CHKERRQ(ierr);
581 
582   mglevels[l]->b = c;
583   PetscFunctionReturn(0);
584 }
585 
586 #undef __FUNCT__
587 #define __FUNCT__ "PCMGSetX"
588 /*@
589    PCMGSetX - Sets the vector space to be used to store the solution on a
590    particular level.
591 
592    Logically Collective on PC and Vec
593 
594    Input Parameters:
595 +  pc - the multigrid context
596 .  l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
597 -  c - the space
598 
599    Level: advanced
600 
601    Notes: If this is not provided PETSc will automatically generate one.
602 
603           You do not need to keep a reference to this vector if you do
604           not need it PCDestroy() will properly free it.
605 
606 .keywords: MG, multigrid, set, solution, level
607 
608 .seealso: PCMGSetRhs(), PCMGSetR()
609 @*/
610 PetscErrorCode  PCMGSetX(PC pc,PetscInt l,Vec c)
611 {
612   PetscErrorCode ierr;
613   PC_MG          *mg        = (PC_MG*)pc->data;
614   PC_MG_Levels   **mglevels = mg->levels;
615 
616   PetscFunctionBegin;
617   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
618   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
619   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set x for finest level");
620   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
621   ierr = VecDestroy(&mglevels[l]->x);CHKERRQ(ierr);
622 
623   mglevels[l]->x = c;
624   PetscFunctionReturn(0);
625 }
626 
627 #undef __FUNCT__
628 #define __FUNCT__ "PCMGSetR"
629 /*@
630    PCMGSetR - Sets the vector space to be used to store the residual on a
631    particular level.
632 
633    Logically Collective on PC and Vec
634 
635    Input Parameters:
636 +  pc - the multigrid context
637 .  l - the level (0 is coarsest) this is to be used for
638 -  c - the space
639 
640    Level: advanced
641 
642    Notes: If this is not provided PETSc will automatically generate one.
643 
644           You do not need to keep a reference to this vector if you do
645           not need it PCDestroy() will properly free it.
646 
647 .keywords: MG, multigrid, set, residual, level
648 @*/
649 PetscErrorCode  PCMGSetR(PC pc,PetscInt l,Vec c)
650 {
651   PetscErrorCode ierr;
652   PC_MG          *mg        = (PC_MG*)pc->data;
653   PC_MG_Levels   **mglevels = mg->levels;
654 
655   PetscFunctionBegin;
656   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
657   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
658   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Need not set residual vector for coarse grid");
659   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
660   ierr = VecDestroy(&mglevels[l]->r);CHKERRQ(ierr);
661 
662   mglevels[l]->r = c;
663   PetscFunctionReturn(0);
664 }
665