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