xref: /petsc/src/ksp/pc/impls/mg/mgfunc.c (revision 4fc747eaadbeca11629f314a99edccbc2ed7b3d3)
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, can be NULL
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   if (mat) 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 PCMGSetRestriction()");
178     ierr = PCMGSetInterpolation(pc,l,mglevels[l]->restrct);CHKERRQ(ierr);
179   }
180   if (mat) *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   if (mat) 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   if (mat) *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     ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level);CHKERRQ(ierr);
469   }
470   if (ksp) *ksp = mglevels[l]->smoothu;
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "PCMGGetSmootherDown"
476 /*@
477    PCMGGetSmootherDown - Gets the KSP context to be used as smoother before
478    coarse grid correction (pre-smoother).
479 
480    Not Collective, KSP returned is parallel if PC is
481 
482    Input Parameters:
483 +  pc - the multigrid context
484 -  l  - the level (0 is coarsest) to supply
485 
486    Ouput Parameters:
487 .  ksp - the smoother
488 
489    Level: advanced
490 
491    Notes: calling this will result in a different pre and post smoother so you may need to
492          set options on the post smoother also
493 
494 .keywords: MG, multigrid, get, smoother, down, pre-smoother, level
495 
496 .seealso: PCMGGetSmootherUp(), PCMGGetSmoother()
497 @*/
498 PetscErrorCode  PCMGGetSmootherDown(PC pc,PetscInt l,KSP *ksp)
499 {
500   PetscErrorCode ierr;
501   PC_MG          *mg        = (PC_MG*)pc->data;
502   PC_MG_Levels   **mglevels = mg->levels;
503 
504   PetscFunctionBegin;
505   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
506   /* make sure smoother up and down are different */
507   if (l) {
508     ierr = PCMGGetSmootherUp(pc,l,NULL);CHKERRQ(ierr);
509   }
510   *ksp = mglevels[l]->smoothd;
511   PetscFunctionReturn(0);
512 }
513 
514 #undef __FUNCT__
515 #define __FUNCT__ "PCMGSetCyclesOnLevel"
516 /*@
517    PCMGSetCyclesOnLevel - Sets the number of cycles to run on this level.
518 
519    Logically Collective on PC
520 
521    Input Parameters:
522 +  pc - the multigrid context
523 .  l  - the level (0 is coarsest) this is to be used for
524 -  n  - the number of cycles
525 
526    Level: advanced
527 
528 .keywords: MG, multigrid, set, cycles, V-cycle, W-cycle, level
529 
530 .seealso: PCMGSetCycles()
531 @*/
532 PetscErrorCode  PCMGSetCyclesOnLevel(PC pc,PetscInt l,PetscInt c)
533 {
534   PC_MG        *mg        = (PC_MG*)pc->data;
535   PC_MG_Levels **mglevels = mg->levels;
536 
537   PetscFunctionBegin;
538   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
539   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
540   PetscValidLogicalCollectiveInt(pc,l,2);
541   PetscValidLogicalCollectiveInt(pc,c,3);
542   mglevels[l]->cycles = c;
543   PetscFunctionReturn(0);
544 }
545 
546 #undef __FUNCT__
547 #define __FUNCT__ "PCMGSetRhs"
548 /*@
549    PCMGSetRhs - Sets the vector space to be used to store the right-hand side
550    on a particular level.
551 
552    Logically Collective on PC and Vec
553 
554    Input Parameters:
555 +  pc - the multigrid context
556 .  l  - the level (0 is coarsest) this is to be used for
557 -  c  - the space
558 
559    Level: advanced
560 
561    Notes: If this is not provided PETSc will automatically generate one.
562 
563           You do not need to keep a reference to this vector if you do
564           not need it PCDestroy() will properly free it.
565 
566 .keywords: MG, multigrid, set, right-hand-side, rhs, level
567 
568 .seealso: PCMGSetX(), PCMGSetR()
569 @*/
570 PetscErrorCode  PCMGSetRhs(PC pc,PetscInt l,Vec c)
571 {
572   PetscErrorCode ierr;
573   PC_MG          *mg        = (PC_MG*)pc->data;
574   PC_MG_Levels   **mglevels = mg->levels;
575 
576   PetscFunctionBegin;
577   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
578   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
579   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set rhs for finest level");
580   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
581   ierr = VecDestroy(&mglevels[l]->b);CHKERRQ(ierr);
582 
583   mglevels[l]->b = c;
584   PetscFunctionReturn(0);
585 }
586 
587 #undef __FUNCT__
588 #define __FUNCT__ "PCMGSetX"
589 /*@
590    PCMGSetX - Sets the vector space to be used to store the solution on a
591    particular level.
592 
593    Logically Collective on PC and Vec
594 
595    Input Parameters:
596 +  pc - the multigrid context
597 .  l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
598 -  c - the space
599 
600    Level: advanced
601 
602    Notes: If this is not provided PETSc will automatically generate one.
603 
604           You do not need to keep a reference to this vector if you do
605           not need it PCDestroy() will properly free it.
606 
607 .keywords: MG, multigrid, set, solution, level
608 
609 .seealso: PCMGSetRhs(), PCMGSetR()
610 @*/
611 PetscErrorCode  PCMGSetX(PC pc,PetscInt l,Vec c)
612 {
613   PetscErrorCode ierr;
614   PC_MG          *mg        = (PC_MG*)pc->data;
615   PC_MG_Levels   **mglevels = mg->levels;
616 
617   PetscFunctionBegin;
618   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
619   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
620   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set x for finest level");
621   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
622   ierr = VecDestroy(&mglevels[l]->x);CHKERRQ(ierr);
623 
624   mglevels[l]->x = c;
625   PetscFunctionReturn(0);
626 }
627 
628 #undef __FUNCT__
629 #define __FUNCT__ "PCMGSetR"
630 /*@
631    PCMGSetR - Sets the vector space to be used to store the residual on a
632    particular level.
633 
634    Logically Collective on PC and Vec
635 
636    Input Parameters:
637 +  pc - the multigrid context
638 .  l - the level (0 is coarsest) this is to be used for
639 -  c - the space
640 
641    Level: advanced
642 
643    Notes: If this is not provided PETSc will automatically generate one.
644 
645           You do not need to keep a reference to this vector if you do
646           not need it PCDestroy() will properly free it.
647 
648 .keywords: MG, multigrid, set, residual, level
649 @*/
650 PetscErrorCode  PCMGSetR(PC pc,PetscInt l,Vec c)
651 {
652   PetscErrorCode ierr;
653   PC_MG          *mg        = (PC_MG*)pc->data;
654   PC_MG_Levels   **mglevels = mg->levels;
655 
656   PetscFunctionBegin;
657   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
658   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
659   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Need not set residual vector for coarse grid");
660   ierr = PetscObjectReference((PetscObject)c);CHKERRQ(ierr);
661   ierr = VecDestroy(&mglevels[l]->r);CHKERRQ(ierr);
662 
663   mglevels[l]->r = c;
664   PetscFunctionReturn(0);
665 }
666