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