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: /*@C
    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:   if (mat) PetscCall(PetscObjectReference((PetscObject)mat));
    155:   PetscCall(MatDestroy(&mglevels[l]->A));
    156:   mglevels[l]->A = mat;
    157:   PetscFunctionReturn(PETSC_SUCCESS);
    158: }

    160: /*@C
    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:   if (mat) 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: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`
    418: @*/
    419: PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
    420: {
    421:   PC_MG         *mg       = (PC_MG *)pc->data;
    422:   PC_MG_Levels **mglevels = mg->levels;

    424:   PetscFunctionBegin;
    426:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
    427:   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);
    428:   if (!mglevels[l]->rscale) {
    429:     Mat      R;
    430:     Vec      X, Y, coarse, fine;
    431:     PetscInt M, N;

    433:     PetscCall(PCMGGetRestriction(pc, l, &R));
    434:     PetscCall(MatCreateVecs(R, &X, &Y));
    435:     PetscCall(MatGetSize(R, &M, &N));
    436:     PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
    437:     if (M < N) {
    438:       fine   = X;
    439:       coarse = Y;
    440:     } else {
    441:       fine   = Y;
    442:       coarse = X;
    443:     }
    444:     PetscCall(VecSet(fine, 1.));
    445:     PetscCall(MatRestrict(R, fine, coarse));
    446:     PetscCall(VecDestroy(&fine));
    447:     PetscCall(VecReciprocal(coarse));
    448:     mglevels[l]->rscale = coarse;
    449:   }
    450:   *rscale = mglevels[l]->rscale;
    451:   PetscFunctionReturn(PETSC_SUCCESS);
    452: }

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

    458:   Logically Collective

    460:   Input Parameters:
    461: + pc  - the multigrid context
    462: . l   - the level (0 is coarsest) to supply [Do not supply 0]
    463: - mat - the injection matrix

    465:   Level: advanced

    467: .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
    468: @*/
    469: PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat)
    470: {
    471:   PC_MG         *mg       = (PC_MG *)pc->data;
    472:   PC_MG_Levels **mglevels = mg->levels;

    474:   PetscFunctionBegin;
    477:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
    478:   PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
    479:   PetscCall(PetscObjectReference((PetscObject)mat));
    480:   PetscCall(MatDestroy(&mglevels[l]->inject));

    482:   mglevels[l]->inject = mat;
    483:   PetscFunctionReturn(PETSC_SUCCESS);
    484: }

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

    490:   Logically Collective

    492:   Input Parameters:
    493: + pc - the multigrid context
    494: - l  - the level (0 is coarsest) to supply [Do not supply 0]

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

    499:   Level: advanced

    501: .seealso: [](ch_ksp), `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()`
    502: @*/
    503: PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat)
    504: {
    505:   PC_MG         *mg       = (PC_MG *)pc->data;
    506:   PC_MG_Levels **mglevels = mg->levels;

    508:   PetscFunctionBegin;
    510:   if (mat) PetscAssertPointer(mat, 3);
    511:   PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
    512:   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);
    513:   if (mat) *mat = mglevels[l]->inject;
    514:   PetscFunctionReturn(PETSC_SUCCESS);
    515: }

    517: /*@
    518:   PCMGGetSmoother - Gets the `KSP` context to be used as smoother for
    519:   both pre- and post-smoothing.  Call both `PCMGGetSmootherUp()` and
    520:   `PCMGGetSmootherDown()` to use different functions for pre- and
    521:   post-smoothing.

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

    525:   Input Parameters:
    526: + pc - the multigrid context
    527: - l  - the level (0 is coarsest) to supply

    529:   Output Parameter:
    530: . ksp - the smoother

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

    537:   Level: advanced

    539: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()`
    540: @*/
    541: PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp)
    542: {
    543:   PC_MG         *mg       = (PC_MG *)pc->data;
    544:   PC_MG_Levels **mglevels = mg->levels;

    546:   PetscFunctionBegin;
    548:   *ksp = mglevels[l]->smoothd;
    549:   PetscFunctionReturn(PETSC_SUCCESS);
    550: }

    552: /*@
    553:   PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
    554:   coarse grid correction (post-smoother).

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

    558:   Input Parameters:
    559: + pc - the multigrid context
    560: - l  - the level (0 is coarsest) to supply

    562:   Output Parameter:
    563: . ksp - the smoother

    565:   Level: advanced

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

    570: .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherDown()`
    571: @*/
    572: PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp)
    573: {
    574:   PC_MG         *mg       = (PC_MG *)pc->data;
    575:   PC_MG_Levels **mglevels = mg->levels;
    576:   const char    *prefix;
    577:   MPI_Comm       comm;

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

    602:     PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
    603:     PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
    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: [](ch_ksp), `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: [](ch_ksp), `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: [](ch_ksp), `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: [](ch_ksp), `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: [](ch_ksp), `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: }