Actual source code: mgfunc.c
1: #include <petsc/private/pcmgimpl.h>
2: #include <petsc/private/matimpl.h>
4: /*@
5: PCMGResidualDefault - Default routine to calculate the residual.
7: Collective
9: Input Parameters:
10: + mat - the matrix
11: . b - the right-hand side
12: - x - the approximate solution
14: Output Parameter:
15: . r - location to store the residual
17: Level: developer
19: .seealso: [](ch_ksp), `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: }
28: /*@
29: PCMGResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
31: Collective
33: Input Parameters:
34: + mat - the matrix
35: . b - the right-hand side
36: - x - the approximate solution
38: Output Parameter:
39: . r - location to store the residual
41: Level: developer
43: .seealso: [](ch_ksp), `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: }
53: /*@
54: PCMGMatResidualDefault - Default routine to calculate the residual.
56: Collective
58: Input Parameters:
59: + mat - the matrix
60: . b - the right-hand side
61: - x - the approximate solution
63: Output Parameter:
64: . r - location to store the residual
66: Level: developer
68: Note:
69: When `r` is dense, the `MatProduct` computing it stays attached to `r`, so that later calls with the same `mat` and nonzero pattern only run
70: its numeric phase; it keeps references to `mat` and `x` until `MatProductClear()` is called on `r` or `r` is destroyed.
72: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidual()`, `PCMGResidualDefault()`
73: @*/
74: PetscErrorCode PCMGMatResidualDefault(Mat mat, Mat b, Mat x, Mat r)
75: {
76: PetscFunctionBegin;
77: PetscCall(MatProductComputeWithMat_Private(mat, x, MATPRODUCT_AB, r));
78: PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
79: PetscFunctionReturn(PETSC_SUCCESS);
80: }
82: /*@
83: PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
85: Collective
87: Input Parameters:
88: + mat - the matrix
89: . b - the right-hand side
90: - x - the approximate solution
92: Output Parameter:
93: . r - location to store the residual
95: Level: developer
97: Note:
98: When `r` is dense, the `MatProduct` computing it stays attached to `r`, so that later calls with the same `mat` and nonzero pattern only run
99: its numeric phase; it keeps references to `mat` and `x` until `MatProductClear()` is called on `r` or `r` is destroyed.
101: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidualTranspose()`
102: @*/
103: PetscErrorCode PCMGMatResidualTransposeDefault(Mat mat, Mat b, Mat x, Mat r)
104: {
105: PetscFunctionBegin;
106: PetscCall(MatProductComputeWithMat_Private(mat, x, MATPRODUCT_AtB, r));
107: PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
108: PetscFunctionReturn(PETSC_SUCCESS);
109: }
110: /*@
111: PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.
113: Not Collective
115: Input Parameter:
116: . pc - the multigrid context
118: Output Parameter:
119: . ksp - the coarse grid solver context
121: Level: advanced
123: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetSmoother()`
124: @*/
125: PetscErrorCode PCMGGetCoarseSolve(PC pc, KSP *ksp)
126: {
127: PC_MG *mg = (PC_MG *)pc->data;
128: PC_MG_Levels **mglevels = mg->levels;
130: PetscFunctionBegin;
132: *ksp = mglevels[0]->smoothd;
133: PetscFunctionReturn(PETSC_SUCCESS);
134: }
136: /*@
137: PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.
139: Logically Collective
141: Input Parameters:
142: + pc - the multigrid context
143: . l - the level (0 is coarsest) to supply
144: . residual - function used to form residual, if none is provided the previously provide one is used, if no
145: previous one were provided then a default is used
146: - mat - matrix associated with residual
148: Level: advanced
150: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualDefault()`
151: @*/
152: PetscErrorCode PCMGSetResidual(PC pc, PetscInt l, PetscErrorCode (*residual)(Mat, Vec, Vec, Vec), Mat mat)
153: {
154: PC_MG *mg = (PC_MG *)pc->data;
155: PC_MG_Levels **mglevels = mg->levels;
157: PetscFunctionBegin;
159: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
160: if (residual) mglevels[l]->residual = residual;
161: if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
162: mglevels[l]->matresidual = PCMGMatResidualDefault;
163: PetscCall(PetscObjectReference((PetscObject)mat));
164: PetscCall(MatDestroy(&mglevels[l]->A));
165: mglevels[l]->A = mat;
166: PetscFunctionReturn(PETSC_SUCCESS);
167: }
169: /*@
170: PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system
171: on the lth level.
173: Logically Collective
175: Input Parameters:
176: + pc - the multigrid context
177: . l - the level (0 is coarsest) to supply
178: . residualt - function used to form transpose of residual, if none is provided the previously provide one is used, if no
179: previous one were provided then a default is used
180: - mat - matrix associated with residual
182: Level: advanced
184: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualTransposeDefault()`
185: @*/
186: PetscErrorCode PCMGSetResidualTranspose(PC pc, PetscInt l, PetscErrorCode (*residualt)(Mat, Vec, Vec, Vec), Mat mat)
187: {
188: PC_MG *mg = (PC_MG *)pc->data;
189: PC_MG_Levels **mglevels = mg->levels;
191: PetscFunctionBegin;
193: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
194: if (residualt) mglevels[l]->residualtranspose = residualt;
195: if (!mglevels[l]->residualtranspose) mglevels[l]->residualtranspose = PCMGResidualTransposeDefault;
196: mglevels[l]->matresidualtranspose = PCMGMatResidualTransposeDefault;
197: PetscCall(PetscObjectReference((PetscObject)mat));
198: PetscCall(MatDestroy(&mglevels[l]->A));
199: mglevels[l]->A = mat;
200: PetscFunctionReturn(PETSC_SUCCESS);
201: }
203: /*@
204: PCMGSetInterpolation - Sets the function to be used to calculate the
205: interpolation from l-1 to the lth level
207: Logically Collective
209: Input Parameters:
210: + pc - the multigrid context
211: . mat - the interpolation operator
212: - l - the level (0 is coarsest) to supply [do not supply 0]
214: Level: advanced
216: Notes:
217: Usually this is the same matrix used also to set the restriction
218: for the same level.
220: One can pass in the interpolation matrix or its transpose; PETSc figures
221: out from the matrix size which one it is.
223: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
224: @*/
225: PetscErrorCode PCMGSetInterpolation(PC pc, PetscInt l, Mat mat)
226: {
227: PC_MG *mg = (PC_MG *)pc->data;
228: PC_MG_Levels **mglevels = mg->levels;
230: PetscFunctionBegin;
232: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
233: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set interpolation routine for coarsest level");
234: if (mat != mglevels[l]->interpolate) PetscCall(PCMGResetBlocks_Private(pc)); /* the kept block products were set up with the old matrix */
235: PetscCall(PetscObjectReference((PetscObject)mat));
236: PetscCall(MatDestroy(&mglevels[l]->interpolate));
238: mglevels[l]->interpolate = mat;
239: PetscFunctionReturn(PETSC_SUCCESS);
240: }
242: /*@
243: PCMGSetOperators - Sets operator and matrix from which to construct a preconditioner for lth level
245: Logically Collective
247: Input Parameters:
248: + pc - the multigrid context
249: . Amat - the operator
250: . Pmat - the preconditioning operator
251: - l - the level (0 is the coarsest) to supply
253: Level: advanced
255: .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()`
256: @*/
257: PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat)
258: {
259: PC_MG *mg = (PC_MG *)pc->data;
260: PC_MG_Levels **mglevels = mg->levels;
262: PetscFunctionBegin;
266: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
267: PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat));
268: PetscFunctionReturn(PETSC_SUCCESS);
269: }
271: /*@
272: PCMGGetInterpolation - Gets the function to be used to calculate the
273: interpolation from l-1 to the lth level
275: Logically Collective
277: Input Parameters:
278: + pc - the multigrid context
279: - l - the level (0 is coarsest) to supply [Do not supply 0]
281: Output Parameter:
282: . mat - the interpolation matrix, can be `NULL`
284: Level: advanced
286: .seealso: [](ch_ksp), `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()`
287: @*/
288: PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat)
289: {
290: PC_MG *mg = (PC_MG *)pc->data;
291: PC_MG_Levels **mglevels = mg->levels;
293: PetscFunctionBegin;
295: if (mat) PetscAssertPointer(mat, 3);
296: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
297: 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);
298: if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct));
299: if (mat) *mat = mglevels[l]->interpolate;
300: PetscFunctionReturn(PETSC_SUCCESS);
301: }
303: /*@
304: PCMGSetRestriction - Sets the function to be used to restrict dual vectors
305: from level l to l-1.
307: Logically Collective
309: Input Parameters:
310: + pc - the multigrid context
311: . l - the level (0 is coarsest) to supply [Do not supply 0]
312: - mat - the restriction matrix
314: Level: advanced
316: Notes:
317: Usually this is the same matrix used also to set the interpolation
318: for the same level.
320: One can pass in the interpolation matrix or its transpose; PETSc figures
321: out from the matrix size which one it is.
323: If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
324: is used.
326: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`
327: @*/
328: PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat)
329: {
330: PC_MG *mg = (PC_MG *)pc->data;
331: PC_MG_Levels **mglevels = mg->levels;
333: PetscFunctionBegin;
336: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
337: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
338: if (mat != mglevels[l]->restrct) PetscCall(PCMGResetBlocks_Private(pc)); /* the kept block products were set up with the old matrix */
339: PetscCall(PetscObjectReference((PetscObject)mat));
340: PetscCall(MatDestroy(&mglevels[l]->restrct));
342: mglevels[l]->restrct = mat;
343: PetscFunctionReturn(PETSC_SUCCESS);
344: }
346: /*@
347: PCMGGetRestriction - Gets the function to be used to restrict dual (i.e. residual) vectors
348: from level l to l-1.
350: Logically Collective
352: Input Parameters:
353: + pc - the multigrid context
354: - l - the level (0 is coarsest) to supply [Do not supply 0]
356: Output Parameter:
357: . mat - the restriction matrix
359: Level: advanced
361: .seealso: [](ch_ksp), `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()`
362: @*/
363: PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat)
364: {
365: PC_MG *mg = (PC_MG *)pc->data;
366: PC_MG_Levels **mglevels = mg->levels;
368: PetscFunctionBegin;
370: if (mat) PetscAssertPointer(mat, 3);
371: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
372: 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);
373: if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate));
374: if (mat) *mat = mglevels[l]->restrct;
375: PetscFunctionReturn(PETSC_SUCCESS);
376: }
378: /*@
379: PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
381: Logically Collective
383: Input Parameters:
384: + pc - the multigrid context
385: . l - the level (0 is coarsest) to supply [Do not supply 0]
386: - rscale - the scaling
388: Level: advanced
390: Note:
391: 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.
392: It is preferable to use `PCMGSetInjection()` to control moving primal vectors.
394: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()`
395: @*/
396: PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale)
397: {
398: PC_MG *mg = (PC_MG *)pc->data;
399: PC_MG_Levels **mglevels = mg->levels;
401: PetscFunctionBegin;
403: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
404: 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);
405: PetscCall(PetscObjectReference((PetscObject)rscale));
406: PetscCall(VecDestroy(&mglevels[l]->rscale));
408: mglevels[l]->rscale = rscale;
409: PetscFunctionReturn(PETSC_SUCCESS);
410: }
412: /*@
413: PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
415: Collective
417: Input Parameters:
418: + pc - the multigrid context
419: . rscale - the scaling
420: - l - the level (0 is coarsest) to supply [Do not supply 0]
422: Level: advanced
424: Note:
425: 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.
426: It is preferable to use `PCMGGetInjection()` to control moving primal vectors.
428: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`
429: @*/
430: PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
431: {
432: PC_MG *mg = (PC_MG *)pc->data;
433: PC_MG_Levels **mglevels = mg->levels;
435: PetscFunctionBegin;
437: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
438: 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);
439: if (!mglevels[l]->rscale) {
440: Mat R;
441: Vec X, Y, coarse, fine;
442: PetscInt M, N;
444: PetscCall(PCMGGetRestriction(pc, l, &R));
445: PetscCall(MatCreateVecs(R, &X, &Y));
446: PetscCall(MatGetSize(R, &M, &N));
447: PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
448: if (M < N) {
449: fine = X;
450: coarse = Y;
451: } else {
452: fine = Y;
453: coarse = X;
454: }
455: PetscCall(VecSet(fine, 1.));
456: PetscCall(MatRestrict(R, fine, coarse));
457: PetscCall(VecDestroy(&fine));
458: PetscCall(VecReciprocal(coarse));
459: mglevels[l]->rscale = coarse;
460: }
461: *rscale = mglevels[l]->rscale;
462: PetscFunctionReturn(PETSC_SUCCESS);
463: }
465: /*@
466: PCMGSetInjection - Sets the function to be used to inject primal (i.e. solution) vectors
467: from level l to l-1.
469: Logically Collective
471: Input Parameters:
472: + pc - the multigrid context
473: . l - the level (0 is coarsest) to supply [Do not supply 0]
474: - mat - the injection matrix
476: Level: advanced
478: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
479: @*/
480: PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat)
481: {
482: PC_MG *mg = (PC_MG *)pc->data;
483: PC_MG_Levels **mglevels = mg->levels;
485: PetscFunctionBegin;
488: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
489: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
490: PetscCall(PetscObjectReference((PetscObject)mat));
491: PetscCall(MatDestroy(&mglevels[l]->inject));
493: mglevels[l]->inject = mat;
494: PetscFunctionReturn(PETSC_SUCCESS);
495: }
497: /*@
498: PCMGGetInjection - Gets the function to be used to inject primal vectors (i.e. solutions)
499: from level l to l-1.
501: Logically Collective
503: Input Parameters:
504: + pc - the multigrid context
505: - l - the level (0 is coarsest) to supply [Do not supply 0]
507: Output Parameter:
508: . mat - the restriction matrix (may be `NULL` if no injection is available).
510: Level: advanced
512: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()`
513: @*/
514: PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat)
515: {
516: PC_MG *mg = (PC_MG *)pc->data;
517: PC_MG_Levels **mglevels = mg->levels;
519: PetscFunctionBegin;
521: if (mat) PetscAssertPointer(mat, 3);
522: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
523: 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);
524: if (mat) *mat = mglevels[l]->inject;
525: PetscFunctionReturn(PETSC_SUCCESS);
526: }
528: /*@
529: PCMGGetSmoother - Gets the `KSP` context to be used as smoother for
530: both pre- and post-smoothing. Call both `PCMGGetSmootherUp()` and
531: `PCMGGetSmootherDown()` to use different functions for pre- and
532: post-smoothing.
534: Not Collective, ksp returned is parallel if pc is
536: Input Parameters:
537: + pc - the multigrid context
538: - l - the level (0 is coarsest) to supply
540: Output Parameter:
541: . ksp - the smoother
543: Note:
544: Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level.
545: You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc)
546: and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing.
548: Level: advanced
550: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()`
551: @*/
552: PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp)
553: {
554: PC_MG *mg = (PC_MG *)pc->data;
555: PC_MG_Levels **mglevels = mg->levels;
557: PetscFunctionBegin;
559: *ksp = mglevels[l]->smoothd;
560: PetscFunctionReturn(PETSC_SUCCESS);
561: }
563: /*@
564: PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
565: coarse grid correction (post-smoother).
567: Not Collective, ksp returned is parallel if pc is
569: Input Parameters:
570: + pc - the multigrid context
571: - l - the level (0 is coarsest) to supply
573: Output Parameter:
574: . ksp - the smoother
576: Level: advanced
578: Note:
579: Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also
581: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherDown()`
582: @*/
583: PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp)
584: {
585: PC_MG *mg = (PC_MG *)pc->data;
586: PC_MG_Levels **mglevels = mg->levels;
587: const char *prefix;
588: MPI_Comm comm;
590: PetscFunctionBegin;
592: /*
593: This is called only if user wants a different pre-smoother from post.
594: Thus we check if a different one has already been allocated,
595: if not we allocate it.
596: */
597: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid");
598: if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
599: KSPType ksptype;
600: PCType pctype;
601: PC ipc;
602: PetscReal rtol, abstol, dtol;
603: PetscInt maxits;
604: KSPNormType normtype;
605: PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm));
606: PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix));
607: PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits));
608: PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype));
609: PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype));
610: PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc));
611: PetscCall(PCGetType(ipc, &pctype));
613: PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
614: PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
615: PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
616: PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
617: PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
618: PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
619: PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
620: PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
621: PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
622: PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
623: PetscCall(PCSetType(ipc, pctype));
624: PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
625: }
626: if (ksp) *ksp = mglevels[l]->smoothu;
627: PetscFunctionReturn(PETSC_SUCCESS);
628: }
630: /*@
631: PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
632: coarse grid correction (pre-smoother).
634: Not Collective, ksp returned is parallel if pc is
636: Input Parameters:
637: + pc - the multigrid context
638: - l - the level (0 is coarsest) to supply
640: Output Parameter:
641: . ksp - the smoother
643: Level: advanced
645: Note:
646: Calling this will result in a different pre and post smoother so you may need to
647: set options on the post smoother also
649: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
650: @*/
651: PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
652: {
653: PC_MG *mg = (PC_MG *)pc->data;
654: PC_MG_Levels **mglevels = mg->levels;
656: PetscFunctionBegin;
658: /* make sure smoother up and down are different */
659: if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
660: *ksp = mglevels[l]->smoothd;
661: PetscFunctionReturn(PETSC_SUCCESS);
662: }
664: /*@
665: PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
667: Logically Collective
669: Input Parameters:
670: + pc - the multigrid context
671: . l - the level (0 is coarsest)
672: - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
674: Level: advanced
676: .seealso: [](ch_ksp), `PCMG`, `PCMGCycleType`, `PCMGSetCycleType()`
677: @*/
678: PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
679: {
680: PC_MG *mg = (PC_MG *)pc->data;
681: PC_MG_Levels **mglevels = mg->levels;
683: PetscFunctionBegin;
685: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
688: mglevels[l]->cycles = c;
689: PetscFunctionReturn(PETSC_SUCCESS);
690: }
692: /*@
693: PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
695: Logically Collective
697: Input Parameters:
698: + pc - the multigrid context
699: . l - the level (0 is coarsest) this is to be used for
700: - c - the Vec
702: Level: advanced
704: Note:
705: 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.
707: .seealso: [](ch_ksp), `PCMG`, `PCMGSetX()`, `PCMGSetR()`
708: @*/
709: PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
710: {
711: PC_MG *mg = (PC_MG *)pc->data;
712: PC_MG_Levels **mglevels = mg->levels;
714: PetscFunctionBegin;
716: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
717: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
718: PetscCall(PetscObjectReference((PetscObject)c));
719: PetscCall(VecDestroy(&mglevels[l]->b));
721: mglevels[l]->b = c;
722: PetscFunctionReturn(PETSC_SUCCESS);
723: }
725: /*@
726: PCMGSetX - Sets the vector to be used to store the solution on a particular level.
728: Logically Collective
730: Input Parameters:
731: + pc - the multigrid context
732: . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
733: - c - the Vec
735: Level: advanced
737: Note:
738: 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.
740: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
741: @*/
742: PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
743: {
744: PC_MG *mg = (PC_MG *)pc->data;
745: PC_MG_Levels **mglevels = mg->levels;
747: PetscFunctionBegin;
749: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
750: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
751: PetscCall(PetscObjectReference((PetscObject)c));
752: PetscCall(VecDestroy(&mglevels[l]->x));
754: mglevels[l]->x = c;
755: PetscFunctionReturn(PETSC_SUCCESS);
756: }
758: /*@
759: PCMGSetR - Sets the vector to be used to store the residual on a particular level.
761: Logically Collective
763: Input Parameters:
764: + pc - the multigrid context
765: . l - the level (0 is coarsest) this is to be used for
766: - c - the Vec
768: Level: advanced
770: Note:
771: 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.
773: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
774: @*/
775: PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
776: {
777: PC_MG *mg = (PC_MG *)pc->data;
778: PC_MG_Levels **mglevels = mg->levels;
780: PetscFunctionBegin;
782: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
783: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
784: PetscCall(PetscObjectReference((PetscObject)c));
785: PetscCall(VecDestroy(&mglevels[l]->r));
787: mglevels[l]->r = c;
788: PetscFunctionReturn(PETSC_SUCCESS);
789: }