Actual source code: mgfunc.c

  1: #include <petsc/private/pcmgimpl.h>
  2: #include <petsc/private/matimpl.h>

  4: /*@
  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: [](ch_ksp), `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: /*@
 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: [](ch_ksp), `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: /*@
 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:   Note:
 69:   When `r` is dense, the `MatProduct` computing it stays attached to `r`, so that later calls with the same `mat` and nonzero pattern only run
 70:   its numeric phase; it keeps references to `mat` and `x` until `MatProductClear()` is called on `r` or `r` is destroyed.

 72: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidual()`, `PCMGResidualDefault()`
 73: @*/
 74: PetscErrorCode PCMGMatResidualDefault(Mat mat, Mat b, Mat x, Mat r)
 75: {
 76:   PetscFunctionBegin;
 77:   PetscCall(MatProductComputeWithMat_Private(mat, x, MATPRODUCT_AB, r));
 78:   PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
 79:   PetscFunctionReturn(PETSC_SUCCESS);
 80: }

 82: /*@
 83:   PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system

 85:   Collective

 87:   Input Parameters:
 88: + mat - the matrix
 89: . b   - the right-hand side
 90: - x   - the approximate solution

 92:   Output Parameter:
 93: . r - location to store the residual

 95:   Level: developer

 97:   Note:
 98:   When `r` is dense, the `MatProduct` computing it stays attached to `r`, so that later calls with the same `mat` and nonzero pattern only run
 99:   its numeric phase; it keeps references to `mat` and `x` until `MatProductClear()` is called on `r` or `r` is destroyed.

101: .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidualTranspose()`
102: @*/
103: PetscErrorCode PCMGMatResidualTransposeDefault(Mat mat, Mat b, Mat x, Mat r)
104: {
105:   PetscFunctionBegin;
106:   PetscCall(MatProductComputeWithMat_Private(mat, x, MATPRODUCT_AtB, r));
107:   PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
108:   PetscFunctionReturn(PETSC_SUCCESS);
109: }
110: /*@
111:   PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.

113:   Not Collective

115:   Input Parameter:
116: . pc - the multigrid context

118:   Output Parameter:
119: . ksp - the coarse grid solver context

121:   Level: advanced

123: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetSmoother()`
124: @*/
125: PetscErrorCode PCMGGetCoarseSolve(PC pc, KSP *ksp)
126: {
127:   PC_MG         *mg       = (PC_MG *)pc->data;
128:   PC_MG_Levels **mglevels = mg->levels;

130:   PetscFunctionBegin;
132:   *ksp = mglevels[0]->smoothd;
133:   PetscFunctionReturn(PETSC_SUCCESS);
134: }

136: /*@
137:   PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.

139:   Logically Collective

141:   Input Parameters:
142: + pc       - the multigrid context
143: . l        - the level (0 is coarsest) to supply
144: . residual - function used to form residual, if none is provided the previously provide one is used, if no
145:               previous one were provided then a default is used
146: - mat      - matrix associated with residual

148:   Level: advanced

150: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualDefault()`
151: @*/
152: PetscErrorCode PCMGSetResidual(PC pc, PetscInt l, PetscErrorCode (*residual)(Mat, Vec, Vec, Vec), Mat mat)
153: {
154:   PC_MG         *mg       = (PC_MG *)pc->data;
155:   PC_MG_Levels **mglevels = mg->levels;

157:   PetscFunctionBegin;
159:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
160:   if (residual) mglevels[l]->residual = residual;
161:   if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
162:   mglevels[l]->matresidual = PCMGMatResidualDefault;
163:   PetscCall(PetscObjectReference((PetscObject)mat));
164:   PetscCall(MatDestroy(&mglevels[l]->A));
165:   mglevels[l]->A = mat;
166:   PetscFunctionReturn(PETSC_SUCCESS);
167: }

