Actual source code: mgfunc.c
2: #include <petsc/private/pcmgimpl.h>
4: /*@C
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: `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: /*@C
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: `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: /*@C
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: .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: }
78: /*@C
79: PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
81: Collective
83: Input Parameters:
84: + mat - the matrix
85: . b - the right-hand-side
86: - x - the approximate solution
88: Output Parameter:
89: . r - location to store the residual
91: Level: developer
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.
105: Not Collective
107: Input Parameter:
108: . pc - the multigrid context
110: Output Parameter:
111: . ksp - the coarse grid solver context
113: Level: advanced
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;
122: PetscFunctionBegin;
124: *ksp = mglevels[0]->smoothd;
125: PetscFunctionReturn(PETSC_SUCCESS);
126: }
128: /*@C
129: PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.
131: Logically Collective
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
140: Level: advanced
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;
149: PetscFunctionBegin;
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: }
161: /*@C
162: PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system
163: on the lth level.
165: Logically Collective
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
174: Level: advanced
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;
183: PetscFunctionBegin;
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: }
195: /*@
196: PCMGSetInterpolation - Sets the function to be used to calculate the
197: interpolation from l-1 to the lth level
199: Logically Collective
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]
206: Level: advanced
208: Notes:
209: Usually this is the same matrix used also to set the restriction
210: for the same level.
212: One can pass in the interpolation matrix or its transpose; PETSc figures
213: out from the matrix size which one it is.
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;
222: PetscFunctionBegin;
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));
229: mglevels[l]->interpolate = mat;
230: PetscFunctionReturn(PETSC_SUCCESS);
231: }
233: /*@
234: PCMGSetOperators - Sets operator and preconditioning matrix for lth level
236: Logically Collective
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
244: Level: advanced
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;
253: PetscFunctionBegin;
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: }
262: /*@
263: PCMGGetInterpolation - Gets the function to be used to calculate the
264: interpolation from l-1 to the lth level
266: Logically Collective
268: Input Parameters:
269: + pc - the multigrid context
270: - l - the level (0 is coarsest) to supply [Do not supply 0]
272: Output Parameter:
273: . mat - the interpolation matrix, can be `NULL`
275: Level: advanced
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;
284: PetscFunctionBegin;
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: }
294: /*@
295: PCMGSetRestriction - Sets the function to be used to restrict dual vectors
296: from level l to l-1.
298: Logically Collective
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
305: Level: advanced
307: Notes:
308: Usually this is the same matrix used also to set the interpolation
309: for the same level.
311: One can pass in the interpolation matrix or its transpose; PETSc figures
312: out from the matrix size which one it is.
314: If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
315: is used.
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;
324: PetscFunctionBegin;
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));
332: mglevels[l]->restrct = mat;
333: PetscFunctionReturn(PETSC_SUCCESS);
334: }
336: /*@
337: PCMGGetRestriction - Gets the function to be used to restrict dual vectors
338: from level l to l-1.
340: Logically Collective
342: Input Parameters:
343: + pc - the multigrid context
344: - l - the level (0 is coarsest) to supply [Do not supply 0]
346: Output Parameter:
347: . mat - the restriction matrix
349: Level: advanced
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;
358: PetscFunctionBegin;
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: }
368: /*@
369: PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
371: Logically Collective
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
378: Level: advanced
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.
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;
391: PetscFunctionBegin;
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));
398: mglevels[l]->rscale = rscale;
399: PetscFunctionReturn(PETSC_SUCCESS);
400: }
402: /*@
403: PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
405: Collective
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]
412: Level: advanced
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.
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;
425: PetscFunctionBegin;
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;
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: }
455: /*@
456: PCMGSetInjection - Sets the function to be used to inject primal vectors
457: from level l to l-1.
459: Logically Collective
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
466: Level: advanced
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;
475: PetscFunctionBegin;
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));
483: mglevels[l]->inject = mat;
484: PetscFunctionReturn(PETSC_SUCCESS);
485: }
487: /*@
488: PCMGGetInjection - Gets the function to be used to inject primal vectors
489: from level l to l-1.
491: Logically Collective
493: Input Parameters:
494: + pc - the multigrid context
495: - l - the level (0 is coarsest) to supply [Do not supply 0]
497: Output Parameter:
498: . mat - the restriction matrix (may be NULL if no injection is available).
500: Level: advanced
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;
509: PetscFunctionBegin;
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: }
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.
524: Not Collective, ksp returned is parallel if pc is
526: Input Parameters:
527: + pc - the multigrid context
528: - l - the level (0 is coarsest) to supply
530: Output Parameter:
531: . ksp - the smoother
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.
538: Level: advanced
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;
547: PetscFunctionBegin;
549: *ksp = mglevels[l]->smoothd;
550: PetscFunctionReturn(PETSC_SUCCESS);
551: }
553: /*@
554: PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
555: coarse grid correction (post-smoother).
557: Not Collective, ksp returned is parallel if pc is
559: Input Parameters:
560: + pc - the multigrid context
561: - l - the level (0 is coarsest) to supply
563: Output Parameter:
564: . ksp - the smoother
566: Level: advanced
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
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;
580: PetscFunctionBegin;
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));
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(PETSC_SUCCESS);
617: }
619: /*@
620: PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
621: coarse grid correction (pre-smoother).
623: Not Collective, ksp returned is parallel if pc is
625: Input Parameters:
626: + pc - the multigrid context
627: - l - the level (0 is coarsest) to supply
629: Output Parameter:
630: . ksp - the smoother
632: Level: advanced
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
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;
645: PetscFunctionBegin;
647: /* make sure smoother up and down are different */
648: if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
649: *ksp = mglevels[l]->smoothd;
650: PetscFunctionReturn(PETSC_SUCCESS);
651: }
653: /*@
654: PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
656: Logically Collective
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`
663: Level: advanced
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;
672: PetscFunctionBegin;
674: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
677: mglevels[l]->cycles = c;
678: PetscFunctionReturn(PETSC_SUCCESS);
679: }
681: /*@
682: PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
684: Logically Collective
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
691: Level: advanced
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.
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;
703: PetscFunctionBegin;
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));
710: mglevels[l]->b = c;
711: PetscFunctionReturn(PETSC_SUCCESS);
712: }
714: /*@
715: PCMGSetX - Sets the vector to be used to store the solution on a particular level.
717: Logically Collective
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
724: Level: advanced
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.
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;
736: PetscFunctionBegin;
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));
743: mglevels[l]->x = c;
744: PetscFunctionReturn(PETSC_SUCCESS);
745: }
747: /*@
748: PCMGSetR - Sets the vector to be used to store the residual on a particular level.
750: Logically Collective
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
757: Level: advanced
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.
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;
769: PetscFunctionBegin;
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));
776: mglevels[l]->r = c;
777: PetscFunctionReturn(PETSC_SUCCESS);
778: }