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