169: /*@
170:   PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system
171:   on the lth level.

173:   Logically Collective

175:   Input Parameters:
176: + pc        - the multigrid context
177: . l         - the level (0 is coarsest) to supply
178: . residualt - function used to form transpose of residual, if none is provided the previously provide one is used, if no
179:                previous one were provided then a default is used
180: - mat       - matrix associated with residual

182:   Level: advanced

184: .seealso: [](ch_ksp), `PCMG`, `PCMGResidualTransposeDefault()`
185: @*/
186: PetscErrorCode PCMGSetResidualTranspose(PC pc, PetscInt l, PetscErrorCode (*residualt)(Mat, Vec, Vec, Vec), Mat mat)
187: {
188:   PC_MG         *mg       = (PC_MG *)pc->data;
189:   PC_MG_Levels **mglevels = mg->levels;

191:   PetscFunctionBegin;
193:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
194:   if (residualt) mglevels[l]->residualtranspose = residualt;
195:   if (!mglevels[l]->residualtranspose) mglevels[l]->residualtranspose = PCMGResidualTransposeDefault;
196:   mglevels[l]->matresidualtranspose = PCMGMatResidualTransposeDefault;
197:   PetscCall(PetscObjectReference((PetscObject)mat));
198:   PetscCall(MatDestroy(&mglevels[l]->A));
199:   mglevels[l]->A = mat;
200:   PetscFunctionReturn(PETSC_SUCCESS);
201: }

203: /*@
204:   PCMGSetInterpolation - Sets the function to be used to calculate the
205:   interpolation from l-1 to the lth level

207:   Logically Collective

209:   Input Parameters:
210: + pc  - the multigrid context
211: . mat - the interpolation operator
212: - l   - the level (0 is coarsest) to supply [do not supply 0]

214:   Level: advanced

216:   Notes:
217:   Usually this is the same matrix used also to set the restriction
218:   for the same level.

220:   One can pass in the interpolation matrix or its transpose; PETSc figures
221:   out from the matrix size which one it is.

223: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
224: @*/
225: PetscErrorCode PCMGSetInterpolation(PC pc, PetscInt l, Mat mat)
226: {
227:   PC_MG         *mg       = (PC_MG *)pc->data;
228:   PC_MG_Levels **mglevels = mg->levels;

230:   PetscFunctionBegin;
232:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
233:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set interpolation routine for coarsest level");
234:   if (mat != mglevels[l]->interpolate) PetscCall(PCMGResetBlocks_Private(pc)); /* the kept block products were set up with the old matrix */
235:   PetscCall(PetscObjectReference((PetscObject)mat));
236:   PetscCall(MatDestroy(&mglevels[l]->interpolate));

238:   mglevels[l]->interpolate = mat;
239:   PetscFunctionReturn(PETSC_SUCCESS);
240: }

242: /*@
243:   PCMGSetOperators - Sets operator and matrix from which to construct a preconditioner for lth level

245:   Logically Collective

247:   Input Parameters:
248: + pc   - the multigrid context
249: . Amat - the operator
250: . Pmat - the preconditioning operator
251: - l    - the level (0 is the coarsest) to supply

253:   Level: advanced

255: .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()`
256: @*/
257: PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat)
258: {
259:   PC_MG         *mg       = (PC_MG *)pc->data;
260:   PC_MG_Levels **mglevels = mg->levels;

262:   PetscFunctionBegin;
266:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
267:   PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat));
268:   PetscFunctionReturn(PETSC_SUCCESS);
269: }

271: /*@
272:   PCMGGetInterpolation - Gets the function to be used to calculate the
273:   interpolation from l-1 to the lth level

275:   Logically Collective

277:   Input Parameters:
278: + pc - the multigrid context
279: - l  - the level (0 is coarsest) to supply [Do not supply 0]

281:   Output Parameter:
282: . mat - the interpolation matrix, can be `NULL`

284:   Level: advanced

286: .seealso: [](ch_ksp), `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()`
287: @*/
288: PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat)
289: {
290:   PC_MG         *mg       = (PC_MG *)pc->data;
291:   PC_MG_Levels **mglevels = mg->levels;

293:   PetscFunctionBegin;
295:   if (mat) PetscAssertPointer(mat, 3);
296:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
297:   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);
298:   if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct));
299:   if (mat) *mat = mglevels[l]->interpolate;
300:   PetscFunctionReturn(PETSC_SUCCESS);
301: }

