xref: /petsc/src/ksp/pc/impls/mg/mgfunc.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
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     PetscCall(PCMGGetRestriction(pc, l, &R));
436     PetscCall(MatCreateVecs(R, &X, &Y));
437     PetscCall(MatGetSize(R, &M, &N));
438     if (M < N) {
439       fine   = X;
440       coarse = Y;
441     } else if (N < M) {
442       fine   = Y;
443       coarse = X;
444     } else SETERRQ(PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
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(0);
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 on pc
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(0);
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 on pc
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) PetscValidPointer(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(0);
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(0);
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`, `PCMGGetSmootherUp()`, `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(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
605     PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
606     PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
607     PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
608     PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
609     PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
610     PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
611     PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
612     PetscCall(PCSetType(ipc, pctype));
613     PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
614   }
615   if (ksp) *ksp = mglevels[l]->smoothu;
616   PetscFunctionReturn(0);
617 }
618 
619 /*@
620    PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
621    coarse grid correction (pre-smoother).
622 
623    Not Collective, ksp returned is parallel if pc is
624 
625    Input Parameters:
626 +  pc - the multigrid context
627 -  l  - the level (0 is coarsest) to supply
628 
629    Output Parameter:
630 .  ksp - the smoother
631 
632    Level: advanced
633 
634    Note:
635    Calling this will result in a different pre and post smoother so you may need to
636    set options on the post smoother also
637 
638 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
639 @*/
640 PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
641 {
642   PC_MG         *mg       = (PC_MG *)pc->data;
643   PC_MG_Levels **mglevels = mg->levels;
644 
645   PetscFunctionBegin;
646   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
647   /* make sure smoother up and down are different */
648   if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
649   *ksp = mglevels[l]->smoothd;
650   PetscFunctionReturn(0);
651 }
652 
653 /*@
654    PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
655 
656    Logically Collective on pc
657 
658    Input Parameters:
659 +  pc - the multigrid context
660 .  l  - the level (0 is coarsest)
661 -  c  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
662 
663    Level: advanced
664 
665 .seealso: `PCMG`, PCMGCycleType`, `PCMGSetCycleType()`
666 @*/
667 PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
668 {
669   PC_MG         *mg       = (PC_MG *)pc->data;
670   PC_MG_Levels **mglevels = mg->levels;
671 
672   PetscFunctionBegin;
673   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
674   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
675   PetscValidLogicalCollectiveInt(pc, l, 2);
676   PetscValidLogicalCollectiveEnum(pc, c, 3);
677   mglevels[l]->cycles = c;
678   PetscFunctionReturn(0);
679 }
680 
681 /*@
682   PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
683 
684    Logically Collective on pc
685 
686   Input Parameters:
687 + pc - the multigrid context
688 . l  - the level (0 is coarsest) this is to be used for
689 - c  - the Vec
690 
691   Level: advanced
692 
693   Note:
694   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.
695 
696 .seealso: `PCMG`, `PCMGSetX()`, `PCMGSetR()`
697 @*/
698 PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
699 {
700   PC_MG         *mg       = (PC_MG *)pc->data;
701   PC_MG_Levels **mglevels = mg->levels;
702 
703   PetscFunctionBegin;
704   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
705   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
706   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
707   PetscCall(PetscObjectReference((PetscObject)c));
708   PetscCall(VecDestroy(&mglevels[l]->b));
709 
710   mglevels[l]->b = c;
711   PetscFunctionReturn(0);
712 }
713 
714 /*@
715   PCMGSetX - Sets the vector to be used to store the solution on a particular level.
716 
717   Logically Collective on pc
718 
719   Input Parameters:
720 + pc - the multigrid context
721 . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
722 - c - the Vec
723 
724   Level: advanced
725 
726   Note:
727   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.
728 
729 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
730 @*/
731 PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
732 {
733   PC_MG         *mg       = (PC_MG *)pc->data;
734   PC_MG_Levels **mglevels = mg->levels;
735 
736   PetscFunctionBegin;
737   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
738   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
739   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
740   PetscCall(PetscObjectReference((PetscObject)c));
741   PetscCall(VecDestroy(&mglevels[l]->x));
742 
743   mglevels[l]->x = c;
744   PetscFunctionReturn(0);
745 }
746 
747 /*@
748   PCMGSetR - Sets the vector to be used to store the residual on a particular level.
749 
750   Logically Collective on pc
751 
752   Input Parameters:
753 + pc - the multigrid context
754 . l - the level (0 is coarsest) this is to be used for
755 - c - the Vec
756 
757   Level: advanced
758 
759   Note:
760   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.
761 
762 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
763 @*/
764 PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
765 {
766   PC_MG         *mg       = (PC_MG *)pc->data;
767   PC_MG_Levels **mglevels = mg->levels;
768 
769   PetscFunctionBegin;
770   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
771   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
772   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
773   PetscCall(PetscObjectReference((PetscObject)c));
774   PetscCall(VecDestroy(&mglevels[l]->r));
775 
776   mglevels[l]->r = c;
777   PetscFunctionReturn(0);
778 }
779