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