303: /*@
304:   PCMGSetRestriction - Sets the function to be used to restrict dual vectors
305:   from level l to l-1.

307:   Logically Collective

309:   Input Parameters:
310: + pc  - the multigrid context
311: . l   - the level (0 is coarsest) to supply [Do not supply 0]
312: - mat - the restriction matrix

314:   Level: advanced

316:   Notes:
317:   Usually this is the same matrix used also to set the interpolation
318:   for the same level.

320:   One can pass in the interpolation matrix or its transpose; PETSc figures
321:   out from the matrix size which one it is.

323:   If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
324:   is used.

326: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`
327: @*/
328: PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat)
329: {
330:   PC_MG         *mg       = (PC_MG *)pc->data;
331:   PC_MG_Levels **mglevels = mg->levels;

333:   PetscFunctionBegin;
336:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
337:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
338:   if (mat != mglevels[l]->restrct) PetscCall(PCMGResetBlocks_Private(pc)); /* the kept block products were set up with the old matrix */
339:   PetscCall(PetscObjectReference((PetscObject)mat));
340:   PetscCall(MatDestroy(&mglevels[l]->restrct));

342:   mglevels[l]->restrct = mat;
343:   PetscFunctionReturn(PETSC_SUCCESS);
344: }

346: /*@
347:   PCMGGetRestriction - Gets the function to be used to restrict dual (i.e. residual) vectors
348:   from level l to l-1.

350:   Logically Collective

352:   Input Parameters:
353: + pc - the multigrid context
354: - l  - the level (0 is coarsest) to supply [Do not supply 0]

356:   Output Parameter:
357: . mat - the restriction matrix

359:   Level: advanced

361: .seealso: [](ch_ksp), `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()`
362: @*/
363: PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat)
364: {
365:   PC_MG         *mg       = (PC_MG *)pc->data;
366:   PC_MG_Levels **mglevels = mg->levels;

368:   PetscFunctionBegin;
370:   if (mat) PetscAssertPointer(mat, 3);
371:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
372:   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);
373:   if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate));
374:   if (mat) *mat = mglevels[l]->restrct;
375:   PetscFunctionReturn(PETSC_SUCCESS);
376: }

378: /*@
379:   PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.

381:   Logically Collective

383:   Input Parameters:
384: + pc     - the multigrid context
385: . l      - the level (0 is coarsest) to supply [Do not supply 0]
386: - rscale - the scaling

388:   Level: advanced

390:   Note:
391:   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.
392:   It is preferable to use `PCMGSetInjection()` to control moving primal vectors.

394: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()`
395: @*/
396: PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale)
397: {
398:   PC_MG         *mg       = (PC_MG *)pc->data;
399:   PC_MG_Levels **mglevels = mg->levels;

401:   PetscFunctionBegin;
403:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
404:   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);
405:   PetscCall(PetscObjectReference((PetscObject)rscale));
406:   PetscCall(VecDestroy(&mglevels[l]->rscale));

408:   mglevels[l]->rscale = rscale;
409:   PetscFunctionReturn(PETSC_SUCCESS);
410: }

412: /*@
413:   PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.

415:   Collective

417:   Input Parameters:
418: + pc     - the multigrid context
419: . rscale - the scaling
420: - l      - the level (0 is coarsest) to supply [Do not supply 0]

422:   Level: advanced

424:   Note:
425:   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.
426:   It is preferable to use `PCMGGetInjection()` to control moving primal vectors.

428: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`
429: @*/
430: PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
431: {
432:   PC_MG         *mg       = (PC_MG *)pc->data;
433:   PC_MG_Levels **mglevels = mg->levels;

435:   PetscFunctionBegin;
437:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
438:   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);
439:   if (!mglevels[l]->rscale) {
440:     Mat      R;
441:     Vec      X, Y, coarse, fine;
442:     PetscInt M, N;

444:     PetscCall(PCMGGetRestriction(pc, l, &R));
445:     PetscCall(MatCreateVecs(R, &X, &Y));
446:     PetscCall(MatGetSize(R, &M, &N));
447:     PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
448:     if (M < N) {
449:       fine   = X;
450:       coarse = Y;
451:     } else {
452:       fine   = Y;
453:       coarse = X;
454:     }
455:     PetscCall(VecSet(fine, 1.));
456:     PetscCall(MatRestrict(R, fine, coarse));
457:     PetscCall(VecDestroy(&fine));
458:     PetscCall(VecReciprocal(coarse));
459:     mglevels[l]->rscale = coarse;
460:   }
461:   *rscale = mglevels[l]->rscale;
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

