xref: /petsc/src/ksp/pc/impls/mg/mgfunc.c (revision a4e35b1925eceef64945ea472b84f2bf06a67b5e)
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
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(PETSC_SUCCESS);
26 }
27 
28 /*@C
29   PCMGResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
30 
31   Collective
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(PETSC_SUCCESS);
51 }
52 
53 /*@C
54   PCMGMatResidualDefault - Default routine to calculate the residual.
55 
56   Collective
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(PETSC_SUCCESS);
76 }
77 
78 /*@C
79   PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
80 
81   Collective
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
126 }
127 
128 /*@C
129   PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.
130 
131   Logically Collective
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(PETSC_SUCCESS);
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
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(PETSC_SUCCESS);
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
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(PETSC_SUCCESS);
231 }
232 
233 /*@
234   PCMGSetOperators - Sets operator and preconditioning matrix for lth level
235 
236   Logically Collective
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 .seealso: `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()`
247 @*/
248 PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat)
249 {
250   PC_MG         *mg       = (PC_MG *)pc->data;
251   PC_MG_Levels **mglevels = mg->levels;
252 
253   PetscFunctionBegin;
254   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
255   PetscValidHeaderSpecific(Amat, MAT_CLASSID, 3);
256   PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 4);
257   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
258   PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat));
259   PetscFunctionReturn(PETSC_SUCCESS);
260 }
261 
262 /*@
263   PCMGGetInterpolation - Gets the function to be used to calculate the
264   interpolation from l-1 to the lth level
265 
266   Logically Collective
267 
268   Input Parameters:
269 + pc - the multigrid context
270 - l  - the level (0 is coarsest) to supply [Do not supply 0]
271 
272   Output Parameter:
273 . mat - the interpolation matrix, can be `NULL`
274 
275   Level: advanced
276 
277 .seealso: `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()`
278 @*/
279 PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat)
280 {
281   PC_MG         *mg       = (PC_MG *)pc->data;
282   PC_MG_Levels **mglevels = mg->levels;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
286   if (mat) PetscAssertPointer(mat, 3);
287   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
288   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);
289   if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct));
290   if (mat) *mat = mglevels[l]->interpolate;
291   PetscFunctionReturn(PETSC_SUCCESS);
292 }
293 
294 /*@
295   PCMGSetRestriction - Sets the function to be used to restrict dual vectors
296   from level l to l-1.
297 
298   Logically Collective
299 
300   Input Parameters:
301 + pc  - the multigrid context
302 . l   - the level (0 is coarsest) to supply [Do not supply 0]
303 - mat - the restriction matrix
304 
305   Level: advanced
306 
307   Notes:
308   Usually this is the same matrix used also to set the interpolation
309   for the same level.
310 
311   One can pass in the interpolation matrix or its transpose; PETSc figures
312   out from the matrix size which one it is.
313 
314   If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
315   is used.
316 
317 .seealso: `PCMG`, `PCMGSetInterpolation()`
318 @*/
319 PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat)
320 {
321   PC_MG         *mg       = (PC_MG *)pc->data;
322   PC_MG_Levels **mglevels = mg->levels;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
326   PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
327   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
328   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
329   PetscCall(PetscObjectReference((PetscObject)mat));
330   PetscCall(MatDestroy(&mglevels[l]->restrct));
331 
332   mglevels[l]->restrct = mat;
333   PetscFunctionReturn(PETSC_SUCCESS);
334 }
335 
336 /*@
337   PCMGGetRestriction - Gets the function to be used to restrict dual vectors
338   from level l to l-1.
339 
340   Logically Collective
341 
342   Input Parameters:
343 + pc - the multigrid context
344 - l  - the level (0 is coarsest) to supply [Do not supply 0]
345 
346   Output Parameter:
347 . mat - the restriction matrix
348 
349   Level: advanced
350 
351 .seealso: `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()`
352 @*/
353 PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat)
354 {
355   PC_MG         *mg       = (PC_MG *)pc->data;
356   PC_MG_Levels **mglevels = mg->levels;
357 
358   PetscFunctionBegin;
359   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
360   if (mat) PetscAssertPointer(mat, 3);
361   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
362   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);
363   if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate));
364   if (mat) *mat = mglevels[l]->restrct;
365   PetscFunctionReturn(PETSC_SUCCESS);
366 }
367 
368 /*@
369   PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
370 
371   Logically Collective
372 
373   Input Parameters:
374 + pc     - the multigrid context
375 . l      - the level (0 is coarsest) to supply [Do not supply 0]
376 - rscale - the scaling
377 
378   Level: advanced
379 
380   Note:
381   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.
382   It is preferable to use `PCMGSetInjection()` to control moving primal vectors.
383 
384 .seealso: `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()`
385 @*/
386 PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale)
387 {
388   PC_MG         *mg       = (PC_MG *)pc->data;
389   PC_MG_Levels **mglevels = mg->levels;
390 
391   PetscFunctionBegin;
392   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
393   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
394   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);
395   PetscCall(PetscObjectReference((PetscObject)rscale));
396   PetscCall(VecDestroy(&mglevels[l]->rscale));
397 
398   mglevels[l]->rscale = rscale;
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
402 /*@
403   PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
404 
405   Collective
406 
407   Input Parameters:
408 + pc     - the multigrid context
409 . rscale - the scaling
410 - l      - the level (0 is coarsest) to supply [Do not supply 0]
411 
412   Level: advanced
413 
414   Note:
415   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.
416   It is preferable to use `PCMGGetInjection()` to control moving primal vectors.
417 
418 .seealso: `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`
419 @*/
420 PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
421 {
422   PC_MG         *mg       = (PC_MG *)pc->data;
423   PC_MG_Levels **mglevels = mg->levels;
424 
425   PetscFunctionBegin;
426   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
427   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
428   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);
429   if (!mglevels[l]->rscale) {
430     Mat      R;
431     Vec      X, Y, coarse, fine;
432     PetscInt M, N;
433 
434     PetscCall(PCMGGetRestriction(pc, l, &R));
435     PetscCall(MatCreateVecs(R, &X, &Y));
436     PetscCall(MatGetSize(R, &M, &N));
437     PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
438     if (M < N) {
439       fine   = X;
440       coarse = Y;
441     } else {
442       fine   = Y;
443       coarse = X;
444     }
445     PetscCall(VecSet(fine, 1.));
446     PetscCall(MatRestrict(R, fine, coarse));
447     PetscCall(VecDestroy(&fine));
448     PetscCall(VecReciprocal(coarse));
449     mglevels[l]->rscale = coarse;
450   }
451   *rscale = mglevels[l]->rscale;
452   PetscFunctionReturn(PETSC_SUCCESS);
453 }
454 
455 /*@
456   PCMGSetInjection - Sets the function to be used to inject primal vectors
457   from level l to l-1.
458 
459   Logically Collective
460 
461   Input Parameters:
462 + pc  - the multigrid context
463 . l   - the level (0 is coarsest) to supply [Do not supply 0]
464 - mat - the injection matrix
465 
466   Level: advanced
467 
468 .seealso: `PCMG`, `PCMGSetRestriction()`
469 @*/
470 PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat)
471 {
472   PC_MG         *mg       = (PC_MG *)pc->data;
473   PC_MG_Levels **mglevels = mg->levels;
474 
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
477   PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
478   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
479   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
480   PetscCall(PetscObjectReference((PetscObject)mat));
481   PetscCall(MatDestroy(&mglevels[l]->inject));
482 
483   mglevels[l]->inject = mat;
484   PetscFunctionReturn(PETSC_SUCCESS);
485 }
486 
487 /*@
488   PCMGGetInjection - Gets the function to be used to inject primal vectors
489   from level l to l-1.
490 
491   Logically Collective
492 
493   Input Parameters:
494 + pc - the multigrid context
495 - l  - the level (0 is coarsest) to supply [Do not supply 0]
496 
497   Output Parameter:
498 . mat - the restriction matrix (may be NULL if no injection is available).
499 
500   Level: advanced
501 
502 .seealso: `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()`
503 @*/
504 PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat)
505 {
506   PC_MG         *mg       = (PC_MG *)pc->data;
507   PC_MG_Levels **mglevels = mg->levels;
508 
509   PetscFunctionBegin;
510   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
511   if (mat) PetscAssertPointer(mat, 3);
512   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
513   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);
514   if (mat) *mat = mglevels[l]->inject;
515   PetscFunctionReturn(PETSC_SUCCESS);
516 }
517 
518 /*@
519   PCMGGetSmoother - Gets the `KSP` context to be used as smoother for
520   both pre- and post-smoothing.  Call both `PCMGGetSmootherUp()` and
521   `PCMGGetSmootherDown()` to use different functions for pre- and
522   post-smoothing.
523 
524   Not Collective, ksp returned is parallel if pc is
525 
526   Input Parameters:
527 + pc - the multigrid context
528 - l  - the level (0 is coarsest) to supply
529 
530   Output Parameter:
531 . ksp - the smoother
532 
533   Note:
534   Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level.
535   You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc)
536   and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing.
537 
538   Level: advanced
539 
540 .seealso: `PCMG`, ``PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()`
541 @*/
542 PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp)
543 {
544   PC_MG         *mg       = (PC_MG *)pc->data;
545   PC_MG_Levels **mglevels = mg->levels;
546 
547   PetscFunctionBegin;
548   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
549   *ksp = mglevels[l]->smoothd;
550   PetscFunctionReturn(PETSC_SUCCESS);
551 }
552 
553 /*@
554   PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
555   coarse grid correction (post-smoother).
556 
557   Not Collective, ksp returned is parallel if pc is
558 
559   Input Parameters:
560 + pc - the multigrid context
561 - l  - the level (0 is coarsest) to supply
562 
563   Output Parameter:
564 . ksp - the smoother
565 
566   Level: advanced
567 
568   Note:
569   Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also
570 
571 .seealso: `PCMG`, `PCMGGetSmootherDown()`
572 @*/
573 PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp)
574 {
575   PC_MG         *mg       = (PC_MG *)pc->data;
576   PC_MG_Levels **mglevels = mg->levels;
577   const char    *prefix;
578   MPI_Comm       comm;
579 
580   PetscFunctionBegin;
581   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
582   /*
583      This is called only if user wants a different pre-smoother from post.
584      Thus we check if a different one has already been allocated,
585      if not we allocate it.
586   */
587   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid");
588   if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
589     KSPType     ksptype;
590     PCType      pctype;
591     PC          ipc;
592     PetscReal   rtol, abstol, dtol;
593     PetscInt    maxits;
594     KSPNormType normtype;
595     PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm));
596     PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix));
597     PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits));
598     PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype));
599     PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype));
600     PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc));
601     PetscCall(PCGetType(ipc, &pctype));
602 
603     PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
604     PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
605     PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
606     PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
607     PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
608     PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
609     PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
610     PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
611     PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
612     PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
613     PetscCall(PCSetType(ipc, pctype));
614     PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
615   }
616   if (ksp) *ksp = mglevels[l]->smoothu;
617   PetscFunctionReturn(PETSC_SUCCESS);
618 }
619 
620 /*@
621   PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
622   coarse grid correction (pre-smoother).
623 
624   Not Collective, ksp returned is parallel if pc is
625 
626   Input Parameters:
627 + pc - the multigrid context
628 - l  - the level (0 is coarsest) to supply
629 
630   Output Parameter:
631 . ksp - the smoother
632 
633   Level: advanced
634 
635   Note:
636   Calling this will result in a different pre and post smoother so you may need to
637   set options on the post smoother also
638 
639 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
640 @*/
641 PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
642 {
643   PC_MG         *mg       = (PC_MG *)pc->data;
644   PC_MG_Levels **mglevels = mg->levels;
645 
646   PetscFunctionBegin;
647   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
648   /* make sure smoother up and down are different */
649   if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
650   *ksp = mglevels[l]->smoothd;
651   PetscFunctionReturn(PETSC_SUCCESS);
652 }
653 
654 /*@
655   PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
656 
657   Logically Collective
658 
659   Input Parameters:
660 + pc - the multigrid context
661 . l  - the level (0 is coarsest)
662 - c  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
663 
664   Level: advanced
665 
666 .seealso: `PCMG`, `PCMGCycleType`, `PCMGSetCycleType()`
667 @*/
668 PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
669 {
670   PC_MG         *mg       = (PC_MG *)pc->data;
671   PC_MG_Levels **mglevels = mg->levels;
672 
673   PetscFunctionBegin;
674   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
675   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
676   PetscValidLogicalCollectiveInt(pc, l, 2);
677   PetscValidLogicalCollectiveEnum(pc, c, 3);
678   mglevels[l]->cycles = c;
679   PetscFunctionReturn(PETSC_SUCCESS);
680 }
681 
682 /*@
683   PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
684 
685   Logically Collective
686 
687   Input Parameters:
688 + pc - the multigrid context
689 . l  - the level (0 is coarsest) this is to be used for
690 - c  - the Vec
691 
692   Level: advanced
693 
694   Note:
695   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.
696 
697 .seealso: `PCMG`, `PCMGSetX()`, `PCMGSetR()`
698 @*/
699 PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
700 {
701   PC_MG         *mg       = (PC_MG *)pc->data;
702   PC_MG_Levels **mglevels = mg->levels;
703 
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
706   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
707   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
708   PetscCall(PetscObjectReference((PetscObject)c));
709   PetscCall(VecDestroy(&mglevels[l]->b));
710 
711   mglevels[l]->b = c;
712   PetscFunctionReturn(PETSC_SUCCESS);
713 }
714 
715 /*@
716   PCMGSetX - Sets the vector to be used to store the solution on a particular level.
717 
718   Logically Collective
719 
720   Input Parameters:
721 + pc - the multigrid context
722 . l  - the level (0 is coarsest) this is to be used for (do not supply the finest level)
723 - c  - the Vec
724 
725   Level: advanced
726 
727   Note:
728   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.
729 
730 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
731 @*/
732 PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
733 {
734   PC_MG         *mg       = (PC_MG *)pc->data;
735   PC_MG_Levels **mglevels = mg->levels;
736 
737   PetscFunctionBegin;
738   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
739   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
740   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
741   PetscCall(PetscObjectReference((PetscObject)c));
742   PetscCall(VecDestroy(&mglevels[l]->x));
743 
744   mglevels[l]->x = c;
745   PetscFunctionReturn(PETSC_SUCCESS);
746 }
747 
748 /*@
749   PCMGSetR - Sets the vector to be used to store the residual on a particular level.
750 
751   Logically Collective
752 
753   Input Parameters:
754 + pc - the multigrid context
755 . l  - the level (0 is coarsest) this is to be used for
756 - c  - the Vec
757 
758   Level: advanced
759 
760   Note:
761   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.
762 
763 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
764 @*/
765 PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
766 {
767   PC_MG         *mg       = (PC_MG *)pc->data;
768   PC_MG_Levels **mglevels = mg->levels;
769 
770   PetscFunctionBegin;
771   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
772   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
773   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
774   PetscCall(PetscObjectReference((PetscObject)c));
775   PetscCall(VecDestroy(&mglevels[l]->r));
776 
777   mglevels[l]->r = c;
778   PetscFunctionReturn(PETSC_SUCCESS);
779 }
780