Actual source code: dmsnes.c

      1: #include <petsc/private/snesimpl.h>
      2: #include <petsc/private/dmimpl.h>

      4: static PetscErrorCode DMSNESDestroy(DMSNES *kdm)
      5: {
      6:   if (!*kdm) return 0;
      8:   if (--((PetscObject)(*kdm))->refct > 0) {*kdm = NULL; return 0;}
      9:   if ((*kdm)->ops->destroy) ((*kdm)->ops->destroy)(*kdm);
     10:   PetscHeaderDestroy(kdm);
     11:   return 0;
     12: }

     14: PetscErrorCode DMSNESLoad(DMSNES kdm,PetscViewer viewer)
     15: {
     16:   PetscViewerBinaryRead(viewer,&kdm->ops->computefunction,1,NULL,PETSC_FUNCTION);
     17:   PetscViewerBinaryRead(viewer,&kdm->ops->computejacobian,1,NULL,PETSC_FUNCTION);
     18:   return 0;
     19: }

     21: PetscErrorCode DMSNESView(DMSNES kdm,PetscViewer viewer)
     22: {
     23:   PetscBool      isascii,isbinary;

     25:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
     26:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
     27:   if (isascii) {
     28: #if defined(PETSC_SERIALIZE_FUNCTIONS) && defined(PETSC_SERIALIZE_FUNCTIONS_VIEW)
     29:     const char *fname;

     31:     PetscFPTFind(kdm->ops->computefunction,&fname);
     32:     if (fname) {
     33:       PetscViewerASCIIPrintf(viewer,"Function used by SNES: %s\n",fname);
     34:     }
     35:     PetscFPTFind(kdm->ops->computejacobian,&fname);
     36:     if (fname) {
     37:       PetscViewerASCIIPrintf(viewer,"Jacobian function used by SNES: %s\n",fname);
     38:     }
     39: #endif
     40:   } else if (isbinary) {
     41:     struct {
     42:       PetscErrorCode (*func)(SNES,Vec,Vec,void*);
     43:     } funcstruct;
     44:     struct {
     45:       PetscErrorCode (*jac)(SNES,Vec,Mat,Mat,void*);
     46:     } jacstruct;
     47:     funcstruct.func = kdm->ops->computefunction;
     48:     jacstruct.jac   = kdm->ops->computejacobian;
     49:     PetscViewerBinaryWrite(viewer,&funcstruct,1,PETSC_FUNCTION);
     50:     PetscViewerBinaryWrite(viewer,&jacstruct,1,PETSC_FUNCTION);
     51:   }
     52:   return 0;
     53: }

     55: static PetscErrorCode DMSNESCreate(MPI_Comm comm,DMSNES *kdm)
     56: {
     57:   SNESInitializePackage();
     58:   PetscHeaderCreate(*kdm, DMSNES_CLASSID,  "DMSNES", "DMSNES", "DMSNES", comm, DMSNESDestroy, DMSNESView);
     59:   return 0;
     60: }

     62: /* Attaches the DMSNES to the coarse level.
     63:  * Under what conditions should we copy versus duplicate?
     64:  */
     65: static PetscErrorCode DMCoarsenHook_DMSNES(DM dm,DM dmc,void *ctx)
     66: {
     67:   DMCopyDMSNES(dm,dmc);
     68:   return 0;
     69: }

     71: /* This could restrict auxiliary information to the coarse level.
     72:  */
     73: static PetscErrorCode DMRestrictHook_DMSNES(DM dm,Mat Restrict,Vec rscale,Mat Inject,DM dmc,void *ctx)
     74: {
     75:   return 0;
     76: }

     78: /* Attaches the DMSNES to the subdomain. */
     79: static PetscErrorCode DMSubDomainHook_DMSNES(DM dm,DM subdm,void *ctx)
     80: {
     81:   DMCopyDMSNES(dm,subdm);
     82:   return 0;
     83: }

     85: /* This could restrict auxiliary information to the coarse level.
     86:  */
     87: static PetscErrorCode DMSubDomainRestrictHook_DMSNES(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
     88: {
     89:   return 0;
     90: }

     92: static PetscErrorCode DMRefineHook_DMSNES(DM dm,DM dmf,void *ctx)
     93: {
     94:   DMCopyDMSNES(dm,dmf);
     95:   return 0;
     96: }

     98: /* This could restrict auxiliary information to the coarse level.
     99:  */
    100: static PetscErrorCode DMInterpolateHook_DMSNES(DM dm,Mat Interp,DM dmf,void *ctx)
    101: {
    102:   return 0;
    103: }

    105: /*@C
    106:    DMSNESCopy - copies the information in a DMSNES to another DMSNES

    108:    Not Collective

    110:    Input Parameters:
    111: +  kdm - Original DMSNES
    112: -  nkdm - DMSNES to receive the data, should have been created with DMSNESCreate()

    114:    Level: developer

    116: .seealso: DMSNESCreate(), DMSNESDestroy()
    117: @*/
    118: PetscErrorCode DMSNESCopy(DMSNES kdm,DMSNES nkdm)
    119: {
    122:   nkdm->ops->computefunction  = kdm->ops->computefunction;
    123:   nkdm->ops->computejacobian  = kdm->ops->computejacobian;
    124:   nkdm->ops->computegs        = kdm->ops->computegs;
    125:   nkdm->ops->computeobjective = kdm->ops->computeobjective;
    126:   nkdm->ops->computepjacobian = kdm->ops->computepjacobian;
    127:   nkdm->ops->computepfunction = kdm->ops->computepfunction;
    128:   nkdm->ops->destroy          = kdm->ops->destroy;
    129:   nkdm->ops->duplicate        = kdm->ops->duplicate;

    131:   nkdm->functionctx  = kdm->functionctx;
    132:   nkdm->gsctx        = kdm->gsctx;
    133:   nkdm->pctx         = kdm->pctx;
    134:   nkdm->jacobianctx  = kdm->jacobianctx;
    135:   nkdm->objectivectx = kdm->objectivectx;
    136:   nkdm->originaldm   = kdm->originaldm;

    138:   /*
    139:   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
    140:   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
    141:   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
    142:   */

    144:   /* implementation specific copy hooks */
    145:   if (kdm->ops->duplicate) (*kdm->ops->duplicate)(kdm,nkdm);
    146:   return 0;
    147: }

    149: /*@C
    150:    DMGetDMSNES - get read-only private DMSNES context from a DM

    152:    Not Collective

    154:    Input Parameter:
    155: .  dm - DM to be used with SNES

    157:    Output Parameter:
    158: .  snesdm - private DMSNES context

    160:    Level: developer

    162:    Notes:
    163:    Use DMGetDMSNESWrite() if write access is needed. The DMSNESSetXXX API should be used wherever possible.

    165: .seealso: DMGetDMSNESWrite()
    166: @*/
    167: PetscErrorCode DMGetDMSNES(DM dm,DMSNES *snesdm)
    168: {
    170:   *snesdm = (DMSNES) dm->dmsnes;
    171:   if (!*snesdm) {
    172:     PetscInfo(dm,"Creating new DMSNES\n");
    173:     DMSNESCreate(PetscObjectComm((PetscObject)dm),snesdm);

    175:     dm->dmsnes            = (PetscObject) *snesdm;
    176:     (*snesdm)->originaldm = dm;
    177:     DMCoarsenHookAdd(dm,DMCoarsenHook_DMSNES,DMRestrictHook_DMSNES,NULL);
    178:     DMRefineHookAdd(dm,DMRefineHook_DMSNES,DMInterpolateHook_DMSNES,NULL);
    179:     DMSubDomainHookAdd(dm,DMSubDomainHook_DMSNES,DMSubDomainRestrictHook_DMSNES,NULL);
    180:   }
    181:   return 0;
    182: }

    184: /*@C
    185:    DMGetDMSNESWrite - get write access to private DMSNES context from a DM

    187:    Not Collective

    189:    Input Parameter:
    190: .  dm - DM to be used with SNES

    192:    Output Parameter:
    193: .  snesdm - private DMSNES context

    195:    Level: developer

    197: .seealso: DMGetDMSNES()
    198: @*/
    199: PetscErrorCode DMGetDMSNESWrite(DM dm,DMSNES *snesdm)
    200: {
    201:   DMSNES         sdm;

    204:   DMGetDMSNES(dm,&sdm);
    206:   if (sdm->originaldm != dm) {  /* Copy on write */
    207:     DMSNES oldsdm = sdm;
    208:     PetscInfo(dm,"Copying DMSNES due to write\n");
    209:     DMSNESCreate(PetscObjectComm((PetscObject)dm),&sdm);
    210:     DMSNESCopy(oldsdm,sdm);
    211:     DMSNESDestroy((DMSNES*)&dm->dmsnes);
    212:     dm->dmsnes = (PetscObject)sdm;
    213:     sdm->originaldm = dm;
    214:   }
    215:   *snesdm = sdm;
    216:   return 0;
    217: }

    219: /*@C
    220:    DMCopyDMSNES - copies a DM context to a new DM

    222:    Logically Collective

    224:    Input Parameters:
    225: +  dmsrc - DM to obtain context from
    226: -  dmdest - DM to add context to

    228:    Level: developer

    230:    Note:
    231:    The context is copied by reference. This function does not ensure that a context exists.

    233: .seealso: DMGetDMSNES(), SNESSetDM()
    234: @*/
    235: PetscErrorCode DMCopyDMSNES(DM dmsrc,DM dmdest)
    236: {
    239:   if (!dmdest->dmsnes) DMSNESCreate(PetscObjectComm((PetscObject) dmdest), (DMSNES *) &dmdest->dmsnes);
    240:   DMSNESCopy((DMSNES) dmsrc->dmsnes, (DMSNES) dmdest->dmsnes);
    241:   DMCoarsenHookAdd(dmdest,DMCoarsenHook_DMSNES,NULL,NULL);
    242:   DMRefineHookAdd(dmdest,DMRefineHook_DMSNES,NULL,NULL);
    243:   DMSubDomainHookAdd(dmdest,DMSubDomainHook_DMSNES,DMSubDomainRestrictHook_DMSNES,NULL);
    244:   return 0;
    245: }

    247: /*@C
    248:    DMSNESSetFunction - set SNES residual evaluation function

    250:    Not Collective

    252:    Input Parameters:
    253: +  dm - DM to be used with SNES
    254: .  f - residual evaluation function; see SNESFunction for details
    255: -  ctx - context for residual evaluation

    257:    Level: advanced

    259:    Note:
    260:    SNESSetFunction() is normally used, but it calls this function internally because the user context is actually
    261:    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
    262:    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.

    264: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), SNESFunction
    265: @*/
    266: PetscErrorCode DMSNESSetFunction(DM dm,PetscErrorCode (*f)(SNES,Vec,Vec,void*),void *ctx)
    267: {
    268:   DMSNES         sdm;

    271:   if (f || ctx) {
    272:     DMGetDMSNESWrite(dm,&sdm);
    273:   }
    274:   if (f) sdm->ops->computefunction = f;
    275:   if (ctx) sdm->functionctx = ctx;
    276:   return 0;
    277: }

    279: /*@C
    280:    DMSNESSetMFFunction - set SNES residual evaluation function used in applying the matrix-free Jacobian with -snes_mf_operator

    282:    Logically Collective on dm

    284:    Input Parameters:
    285: +  dm - DM to be used with SNES
    286: -  f - residual evaluation function; see SNESFunction for details

    288:    Level: advanced

    290: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), SNESFunction, DMSNESSetFunction()
    291: @*/
    292: PetscErrorCode DMSNESSetMFFunction(DM dm,PetscErrorCode (*f)(SNES,Vec,Vec,void*),void *ctx)
    293: {
    294:   DMSNES         sdm;

    297:   if (f || ctx) {
    298:     DMGetDMSNESWrite(dm,&sdm);
    299:   }
    300:   if (f) sdm->ops->computemffunction = f;
    301:   if (ctx) sdm->mffunctionctx = ctx;
    302:   return 0;
    303: }

    305: /*@C
    306:    DMSNESGetFunction - get SNES residual evaluation function

    308:    Not Collective

    310:    Input Parameter:
    311: .  dm - DM to be used with SNES

    313:    Output Parameters:
    314: +  f - residual evaluation function; see SNESFunction for details
    315: -  ctx - context for residual evaluation

    317:    Level: advanced

    319:    Note:
    320:    SNESGetFunction() is normally used, but it calls this function internally because the user context is actually
    321:    associated with the DM.

    323: .seealso: DMSNESSetContext(), DMSNESSetFunction(), SNESSetFunction(), SNESFunction
    324: @*/
    325: PetscErrorCode DMSNESGetFunction(DM dm,PetscErrorCode (**f)(SNES,Vec,Vec,void*),void **ctx)
    326: {
    327:   DMSNES         sdm;

    330:   DMGetDMSNES(dm,&sdm);
    331:   if (f) *f = sdm->ops->computefunction;
    332:   if (ctx) *ctx = sdm->functionctx;
    333:   return 0;
    334: }

    336: /*@C
    337:    DMSNESSetObjective - set SNES objective evaluation function

    339:    Not Collective

    341:    Input Parameters:
    342: +  dm - DM to be used with SNES
    343: .  obj - objective evaluation function; see SNESObjectiveFunction for details
    344: -  ctx - context for residual evaluation

    346:    Level: advanced

    348: .seealso: DMSNESSetContext(), SNESGetObjective(), DMSNESSetFunction()
    349: @*/
    350: PetscErrorCode DMSNESSetObjective(DM dm,PetscErrorCode (*obj)(SNES,Vec,PetscReal*,void*),void *ctx)
    351: {
    352:   DMSNES         sdm;

    355:   if (obj || ctx) {
    356:     DMGetDMSNESWrite(dm,&sdm);
    357:   }
    358:   if (obj) sdm->ops->computeobjective = obj;
    359:   if (ctx) sdm->objectivectx = ctx;
    360:   return 0;
    361: }

    363: /*@C
    364:    DMSNESGetObjective - get SNES objective evaluation function

    366:    Not Collective

    368:    Input Parameter:
    369: .  dm - DM to be used with SNES

    371:    Output Parameters:
    372: +  obj- residual evaluation function; see SNESObjectiveFunction for details
    373: -  ctx - context for residual evaluation

    375:    Level: advanced

    377:    Note:
    378:    SNESGetFunction() is normally used, but it calls this function internally because the user context is actually
    379:    associated with the DM.

    381: .seealso: DMSNESSetContext(), DMSNESSetObjective(), SNESSetFunction()
    382: @*/
    383: PetscErrorCode DMSNESGetObjective(DM dm,PetscErrorCode (**obj)(SNES,Vec,PetscReal*,void*),void **ctx)
    384: {
    385:   DMSNES         sdm;

    388:   DMGetDMSNES(dm,&sdm);
    389:   if (obj) *obj = sdm->ops->computeobjective;
    390:   if (ctx) *ctx = sdm->objectivectx;
    391:   return 0;
    392: }

    394: /*@C
    395:    DMSNESSetNGS - set SNES Gauss-Seidel relaxation function

    397:    Not Collective

    399:    Input Parameters:
    400: +  dm - DM to be used with SNES
    401: .  f  - relaxation function, see SNESGSFunction
    402: -  ctx - context for residual evaluation

    404:    Level: advanced

    406:    Note:
    407:    SNESSetNGS() is normally used, but it calls this function internally because the user context is actually
    408:    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
    409:    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.

    411: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), DMSNESSetFunction(), SNESGSFunction
    412: @*/
    413: PetscErrorCode DMSNESSetNGS(DM dm,PetscErrorCode (*f)(SNES,Vec,Vec,void*),void *ctx)
    414: {
    415:   DMSNES         sdm;

    418:   if (f || ctx) {
    419:     DMGetDMSNESWrite(dm,&sdm);
    420:   }
    421:   if (f) sdm->ops->computegs = f;
    422:   if (ctx) sdm->gsctx = ctx;
    423:   return 0;
    424: }

    426: /*@C
    427:    DMSNESGetNGS - get SNES Gauss-Seidel relaxation function

    429:    Not Collective

    431:    Input Parameter:
    432: .  dm - DM to be used with SNES

    434:    Output Parameters:
    435: +  f - relaxation function which performs Gauss-Seidel sweeps, see SNESGSFunction
    436: -  ctx - context for residual evaluation

    438:    Level: advanced

    440:    Note:
    441:    SNESGetNGS() is normally used, but it calls this function internally because the user context is actually
    442:    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
    443:    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.

    445: .seealso: DMSNESSetContext(), SNESGetNGS(), DMSNESGetJacobian(), DMSNESGetFunction(), SNESNGSFunction
    446: @*/
    447: PetscErrorCode DMSNESGetNGS(DM dm,PetscErrorCode (**f)(SNES,Vec,Vec,void*),void **ctx)
    448: {
    449:   DMSNES         sdm;

    452:   DMGetDMSNES(dm,&sdm);
    453:   if (f) *f = sdm->ops->computegs;
    454:   if (ctx) *ctx = sdm->gsctx;
    455:   return 0;
    456: }

    458: /*@C
    459:    DMSNESSetJacobian - set SNES Jacobian evaluation function

    461:    Not Collective

    463:    Input Parameters:
    464: +  dm - DM to be used with SNES
    465: .  J - Jacobian evaluation function
    466: -  ctx - context for residual evaluation

    468:    Level: advanced

    470:    Note:
    471:    SNESSetJacobian() is normally used, but it calls this function internally because the user context is actually
    472:    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
    473:    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.

    475: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESGetJacobian(), SNESSetJacobian(), SNESJacobianFunction
    476: @*/
    477: PetscErrorCode DMSNESSetJacobian(DM dm,PetscErrorCode (*J)(SNES,Vec,Mat,Mat,void*),void *ctx)
    478: {
    479:   DMSNES         sdm;

    482:   if (J || ctx) {
    483:     DMGetDMSNESWrite(dm,&sdm);
    484:   }
    485:   if (J) sdm->ops->computejacobian = J;
    486:   if (ctx) sdm->jacobianctx = ctx;
    487:   return 0;
    488: }

    490: /*@C
    491:    DMSNESGetJacobian - get SNES Jacobian evaluation function

    493:    Not Collective

    495:    Input Parameter:
    496: .  dm - DM to be used with SNES

    498:    Output Parameters:
    499: +  J - Jacobian evaluation function; see SNESJacobianFunction for all calling sequence
    500: -  ctx - context for residual evaluation

    502:    Level: advanced

    504:    Note:
    505:    SNESGetJacobian() is normally used, but it calls this function internally because the user context is actually
    506:    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
    507:    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.

    509: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), SNESJacobianFunction
    510: @*/
    511: PetscErrorCode DMSNESGetJacobian(DM dm,PetscErrorCode (**J)(SNES,Vec,Mat,Mat,void*),void **ctx)
    512: {
    513:   DMSNES         sdm;

    516:   DMGetDMSNES(dm,&sdm);
    517:   if (J) *J = sdm->ops->computejacobian;
    518:   if (ctx) *ctx = sdm->jacobianctx;
    519:   return 0;
    520: }

    522: /*@C
    523:    DMSNESSetPicard - set SNES Picard iteration matrix and RHS evaluation functions.

    525:    Not Collective

    527:    Input Parameters:
    528: +  dm - DM to be used with SNES
    529: .  b - RHS evaluation function
    530: .  J - Picard matrix evaluation function
    531: -  ctx - context for residual evaluation

    533:    Level: advanced

    535: .seealso: SNESSetPicard(), DMSNESSetFunction(), DMSNESSetJacobian()
    536: @*/
    537: PetscErrorCode DMSNESSetPicard(DM dm,PetscErrorCode (*b)(SNES,Vec,Vec,void*),PetscErrorCode (*J)(SNES,Vec,Mat,Mat,void*),void *ctx)
    538: {
    539:   DMSNES         sdm;

    542:   DMGetDMSNES(dm,&sdm);
    543:   if (b) sdm->ops->computepfunction = b;
    544:   if (J) sdm->ops->computepjacobian = J;
    545:   if (ctx) sdm->pctx = ctx;
    546:   return 0;
    547: }

    549: /*@C
    550:    DMSNESGetPicard - get SNES Picard iteration evaluation functions

    552:    Not Collective

    554:    Input Parameter:
    555: .  dm - DM to be used with SNES

    557:    Output Parameters:
    558: +  b - RHS evaluation function; see SNESFunction for details
    559: .  J  - RHS evaluation function; see SNESJacobianFunction for detailsa
    560: -  ctx - context for residual evaluation

    562:    Level: advanced

    564: .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian()
    565: @*/
    566: PetscErrorCode DMSNESGetPicard(DM dm,PetscErrorCode (**b)(SNES,Vec,Vec,void*),PetscErrorCode (**J)(SNES,Vec,Mat,Mat,void*),void **ctx)
    567: {
    568:   DMSNES         sdm;

    571:   DMGetDMSNES(dm,&sdm);
    572:   if (b) *b = sdm->ops->computepfunction;
    573:   if (J) *J = sdm->ops->computepjacobian;
    574:   if (ctx) *ctx = sdm->pctx;
    575:   return 0;
    576: }