465: /*@
466:   PCMGSetInjection - Sets the function to be used to inject primal (i.e. solution) vectors
467:   from level l to l-1.

469:   Logically Collective

471:   Input Parameters:
472: + pc  - the multigrid context
473: . l   - the level (0 is coarsest) to supply [Do not supply 0]
474: - mat - the injection matrix

476:   Level: advanced

478: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
479: @*/
480: PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat)
481: {
482:   PC_MG         *mg       = (PC_MG *)pc->data;
483:   PC_MG_Levels **mglevels = mg->levels;

485:   PetscFunctionBegin;
488:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
489:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
490:   PetscCall(PetscObjectReference((PetscObject)mat));
491:   PetscCall(MatDestroy(&mglevels[l]->inject));

493:   mglevels[l]->inject = mat;
494:   PetscFunctionReturn(PETSC_SUCCESS);
495: }

497: /*@
498:   PCMGGetInjection - Gets the function to be used to inject primal vectors (i.e. solutions)
499:   from level l to l-1.

501:   Logically Collective

503:   Input Parameters:
504: + pc - the multigrid context
505: - l  - the level (0 is coarsest) to supply [Do not supply 0]

507:   Output Parameter:
508: . mat - the restriction matrix (may be `NULL` if no injection is available).

510:   Level: advanced

512: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()`
513: @*/
514: PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat)
515: {
516:   PC_MG         *mg       = (PC_MG *)pc->data;
517:   PC_MG_Levels **mglevels = mg->levels;

519:   PetscFunctionBegin;
521:   if (mat) PetscAssertPointer(mat, 3);
522:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
523:   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);
524:   if (mat) *mat = mglevels[l]->inject;
525:   PetscFunctionReturn(PETSC_SUCCESS);
526: }

528: /*@
529:   PCMGGetSmoother - Gets the `KSP` context to be used as smoother for
530:   both pre- and post-smoothing.  Call both `PCMGGetSmootherUp()` and
531:   `PCMGGetSmootherDown()` to use different functions for pre- and
532:   post-smoothing.

534:   Not Collective, ksp returned is parallel if pc is

536:   Input Parameters:
537: + pc - the multigrid context
538: - l  - the level (0 is coarsest) to supply

540:   Output Parameter:
541: . ksp - the smoother

543:   Note:
544:   Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level.
545:   You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc)
546:   and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing.

548:   Level: advanced

550: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()`
551: @*/
552: PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp)
553: {
554:   PC_MG         *mg       = (PC_MG *)pc->data;
555:   PC_MG_Levels **mglevels = mg->levels;

557:   PetscFunctionBegin;
559:   *ksp = mglevels[l]->smoothd;
560:   PetscFunctionReturn(PETSC_SUCCESS);
561: }

563: /*@
564:   PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
565:   coarse grid correction (post-smoother).

567:   Not Collective, ksp returned is parallel if pc is

569:   Input Parameters:
570: + pc - the multigrid context
571: - l  - the level (0 is coarsest) to supply

573:   Output Parameter:
574: . ksp - the smoother

576:   Level: advanced

578:   Note:
579:   Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also

581: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherDown()`
582: @*/
583: PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp)
584: {
585:   PC_MG         *mg       = (PC_MG *)pc->data;
586:   PC_MG_Levels **mglevels = mg->levels;
587:   const char    *prefix;
588:   MPI_Comm       comm;

590:   PetscFunctionBegin;
592:   /*
593:      This is called only if user wants a different pre-smoother from post.
594:      Thus we check if a different one has already been allocated,
595:      if not we allocate it.
596:   */
597:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid");
598:   if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
599:     KSPType     ksptype;
600:     PCType      pctype;
601:     PC          ipc;
602:     PetscReal   rtol, abstol, dtol;
603:     PetscInt    maxits;
604:     KSPNormType normtype;
605:     PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm));
606:     PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix));
607:     PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits));
608:     PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype));
609:     PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype));
610:     PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc));
611:     PetscCall(PCGetType(ipc, &pctype));

