Date: 2015-10-02T22:18:01+00:00

Actual source code: mgfunc.c
petsc-3.6.2 2015-10-02
Report Typos and Errors

      2: #include <petsc/private/pcmgimpl.h>       /*I "petscksp.h" I*/

      4: /* ---------------------------------------------------------------------------*/
      7: /*@C
      8:    PCMGResidualDefault - Default routine to calculate the residual.

     10:    Collective on Mat and Vec

     12:    Input Parameters:
     13: +  mat - the matrix
     14: .  b   - the right-hand-side
     15: -  x   - the approximate solution

     17:    Output Parameter:
     18: .  r - location to store the residual

     20:    Level: developer

     22: .keywords: MG, default, multigrid, residual

     24: .seealso: PCMGSetResidual()
     25: @*/
     26: PetscErrorCode  PCMGResidualDefault(Mat mat,Vec b,Vec x,Vec r)
     27: {

     31:   MatResidual(mat,b,x,r);
     32:   return(0);
     33: }

     37: /*@
     38:    PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.

     40:    Not Collective

     42:    Input Parameter:
     43: .  pc - the multigrid context

     45:    Output Parameter:
     46: .  ksp - the coarse grid solver context

     48:    Level: advanced

     50: .keywords: MG, multigrid, get, coarse grid
     51: @*/
     52: PetscErrorCode  PCMGGetCoarseSolve(PC pc,KSP *ksp)
     53: {
     54:   PC_MG        *mg        = (PC_MG*)pc->data;
     55:   PC_MG_Levels **mglevels = mg->levels;

     59:   *ksp =  mglevels[0]->smoothd;
     60:   return(0);
     61: }

     65: /*@C
     66:    PCMGSetResidual - Sets the function to be used to calculate the residual
     67:    on the lth level.

     69:    Logically Collective on PC and Mat

     71:    Input Parameters:
     72: +  pc       - the multigrid context
     73: .  l        - the level (0 is coarsest) to supply
     74: .  residual - function used to form residual, if none is provided the previously provide one is used, if no
     75:               previous one were provided then a default is used
     76: -  mat      - matrix associated with residual

     78:    Level: advanced

     80: .keywords:  MG, set, multigrid, residual, level

     82: .seealso: PCMGResidualDefault()
     83: @*/
     84: PetscErrorCode  PCMGSetResidual(PC pc,PetscInt l,PetscErrorCode (*residual)(Mat,Vec,Vec,Vec),Mat mat)
     85: {
     86:   PC_MG          *mg        = (PC_MG*)pc->data;
     87:   PC_MG_Levels   **mglevels = mg->levels;

     92:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
     93:   if (residual) mglevels[l]->residual = residual;
     94:   if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
     95:   if (mat) {PetscObjectReference((PetscObject)mat);}
     96:   MatDestroy(&mglevels[l]->A);
     97:   mglevels[l]->A = mat;
     98:   return(0);
     99: }

    103: /*@
    104:    PCMGSetInterpolation - Sets the function to be used to calculate the
    105:    interpolation from l-1 to the lth level

    107:    Logically Collective on PC and Mat

    109:    Input Parameters:
    110: +  pc  - the multigrid context
    111: .  mat - the interpolation operator
    112: -  l   - the level (0 is coarsest) to supply [do not supply 0]

    114:    Level: advanced

    116:    Notes:
    117:           Usually this is the same matrix used also to set the restriction
    118:     for the same level.

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

    123: .keywords:  multigrid, set, interpolate, level

    125: .seealso: PCMGSetRestriction()
    126: @*/
    127: PetscErrorCode  PCMGSetInterpolation(PC pc,PetscInt l,Mat mat)
    128: {
    129:   PC_MG          *mg        = (PC_MG*)pc->data;
    130:   PC_MG_Levels   **mglevels = mg->levels;

    135:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    136:   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set interpolation routine for coarsest level");
    137:   PetscObjectReference((PetscObject)mat);
    138:   MatDestroy(&mglevels[l]->interpolate);

    140:   mglevels[l]->interpolate = mat;
    141:   return(0);
    142: }

    146: /*@
    147:    PCMGGetInterpolation - Gets the function to be used to calculate the
    148:    interpolation from l-1 to the lth level

    150:    Logically Collective on PC

    152:    Input Parameters:
    153: +  pc - the multigrid context
    154: -  l - the level (0 is coarsest) to supply [Do not supply 0]

    156:    Output Parameter:
    157: .  mat - the interpolation matrix

    159:    Level: advanced

    161: .keywords: MG, get, multigrid, interpolation, level

    163: .seealso: PCMGGetRestriction(), PCMGSetInterpolation(), PCMGGetRScale()
    164: @*/
    165: PetscErrorCode  PCMGGetInterpolation(PC pc,PetscInt l,Mat *mat)
    166: {
    167:   PC_MG          *mg        = (PC_MG*)pc->data;
    168:   PC_MG_Levels   **mglevels = mg->levels;

    174:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    175:   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
    176:   if (!mglevels[l]->interpolate) {
    177:     if (!mglevels[l]->restrct) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetInterpolation() or PCMGSetInterpolation()");
    178:     PCMGSetInterpolation(pc,l,mglevels[l]->restrct);
    179:   }
    180:   *mat = mglevels[l]->interpolate;
    181:   return(0);
    182: }

    186: /*@
    187:    PCMGSetRestriction - Sets the function to be used to restrict vector
    188:    from level l to l-1.

    190:    Logically Collective on PC and Mat

    192:    Input Parameters:
    193: +  pc - the multigrid context
    194: .  l - the level (0 is coarsest) to supply [Do not supply 0]
    195: -  mat - the restriction matrix

    197:    Level: advanced

    199:    Notes:
    200:           Usually this is the same matrix used also to set the interpolation
    201:     for the same level.

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

    206:          If you do not set this, the transpose of the Mat set with PCMGSetInterpolation()
    207:     is used.

    209: .keywords: MG, set, multigrid, restriction, level

    211: .seealso: PCMGSetInterpolation()
    212: @*/
    213: PetscErrorCode  PCMGSetRestriction(PC pc,PetscInt l,Mat mat)
    214: {
    216:   PC_MG          *mg        = (PC_MG*)pc->data;
    217:   PC_MG_Levels   **mglevels = mg->levels;

    222:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    223:   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Do not set restriction routine for coarsest level");
    224:   PetscObjectReference((PetscObject)mat);
    225:   MatDestroy(&mglevels[l]->restrct);

    227:   mglevels[l]->restrct = mat;
    228:   return(0);
    229: }

    233: /*@
    234:    PCMGGetRestriction - Gets the function to be used to restrict vector
    235:    from level l to l-1.

    237:    Logically Collective on PC and Mat

    239:    Input Parameters:
    240: +  pc - the multigrid context
    241: -  l - the level (0 is coarsest) to supply [Do not supply 0]

    243:    Output Parameter:
    244: .  mat - the restriction matrix

    246:    Level: advanced

    248: .keywords: MG, get, multigrid, restriction, level

    250: .seealso: PCMGGetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
    251: @*/
    252: PetscErrorCode  PCMGGetRestriction(PC pc,PetscInt l,Mat *mat)
    253: {
    254:   PC_MG          *mg        = (PC_MG*)pc->data;
    255:   PC_MG_Levels   **mglevels = mg->levels;

    261:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    262:   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
    263:   if (!mglevels[l]->restrct) {
    264:     if (!mglevels[l]->interpolate) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call PCMGSetRestriction() or PCMGSetInterpolation()");
    265:     PCMGSetRestriction(pc,l,mglevels[l]->interpolate);
    266:   }
    267:   *mat = mglevels[l]->restrct;
    268:   return(0);
    269: }

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

    276:    Logically Collective on PC and Vec

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

    283:    Level: advanced

    285:    Notes:
    286:        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.

    288: .keywords: MG, set, multigrid, restriction, level

    290: .seealso: PCMGSetInterpolation(), PCMGSetRestriction(), PCMGGetRScale()
    291: @*/
    292: PetscErrorCode  PCMGSetRScale(PC pc,PetscInt l,Vec rscale)
    293: {
    295:   PC_MG          *mg        = (PC_MG*)pc->data;
    296:   PC_MG_Levels   **mglevels = mg->levels;

    300:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    301:   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
    302:   PetscObjectReference((PetscObject)rscale);
    303:   VecDestroy(&mglevels[l]->rscale);

    305:   mglevels[l]->rscale = rscale;
    306:   return(0);
    307: }

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

    314:    Collective on PC

    316:    Input Parameters:
    317: +  pc - the multigrid context
    318: .  rscale - the scaling
    319: -  l - the level (0 is coarsest) to supply [Do not supply 0]

    321:    Level: advanced

    323:    Notes:
    324:        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.

    326: .keywords: MG, set, multigrid, restriction, level

    328: .seealso: PCMGSetInterpolation(), PCMGGetRestriction()
    329: @*/
    330: PetscErrorCode PCMGGetRScale(PC pc,PetscInt l,Vec *rscale)
    331: {
    333:   PC_MG          *mg        = (PC_MG*)pc->data;
    334:   PC_MG_Levels   **mglevels = mg->levels;

    338:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    339:   if (l <= 0 || mg->nlevels <= l) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Level %D must be in range {1,...,%D}",l,mg->nlevels-1);
    340:   if (!mglevels[l]->rscale) {
    341:     Mat      R;
    342:     Vec      X,Y,coarse,fine;
    343:     PetscInt M,N;
    344:     PCMGGetRestriction(pc,l,&R);
    345:     MatCreateVecs(R,&X,&Y);
    346:     MatGetSize(R,&M,&N);
    347:     if (M < N) {
    348:       fine = X;
    349:       coarse = Y;
    350:     } else if (N < M) {
    351:       fine = Y; coarse = X;
    352:     } else SETERRQ(PetscObjectComm((PetscObject)R),PETSC_ERR_SUP,"Restriction matrix is square, cannot determine which Vec is coarser");
    353:     VecSet(fine,1.);
    354:     MatRestrict(R,fine,coarse);
    355:     VecDestroy(&fine);
    356:     VecReciprocal(coarse);
    357:     mglevels[l]->rscale = coarse;
    358:   }
    359:   *rscale = mglevels[l]->rscale;
    360:   return(0);
    361: }

    365: /*@
    366:    PCMGGetSmoother - Gets the KSP context to be used as smoother for
    367:    both pre- and post-smoothing.  Call both PCMGGetSmootherUp() and
    368:    PCMGGetSmootherDown() to use different functions for pre- and
    369:    post-smoothing.

    371:    Not Collective, KSP returned is parallel if PC is

    373:    Input Parameters:
    374: +  pc - the multigrid context
    375: -  l - the level (0 is coarsest) to supply

    377:    Ouput Parameters:
    378: .  ksp - the smoother

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

    385:    Level: advanced

    387: .keywords: MG, get, multigrid, level, smoother, pre-smoother, post-smoother

    389: .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
    390: @*/
    391: PetscErrorCode  PCMGGetSmoother(PC pc,PetscInt l,KSP *ksp)
    392: {
    393:   PC_MG        *mg        = (PC_MG*)pc->data;
    394:   PC_MG_Levels **mglevels = mg->levels;

    398:   *ksp = mglevels[l]->smoothd;
    399:   return(0);
    400: }

    404: /*@
    405:    PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
    406:    coarse grid correction (post-smoother).

    408:    Not Collective, KSP returned is parallel if PC is

    410:    Input Parameters:
    411: +  pc - the multigrid context
    412: -  l  - the level (0 is coarsest) to supply

    414:    Ouput Parameters:
    415: .  ksp - the smoother

    417:    Level: advanced

    419:    Notes: calling this will result in a different pre and post smoother so you may need to
    420:          set options on the pre smoother also

    422: .keywords: MG, multigrid, get, smoother, up, post-smoother, level

    424: .seealso: PCMGGetSmootherUp(), PCMGGetSmootherDown()
    425: @*/
    426: PetscErrorCode  PCMGGetSmootherUp(PC pc,PetscInt l,KSP *ksp)
    427: {
    428:   PC_MG          *mg        = (PC_MG*)pc->data;
    429:   PC_MG_Levels   **mglevels = mg->levels;
    431:   const char     *prefix;
    432:   MPI_Comm       comm;

    436:   /*
    437:      This is called only if user wants a different pre-smoother from post.
    438:      Thus we check if a different one has already been allocated,
    439:      if not we allocate it.
    440:   */
    441:   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"There is no such thing as a up smoother on the coarse grid");
    442:   if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
    443:     KSPType     ksptype;
    444:     PCType      pctype;
    445:     PC          ipc;
    446:     PetscReal   rtol,abstol,dtol;
    447:     PetscInt    maxits;
    448:     KSPNormType normtype;
    449:     PetscObjectGetComm((PetscObject)mglevels[l]->smoothd,&comm);
    450:     KSPGetOptionsPrefix(mglevels[l]->smoothd,&prefix);
    451:     KSPGetTolerances(mglevels[l]->smoothd,&rtol,&abstol,&dtol,&maxits);
    452:     KSPGetType(mglevels[l]->smoothd,&ksptype);
    453:     KSPGetNormType(mglevels[l]->smoothd,&normtype);
    454:     KSPGetPC(mglevels[l]->smoothd,&ipc);
    455:     PCGetType(ipc,&pctype);

    457:     KSPCreate(comm,&mglevels[l]->smoothu);
    458:     KSPSetErrorIfNotConverged(mglevels[l]->smoothu,pc->erroriffailure);
    459:     PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu,(PetscObject)pc,mglevels[0]->levels-l);
    460:     KSPSetOptionsPrefix(mglevels[l]->smoothu,prefix);
    461:     KSPSetTolerances(mglevels[l]->smoothu,rtol,abstol,dtol,maxits);
    462:     KSPSetType(mglevels[l]->smoothu,ksptype);
    463:     KSPSetNormType(mglevels[l]->smoothu,normtype);
    464:     KSPSetConvergenceTest(mglevels[l]->smoothu,KSPConvergedSkip,NULL,NULL);
    465:     KSPGetPC(mglevels[l]->smoothu,&ipc);
    466:     PCSetType(ipc,pctype);
    467:     PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[l]->smoothu);
    468:   }
    469:   if (ksp) *ksp = mglevels[l]->smoothu;
    470:   return(0);
    471: }

    475: /*@
    476:    PCMGGetSmootherDown - Gets the KSP context to be used as smoother before
    477:    coarse grid correction (pre-smoother).

    479:    Not Collective, KSP returned is parallel if PC is

    481:    Input Parameters:
    482: +  pc - the multigrid context
    483: -  l  - the level (0 is coarsest) to supply

    485:    Ouput Parameters:
    486: .  ksp - the smoother

    488:    Level: advanced

    490:    Notes: calling this will result in a different pre and post smoother so you may need to
    491:          set options on the post smoother also

    493: .keywords: MG, multigrid, get, smoother, down, pre-smoother, level

    495: .seealso: PCMGGetSmootherUp(), PCMGGetSmoother()
    496: @*/
    497: PetscErrorCode  PCMGGetSmootherDown(PC pc,PetscInt l,KSP *ksp)
    498: {
    500:   PC_MG          *mg        = (PC_MG*)pc->data;
    501:   PC_MG_Levels   **mglevels = mg->levels;

    505:   /* make sure smoother up and down are different */
    506:   if (l) {
    507:     PCMGGetSmootherUp(pc,l,NULL);
    508:   }
    509:   *ksp = mglevels[l]->smoothd;
    510:   return(0);
    511: }

    515: /*@
    516:    PCMGSetCyclesOnLevel - Sets the number of cycles to run on this level.

    518:    Logically Collective on PC

    520:    Input Parameters:
    521: +  pc - the multigrid context
    522: .  l  - the level (0 is coarsest) this is to be used for
    523: -  n  - the number of cycles

    525:    Level: advanced

    527: .keywords: MG, multigrid, set, cycles, V-cycle, W-cycle, level

    529: .seealso: PCMGSetCycles()
    530: @*/
    531: PetscErrorCode  PCMGSetCyclesOnLevel(PC pc,PetscInt l,PetscInt c)
    532: {
    533:   PC_MG        *mg        = (PC_MG*)pc->data;
    534:   PC_MG_Levels **mglevels = mg->levels;

    538:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    541:   mglevels[l]->cycles = c;
    542:   return(0);
    543: }

    547: /*@
    548:    PCMGSetRhs - Sets the vector space to be used to store the right-hand side
    549:    on a particular level.

    551:    Logically Collective on PC and Vec

    553:    Input Parameters:
    554: +  pc - the multigrid context
    555: .  l  - the level (0 is coarsest) this is to be used for
    556: -  c  - the space

    558:    Level: advanced

    560:    Notes: If this is not provided PETSc will automatically generate one.

    562:           You do not need to keep a reference to this vector if you do
    563:           not need it PCDestroy() will properly free it.

    565: .keywords: MG, multigrid, set, right-hand-side, rhs, level

    567: .seealso: PCMGSetX(), PCMGSetR()
    568: @*/
    569: PetscErrorCode  PCMGSetRhs(PC pc,PetscInt l,Vec c)
    570: {
    572:   PC_MG          *mg        = (PC_MG*)pc->data;
    573:   PC_MG_Levels   **mglevels = mg->levels;

    577:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    578:   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set rhs for finest level");
    579:   PetscObjectReference((PetscObject)c);
    580:   VecDestroy(&mglevels[l]->b);

    582:   mglevels[l]->b = c;
    583:   return(0);
    584: }

    588: /*@
    589:    PCMGSetX - Sets the vector space to be used to store the solution on a
    590:    particular level.

    592:    Logically Collective on PC and Vec

    594:    Input Parameters:
    595: +  pc - the multigrid context
    596: .  l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
    597: -  c - the space

    599:    Level: advanced

    601:    Notes: If this is not provided PETSc will automatically generate one.

    603:           You do not need to keep a reference to this vector if you do
    604:           not need it PCDestroy() will properly free it.

    606: .keywords: MG, multigrid, set, solution, level

    608: .seealso: PCMGSetRhs(), PCMGSetR()
    609: @*/
    610: PetscErrorCode  PCMGSetX(PC pc,PetscInt l,Vec c)
    611: {
    613:   PC_MG          *mg        = (PC_MG*)pc->data;
    614:   PC_MG_Levels   **mglevels = mg->levels;

    618:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    619:   if (l == mglevels[0]->levels-1) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Do not set x for finest level");
    620:   PetscObjectReference((PetscObject)c);
    621:   VecDestroy(&mglevels[l]->x);

    623:   mglevels[l]->x = c;
    624:   return(0);
    625: }

    629: /*@
    630:    PCMGSetR - Sets the vector space to be used to store the residual on a
    631:    particular level.

    633:    Logically Collective on PC and Vec

    635:    Input Parameters:
    636: +  pc - the multigrid context
    637: .  l - the level (0 is coarsest) this is to be used for
    638: -  c - the space

    640:    Level: advanced

    642:    Notes: If this is not provided PETSc will automatically generate one.

    644:           You do not need to keep a reference to this vector if you do
    645:           not need it PCDestroy() will properly free it.

    647: .keywords: MG, multigrid, set, residual, level
    648: @*/
    649: PetscErrorCode  PCMGSetR(PC pc,PetscInt l,Vec c)
    650: {
    652:   PC_MG          *mg        = (PC_MG*)pc->data;
    653:   PC_MG_Levels   **mglevels = mg->levels;

    657:   if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling");
    658:   if (!l) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Need not set residual vector for coarse grid");
    659:   PetscObjectReference((PetscObject)c);
    660:   VecDestroy(&mglevels[l]->r);

    662:   mglevels[l]->r = c;
    663:   return(0);
    664: }