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: .keywords: multigrid, set, interpolate, level
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;
255: PetscFunctionBegin;
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(PETSC_SUCCESS);
262: }
264: /*@
265: PCMGGetInterpolation - Gets the function to be used to calculate the
266: interpolation from l-1 to the lth level
268: Logically Collective
270: Input Parameters:
271: + pc - the multigrid context
272: - l - the level (0 is coarsest) to supply [Do not supply 0]
274: Output Parameter:
275: . mat - the interpolation matrix, can be NULL
277: Level: advanced
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;
286: PetscFunctionBegin;
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(PETSC_SUCCESS);
294: }
296: /*@
297: PCMGSetRestriction - Sets the function to be used to restrict dual vectors
298: from level l to l-1.
300: Logically Collective
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
307: Level: advanced
309: Notes:
310: Usually this is the same matrix used also to set the interpolation
311: for the same level.
313: One can pass in the interpolation matrix or its transpose; PETSc figures
314: out from the matrix size which one it is.
316: If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
317: is used.
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;
326: PetscFunctionBegin;
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));
334: mglevels[l]->restrct = mat;
335: PetscFunctionReturn(PETSC_SUCCESS);
336: }
338: /*@
339: PCMGGetRestriction - Gets the function to be used to restrict dual vectors
340: from level l to l-1.
342: Logically Collective
344: Input Parameters:
345: + pc - the multigrid context
346: - l - the level (0 is coarsest) to supply [Do not supply 0]
348: Output Parameter:
349: . mat - the restriction matrix
351: Level: advanced
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;
360: PetscFunctionBegin;
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(PETSC_SUCCESS);
368: }
370: /*@
371: PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
373: Logically Collective
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
380: Level: advanced
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.
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;
393: PetscFunctionBegin;
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));
400: mglevels[l]->rscale = rscale;
401: PetscFunctionReturn(PETSC_SUCCESS);
402: }
404: /*@
405: PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
407: Collective
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]
414: Level: advanced
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.
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;
427: PetscFunctionBegin;
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;
436: PetscCall(PCMGGetRestriction(pc, l, &R));
437: PetscCall(MatCreateVecs(R, &X, &Y));
438: PetscCall(MatGetSize(R, &M, &N));
439: PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
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 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: `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
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: `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;
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: 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: `PCMG`, `PCMGGetSmootherUp()`, `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(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
607: PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
608: PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
609: PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
610: PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
611: PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
612: PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
613: PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
614: PetscCall(PCSetType(ipc, pctype));
615: PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
616: }
617: if (ksp) *ksp = mglevels[l]->smoothu;
618: PetscFunctionReturn(PETSC_SUCCESS);
619: }
621: /*@
622: PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
623: coarse grid correction (pre-smoother).
625: Not Collective, ksp returned is parallel if pc is
627: Input Parameters:
628: + pc - the multigrid context
629: - l - the level (0 is coarsest) to supply
631: Output Parameter:
632: . ksp - the smoother
634: Level: advanced
636: Note:
637: Calling this will result in a different pre and post smoother so you may need to
638: set options on the post smoother also
640: .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
641: @*/
642: PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
643: {
644: PC_MG *mg = (PC_MG *)pc->data;
645: PC_MG_Levels **mglevels = mg->levels;
647: PetscFunctionBegin;
649: /* make sure smoother up and down are different */
650: if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
651: *ksp = mglevels[l]->smoothd;
652: PetscFunctionReturn(PETSC_SUCCESS);
653: }
655: /*@
656: PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
658: Logically Collective
660: Input Parameters:
661: + pc - the multigrid context
662: . l - the level (0 is coarsest)
663: - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
665: Level: advanced
667: .seealso: `PCMG`, PCMGCycleType`, `PCMGSetCycleType()`
668: @*/
669: PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
670: {
671: PC_MG *mg = (PC_MG *)pc->data;
672: PC_MG_Levels **mglevels = mg->levels;
674: PetscFunctionBegin;
676: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
679: mglevels[l]->cycles = c;
680: PetscFunctionReturn(PETSC_SUCCESS);
681: }
683: /*@
684: PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
686: Logically Collective
688: Input Parameters:
689: + pc - the multigrid context
690: . l - the level (0 is coarsest) this is to be used for
691: - c - the Vec
693: Level: advanced
695: Note:
696: 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.
698: .seealso: `PCMG`, `PCMGSetX()`, `PCMGSetR()`
699: @*/
700: PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
701: {
702: PC_MG *mg = (PC_MG *)pc->data;
703: PC_MG_Levels **mglevels = mg->levels;
705: PetscFunctionBegin;
707: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
708: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
709: PetscCall(PetscObjectReference((PetscObject)c));
710: PetscCall(VecDestroy(&mglevels[l]->b));
712: mglevels[l]->b = c;
713: PetscFunctionReturn(PETSC_SUCCESS);
714: }
716: /*@
717: PCMGSetX - Sets the vector to be used to store the solution on a particular level.
719: Logically Collective
721: Input Parameters:
722: + pc - the multigrid context
723: . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
724: - c - the Vec
726: Level: advanced
728: Note:
729: 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.
731: .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
732: @*/
733: PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
734: {
735: PC_MG *mg = (PC_MG *)pc->data;
736: PC_MG_Levels **mglevels = mg->levels;
738: PetscFunctionBegin;
740: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
741: PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
742: PetscCall(PetscObjectReference((PetscObject)c));
743: PetscCall(VecDestroy(&mglevels[l]->x));
745: mglevels[l]->x = c;
746: PetscFunctionReturn(PETSC_SUCCESS);
747: }
749: /*@
750: PCMGSetR - Sets the vector to be used to store the residual on a particular level.
752: Logically Collective
754: Input Parameters:
755: + pc - the multigrid context
756: . l - the level (0 is coarsest) this is to be used for
757: - c - the Vec
759: Level: advanced
761: Note:
762: 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.
764: .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
765: @*/
766: PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
767: {
768: PC_MG *mg = (PC_MG *)pc->data;
769: PC_MG_Levels **mglevels = mg->levels;
771: PetscFunctionBegin;
773: PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
774: PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
775: PetscCall(PetscObjectReference((PetscObject)c));
776: PetscCall(VecDestroy(&mglevels[l]->r));
778: mglevels[l]->r = c;
779: PetscFunctionReturn(PETSC_SUCCESS);
780: }