Actual source code: mgfunc.c
1: #include <petsc/private/pcmgimpl.h>
3: /*@
4: PCMGResidualDefault - Default routine to calculate the residual.
6: Collective
8: Input Parameters:
9: + mat - the matrix
10: . b - the right-hand side
11: - x - the approximate solution
13: Output Parameter:
14: . r - location to store the residual
16: Level: developer
18: .seealso: [](ch_ksp), `PCMG`, `PCMGSetResidual()`, `PCMGSetMatResidual()`
19: @*/
20: PetscErrorCode PCMGResidualDefault(Mat mat, Vec b, Vec x, Vec r)
21: {
22: PetscFunctionBegin;
23: PetscCall(MatResidual(mat, b, x, r));
24: PetscFunctionReturn(PETSC_SUCCESS);
25: }
27: /*@
28: PCMGResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
30: Collective
32: Input Parameters:
33: + mat - the matrix
34: . b - the right-hand side
35: - x - the approximate solution
37: Output Parameter:
38: . r - location to store the residual
40: Level: developer
42: .seealso: [](ch_ksp), `PCMG`, `PCMGSetResidualTranspose()`, `PCMGMatResidualTransposeDefault()`
43: @*/
44: PetscErrorCode PCMGResidualTransposeDefault(Mat mat, Vec b, Vec x, Vec r)
45: {
46: PetscFunctionBegin;
47: PetscCall(MatMultTranspose(mat, x, r));
48: PetscCall(VecAYPX(r, -1.0, b));
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
52: /*@
53: PCMGMatResidualDefault - Default routine to calculate the residual.
55: Collective
57: Input Parameters:
58: + mat - the matrix
59: . b - the right-hand side
60: - x - the approximate solution
62: Output Parameter:
63: . r - location to store the residual
65: Level: developer
67: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidual()`, `PCMGResidualDefault()`
68: @*/
69: PetscErrorCode PCMGMatResidualDefault(Mat mat, Mat b, Mat x, Mat r)
70: {
71: PetscFunctionBegin;
72: PetscCall(MatMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_CURRENT, &r));
73: PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
74: PetscFunctionReturn(PETSC_SUCCESS);
75: }
77: /*@
78: PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
80: Collective
82: Input Parameters:
83: + mat - the matrix
84: . b - the right-hand side
85: - x - the approximate solution
87: Output Parameter:
88: . r - location to store the residual
90: Level: developer
92: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidualTranspose()`
93: @*/
94: PetscErrorCode PCMGMatResidualTransposeDefault(Mat mat, Mat b, Mat x, Mat r)
95: {
96: PetscFunctionBegin;
97: PetscCall(MatTransposeMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_CURRENT, &r));
98: PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
99: PetscFunctionReturn(PETSC_SUCCESS);
100: }
101: /*@
102: PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.
104: Not Collective
106: Input Parameter:
107: . pc - the multigrid context
109: Output Parameter:
110: . ksp - the coarse grid solver context
112: Level: advanced
114: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetSmoother()`
115: @*/
116: PetscErrorCode PCMGGetCoarseSolve(PC pc, KSP *ksp)
117: {
118: PC_MG *mg = (PC_MG *)pc->data;
119: PC_MG_Levels **mglevels = mg->levels;
121: PetscFunctionBegin;
123: *ksp = mglevels[0]->smoothd;
124: PetscFunctionReturn(PETSC_SUCCESS);
125: }
127: /*@
128: PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.
130: Logically Collective
132: Input Parameters:
133: + pc - the multigrid context
134: . l - the level (0 is coarsest) to supply
135: . residual - function used to form residual, if none is provided the previously provide one is used, if no
136: previous one were provided then a default is used
137: - mat - matrix associated with residual
139: Level: advanced
141: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualDefault()`
142: @*/
143: PetscErrorCode PCMGSetResidual(PC pc, PetscInt l, PetscErrorCode (*residual)(Mat, Vec, Vec, Vec), Mat mat)
144: {
145: PC_MG *mg = (PC_MG *)pc->data;
146: PC_MG_Levels **mglevels = mg->levels;
148: PetscFunctionBegin;
150: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
151: if (residual) mglevels[l]->residual = residual;
152: if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
153: mglevels[l]->matresidual = PCMGMatResidualDefault;
154: PetscCall(PetscObjectReference((PetscObject)mat));
155: PetscCall(MatDestroy(&mglevels[l]->A));
156: mglevels[l]->A = mat;
157: PetscFunctionReturn(PETSC_SUCCESS);
158: }
160: /*@
161: PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system
162: on the lth level.
164: Logically Collective
166: Input Parameters:
167: + pc - the multigrid context
168: . l - the level (0 is coarsest) to supply
169: . residualt - function used to form transpose of residual, if none is provided the previously provide one is used, if no
170: previous one were provided then a default is used
171: - mat - matrix associated with residual
173: Level: advanced
175: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualTransposeDefault()`
176: @*/
177: PetscErrorCode PCMGSetResidualTranspose(PC pc, PetscInt l, PetscErrorCode (*residualt)(Mat, Vec, Vec, Vec), Mat mat)
178: {
179: PC_MG *mg = (PC_MG *)pc->data;
180: PC_MG_Levels **mglevels = mg->levels;
182: PetscFunctionBegin;
184: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
185: if (residualt) mglevels[l]->residualtranspose = residualt;
186: if (!mglevels[l]->residualtranspose) mglevels[l]->residualtranspose = PCMGResidualTransposeDefault;
187: mglevels[l]->matresidualtranspose = PCMGMatResidualTransposeDefault;
188: PetscCall(PetscObjectReference((PetscObject)mat));
189: PetscCall(MatDestroy(&mglevels[l]->A));
190: mglevels[l]->A = mat;
191: PetscFunctionReturn(PETSC_SUCCESS);
192: }
194: /*@
195: PCMGSetInterpolation - Sets the function to be used to calculate the
196: interpolation from l-1 to the lth level
198: Logically Collective
200: Input Parameters:
201: + pc - the multigrid context
202: . mat - the interpolation operator
203: - l - the level (0 is coarsest) to supply [do not supply 0]
205: Level: advanced
207: Notes:
208: Usually this is the same matrix used also to set the restriction
209: for the same level.
211: One can pass in the interpolation matrix or its transpose; PETSc figures
212: out from the matrix size which one it is.
214: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
215: @*/
216: PetscErrorCode PCMGSetInterpolation(PC pc, PetscInt l, Mat mat)
217: {
218: PC_MG *mg = (PC_MG *)pc->data;
219: PC_MG_Levels **mglevels = mg->levels;
221: PetscFunctionBegin;
223: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
224: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set interpolation routine for coarsest level");
225: PetscCall(PetscObjectReference((PetscObject)mat));
226: PetscCall(MatDestroy(&mglevels[l]->interpolate));
228: mglevels[l]->interpolate = mat;
229: PetscFunctionReturn(PETSC_SUCCESS);
230: }
232: /*@
233: PCMGSetOperators - Sets operator and matrix from which to construct a preconditioner for lth level
235: Logically Collective
237: Input Parameters:
238: + pc - the multigrid context
239: . Amat - the operator
240: . Pmat - the preconditioning operator
241: - l - the level (0 is the coarsest) to supply
243: Level: advanced
245: .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()`
246: @*/
247: PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat)
248: {
249: PC_MG *mg = (PC_MG *)pc->data;
250: PC_MG_Levels **mglevels = mg->levels;
252: PetscFunctionBegin;
256: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
257: PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat));
258: PetscFunctionReturn(PETSC_SUCCESS);
259: }
261: /*@
262: PCMGGetInterpolation - Gets the function to be used to calculate the
263: interpolation from l-1 to the lth level
265: Logically Collective
267: Input Parameters:
268: + pc - the multigrid context
269: - l - the level (0 is coarsest) to supply [Do not supply 0]
271: Output Parameter:
272: . mat - the interpolation matrix, can be `NULL`
274: Level: advanced
276: .seealso: [](ch_ksp), `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()`
277: @*/
278: PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat)
279: {
280: PC_MG *mg = (PC_MG *)pc->data;
281: PC_MG_Levels **mglevels = mg->levels;
283: PetscFunctionBegin;
285: if (mat) PetscAssertPointer(mat, 3);
286: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
287: 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);
288: if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct));
289: if (mat) *mat = mglevels[l]->interpolate;
290: PetscFunctionReturn(PETSC_SUCCESS);
291: }
293: /*@
294: PCMGSetRestriction - Sets the function to be used to restrict dual vectors
295: from level l to l-1.
297: Logically Collective
299: Input Parameters:
300: + pc - the multigrid context
301: . l - the level (0 is coarsest) to supply [Do not supply 0]
302: - mat - the restriction matrix
304: Level: advanced
306: Notes:
307: Usually this is the same matrix used also to set the interpolation
308: for the same level.
310: One can pass in the interpolation matrix or its transpose; PETSc figures
311: out from the matrix size which one it is.
313: If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
314: is used.
316: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`
317: @*/
318: PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat)
319: {
320: PC_MG *mg = (PC_MG *)pc->data;
321: PC_MG_Levels **mglevels = mg->levels;
323: PetscFunctionBegin;
326: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
327: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
328: PetscCall(PetscObjectReference((PetscObject)mat));
329: PetscCall(MatDestroy(&mglevels[l]->restrct));
331: mglevels[l]->restrct = mat;
332: PetscFunctionReturn(PETSC_SUCCESS);
333: }
335: /*@
336: PCMGGetRestriction - Gets the function to be used to restrict dual (i.e. residual) vectors
337: from level l to l-1.
339: Logically Collective
341: Input Parameters:
342: + pc - the multigrid context
343: - l - the level (0 is coarsest) to supply [Do not supply 0]
345: Output Parameter:
346: . mat - the restriction matrix
348: Level: advanced
350: .seealso: [](ch_ksp), `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()`
351: @*/
352: PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat)
353: {
354: PC_MG *mg = (PC_MG *)pc->data;
355: PC_MG_Levels **mglevels = mg->levels;
357: PetscFunctionBegin;
359: if (mat) PetscAssertPointer(mat, 3);
360: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
361: 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);
362: if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate));
363: if (mat) *mat = mglevels[l]->restrct;
364: PetscFunctionReturn(PETSC_SUCCESS);
365: }
367: /*@
368: PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
370: Logically Collective
372: Input Parameters:
373: + pc - the multigrid context
374: . l - the level (0 is coarsest) to supply [Do not supply 0]
375: - rscale - the scaling
377: Level: advanced
379: Note:
380: 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.
381: It is preferable to use `PCMGSetInjection()` to control moving primal vectors.
383: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()`
384: @*/
385: PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale)
386: {
387: PC_MG *mg = (PC_MG *)pc->data;
388: PC_MG_Levels **mglevels = mg->levels;
390: PetscFunctionBegin;
392: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
393: 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);
394: PetscCall(PetscObjectReference((PetscObject)rscale));
395: PetscCall(VecDestroy(&mglevels[l]->rscale));
397: mglevels[l]->rscale = rscale;
398: PetscFunctionReturn(PETSC_SUCCESS);
399: }
401: /*@
402: PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
404: Collective
406: Input Parameters:
407: + pc - the multigrid context
408: . rscale - the scaling
409: - l - the level (0 is coarsest) to supply [Do not supply 0]
411: Level: advanced
413: Note:
414: 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.
415: It is preferable to use `PCMGGetInjection()` to control moving primal vectors.
417: The scaling is computed using vectors compatible with the matrix returned by `PCMGGetRestriction()`.
418: If this matrix is square, it is treated as an interpolation matrix and its transpose is used. For a square restriction matrix,
419: set the scaling explicitly with `PCMGSetRScale()`.
421: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`, `PCMGSetRScale()`
422: @*/
423: PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
424: {
425: PC_MG *mg = (PC_MG *)pc->data;
426: PC_MG_Levels **mglevels = mg->levels;
428: PetscFunctionBegin;
430: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
431: 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);
432: if (!mglevels[l]->rscale) {
433: Mat R;
434: Vec X, Y, coarse, fine;
435: PetscInt M, N;
437: PetscCall(PCMGGetRestriction(pc, l, &R));
438: PetscCall(MatCreateVecs(R, &X, &Y));
439: PetscCall(MatGetSize(R, &M, &N));
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(PETSC_SUCCESS);
455: }
457: /*@
458: PCMGSetInjection - Sets the function to be used to inject primal (i.e. solution) vectors
459: from level l to l-1.
461: Logically Collective
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
468: Level: advanced
470: .seealso: [](ch_ksp), `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;
477: PetscFunctionBegin;
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));
485: mglevels[l]->inject = mat;
486: PetscFunctionReturn(PETSC_SUCCESS);
487: }
489: /*@
490: PCMGGetInjection - Gets the function to be used to inject primal vectors (i.e. solutions)
491: from level l to l-1.
493: Logically Collective
495: Input Parameters:
496: + pc - the multigrid context
497: - l - the level (0 is coarsest) to supply [Do not supply 0]
499: Output Parameter:
500: . mat - the restriction matrix (may be `NULL` if no injection is available).
502: Level: advanced
504: .seealso: [](ch_ksp), `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;
511: PetscFunctionBegin;
513: if (mat) PetscAssertPointer(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(PETSC_SUCCESS);
518: }
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.
526: Not Collective, ksp returned is parallel if pc is
528: Input Parameters:
529: + pc - the multigrid context
530: - l - the level (0 is coarsest) to supply
532: Output Parameter:
533: . ksp - the smoother
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.
540: Level: advanced
542: .seealso: [](ch_ksp), `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;
549: PetscFunctionBegin;
551: *ksp = mglevels[l]->smoothd;
552: PetscFunctionReturn(PETSC_SUCCESS);
553: }
555: /*@
556: PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
557: coarse grid correction (post-smoother).
559: Not Collective, ksp returned is parallel if pc is
561: Input Parameters:
562: + pc - the multigrid context
563: - l - the level (0 is coarsest) to supply
565: Output Parameter:
566: . ksp - the smoother
568: Level: advanced
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
573: .seealso: [](ch_ksp), `PCMG`, `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;
582: PetscFunctionBegin;
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));
605: PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
606: PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
607: PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
608: PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
609: PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
610: PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
611: PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
612: PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
613: PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
614: PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
615: PetscCall(PCSetType(ipc, pctype));
616: PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
617: }
618: if (ksp) *ksp = mglevels[l]->smoothu;
619: PetscFunctionReturn(PETSC_SUCCESS);
620: }
622: /*@
623: PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
624: coarse grid correction (pre-smoother).
626: Not Collective, ksp returned is parallel if pc is
628: Input Parameters:
629: + pc - the multigrid context
630: - l - the level (0 is coarsest) to supply
632: Output Parameter:
633: . ksp - the smoother
635: Level: advanced
637: Note:
638: Calling this will result in a different pre and post smoother so you may need to
639: set options on the post smoother also
641: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
642: @*/
643: PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
644: {
645: PC_MG *mg = (PC_MG *)pc->data;
646: PC_MG_Levels **mglevels = mg->levels;
648: PetscFunctionBegin;
650: /* make sure smoother up and down are different */
651: if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
652: *ksp = mglevels[l]->smoothd;
653: PetscFunctionReturn(PETSC_SUCCESS);
654: }
656: /*@
657: PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
659: Logically Collective
661: Input Parameters:
662: + pc - the multigrid context
663: . l - the level (0 is coarsest)
664: - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
666: Level: advanced
668: .seealso: [](ch_ksp), `PCMG`, `PCMGCycleType`, `PCMGSetCycleType()`
669: @*/
670: PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
671: {
672: PC_MG *mg = (PC_MG *)pc->data;
673: PC_MG_Levels **mglevels = mg->levels;
675: PetscFunctionBegin;
677: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
680: mglevels[l]->cycles = c;
681: PetscFunctionReturn(PETSC_SUCCESS);
682: }
684: /*@
685: PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
687: Logically Collective
689: Input Parameters:
690: + pc - the multigrid context
691: . l - the level (0 is coarsest) this is to be used for
692: - c - the Vec
694: Level: advanced
696: Note:
697: 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.
699: .seealso: [](ch_ksp), `PCMG`, `PCMGSetX()`, `PCMGSetR()`
700: @*/
701: PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
702: {
703: PC_MG *mg = (PC_MG *)pc->data;
704: PC_MG_Levels **mglevels = mg->levels;
706: PetscFunctionBegin;
708: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
709: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
710: PetscCall(PetscObjectReference((PetscObject)c));
711: PetscCall(VecDestroy(&mglevels[l]->b));
713: mglevels[l]->b = c;
714: PetscFunctionReturn(PETSC_SUCCESS);
715: }
717: /*@
718: PCMGSetX - Sets the vector to be used to store the solution on a particular level.
720: Logically Collective
722: Input Parameters:
723: + pc - the multigrid context
724: . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
725: - c - the Vec
727: Level: advanced
729: Note:
730: 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.
732: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
733: @*/
734: PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
735: {
736: PC_MG *mg = (PC_MG *)pc->data;
737: PC_MG_Levels **mglevels = mg->levels;
739: PetscFunctionBegin;
741: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
742: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
743: PetscCall(PetscObjectReference((PetscObject)c));
744: PetscCall(VecDestroy(&mglevels[l]->x));
746: mglevels[l]->x = c;
747: PetscFunctionReturn(PETSC_SUCCESS);
748: }
750: /*@
751: PCMGSetR - Sets the vector to be used to store the residual on a particular level.
753: Logically Collective
755: Input Parameters:
756: + pc - the multigrid context
757: . l - the level (0 is coarsest) this is to be used for
758: - c - the Vec
760: Level: advanced
762: Note:
763: 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.
765: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
766: @*/
767: PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
768: {
769: PC_MG *mg = (PC_MG *)pc->data;
770: PC_MG_Levels **mglevels = mg->levels;
772: PetscFunctionBegin;
774: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
775: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
776: PetscCall(PetscObjectReference((PetscObject)c));
777: PetscCall(VecDestroy(&mglevels[l]->r));
779: mglevels[l]->r = c;
780: PetscFunctionReturn(PETSC_SUCCESS);
781: }