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: }