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