613:     PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
614:     PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
615:     PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
616:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
617:     PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
618:     PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
619:     PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
620:     PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
621:     PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
622:     PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
623:     PetscCall(PCSetType(ipc, pctype));
624:     PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
625:   }
626:   if (ksp) *ksp = mglevels[l]->smoothu;
627:   PetscFunctionReturn(PETSC_SUCCESS);
628: }

630: /*@
631:   PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
632:   coarse grid correction (pre-smoother).

634:   Not Collective, ksp returned is parallel if pc is

636:   Input Parameters:
637: + pc - the multigrid context
638: - l  - the level (0 is coarsest) to supply

640:   Output Parameter:
641: . ksp - the smoother

643:   Level: advanced

645:   Note:
646:   Calling this will result in a different pre and post smoother so you may need to
647:   set options on the post smoother also

649: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
650: @*/
651: PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
652: {
653:   PC_MG         *mg       = (PC_MG *)pc->data;
654:   PC_MG_Levels **mglevels = mg->levels;

656:   PetscFunctionBegin;
658:   /* make sure smoother up and down are different */
659:   if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
660:   *ksp = mglevels[l]->smoothd;
661:   PetscFunctionReturn(PETSC_SUCCESS);
662: }

664: /*@
665:   PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.

667:   Logically Collective

669:   Input Parameters:
670: + pc - the multigrid context
671: . l  - the level (0 is coarsest)
672: - c  - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`

674:   Level: advanced

676: .seealso: [](ch_ksp), `PCMG`, `PCMGCycleType`, `PCMGSetCycleType()`
677: @*/
678: PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
679: {
680:   PC_MG         *mg       = (PC_MG *)pc->data;
681:   PC_MG_Levels **mglevels = mg->levels;

683:   PetscFunctionBegin;
685:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
688:   mglevels[l]->cycles = c;
689:   PetscFunctionReturn(PETSC_SUCCESS);
690: }

692: /*@
693:   PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.

695:   Logically Collective

697:   Input Parameters:
698: + pc - the multigrid context
699: . l  - the level (0 is coarsest) this is to be used for
700: - c  - the Vec

702:   Level: advanced

704:   Note:
705:   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.

707: .seealso: [](ch_ksp), `PCMG`, `PCMGSetX()`, `PCMGSetR()`
708: @*/
709: PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
710: {
711:   PC_MG         *mg       = (PC_MG *)pc->data;
712:   PC_MG_Levels **mglevels = mg->levels;

714:   PetscFunctionBegin;
716:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
717:   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
718:   PetscCall(PetscObjectReference((PetscObject)c));
719:   PetscCall(VecDestroy(&mglevels[l]->b));

721:   mglevels[l]->b = c;
722:   PetscFunctionReturn(PETSC_SUCCESS);
723: }

725: /*@
726:   PCMGSetX - Sets the vector to be used to store the solution on a particular level.

728:   Logically Collective

730:   Input Parameters:
731: + pc - the multigrid context
732: . l  - the level (0 is coarsest) this is to be used for (do not supply the finest level)
733: - c  - the Vec

735:   Level: advanced

737:   Note:
738:   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.

740: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
741: @*/
742: PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
743: {
744:   PC_MG         *mg       = (PC_MG *)pc->data;
745:   PC_MG_Levels **mglevels = mg->levels;

747:   PetscFunctionBegin;
749:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
750:   PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
751:   PetscCall(PetscObjectReference((PetscObject)c));
752:   PetscCall(VecDestroy(&mglevels[l]->x));

754:   mglevels[l]->x = c;
755:   PetscFunctionReturn(PETSC_SUCCESS);
756: }

758: /*@
759:   PCMGSetR - Sets the vector to be used to store the residual on a particular level.

761:   Logically Collective

763:   Input Parameters:
764: + pc - the multigrid context
765: . l  - the level (0 is coarsest) this is to be used for
766: - c  - the Vec

768:   Level: advanced

770:   Note:
771:   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.

773: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
774: @*/
775: PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
776: {
777:   PC_MG         *mg       = (PC_MG *)pc->data;
778:   PC_MG_Levels **mglevels = mg->levels;

780:   PetscFunctionBegin;
782:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
783:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
784:   PetscCall(PetscObjectReference((PetscObject)c));
785:   PetscCall(VecDestroy(&mglevels[l]->r));

787:   mglevels[l]->r = c;
788:   PetscFunctionReturn(PETSC_SUCCESS);
789: }