Actual source code: mgfunc.c
petsc-3.7.1 2016-05-15
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, can be NULL

    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 PCMGSetRestriction()");
    178:     PCMGSetInterpolation(pc,l,mglevels[l]->restrct);
    179:   }
    180:   if (mat) *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:   if (mat) *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:     PetscObjectComposedDataSetInt((PetscObject) mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level);
    469:   }
    470:   if (ksp) *ksp = mglevels[l]->smoothu;
    471:   return(0);
    472: }

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

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

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

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

    489:    Level: advanced

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

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

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

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

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

    519:    Logically Collective on PC

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

    526:    Level: advanced

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

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

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

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

    552:    Logically Collective on PC and Vec

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

    559:    Level: advanced

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

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

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

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

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

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

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

    593:    Logically Collective on PC and Vec

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

    600:    Level: advanced

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

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

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

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

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

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

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

    634:    Logically Collective on PC and Vec

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

    641:    Level: advanced

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

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

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

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

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