Actual source code: dmdasnes.c

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

      5: /* This structure holds the user-provided DMDA callbacks */
      6: typedef struct {
      7:   PetscErrorCode (*residuallocal)(DMDALocalInfo*,void*,void*,void*);
      8:   PetscErrorCode (*jacobianlocal)(DMDALocalInfo*,void*,Mat,Mat,void*);
      9:   PetscErrorCode (*objectivelocal)(DMDALocalInfo*,void*,PetscReal*,void*);
     10:   void       *residuallocalctx;
     11:   void       *jacobianlocalctx;
     12:   void       *objectivelocalctx;
     13:   InsertMode residuallocalimode;

     15:   /*   For Picard iteration defined locally */
     16:   PetscErrorCode (*rhsplocal)(DMDALocalInfo*,void*,void*,void*);
     17:   PetscErrorCode (*jacobianplocal)(DMDALocalInfo*,void*,Mat,Mat,void*);
     18:   void *picardlocalctx;
     19: } DMSNES_DA;

     21: static PetscErrorCode DMSNESDestroy_DMDA(DMSNES sdm)
     22: {
     23:   PetscFree(sdm->data);
     24:   return 0;
     25: }

     27: static PetscErrorCode DMSNESDuplicate_DMDA(DMSNES oldsdm,DMSNES sdm)
     28: {
     29:   PetscNewLog(sdm,(DMSNES_DA**)&sdm->data);
     30:   if (oldsdm->data) {
     31:     PetscMemcpy(sdm->data,oldsdm->data,sizeof(DMSNES_DA));
     32:   }
     33:   return 0;
     34: }

     36: static PetscErrorCode DMDASNESGetContext(DM dm,DMSNES sdm,DMSNES_DA  **dmdasnes)
     37: {
     38:   *dmdasnes = NULL;
     39:   if (!sdm->data) {
     40:     PetscNewLog(dm,(DMSNES_DA**)&sdm->data);
     41:     sdm->ops->destroy   = DMSNESDestroy_DMDA;
     42:     sdm->ops->duplicate = DMSNESDuplicate_DMDA;
     43:   }
     44:   *dmdasnes = (DMSNES_DA*)sdm->data;
     45:   return 0;
     46: }

     48: static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx)
     49: {
     50:   DM             dm;
     51:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
     52:   DMDALocalInfo  info;
     53:   Vec            Xloc;
     54:   void           *x,*f;

     60:   SNESGetDM(snes,&dm);
     61:   DMGetLocalVector(dm,&Xloc);
     62:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
     63:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
     64:   DMDAGetLocalInfo(dm,&info);
     65:   DMDAVecGetArray(dm,Xloc,&x);
     66:   switch (dmdasnes->residuallocalimode) {
     67:   case INSERT_VALUES: {
     68:     DMDAVecGetArray(dm,F,&f);
     69:     PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);
     70:     CHKMEMQ;
     71:     (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
     72:     CHKMEMQ;
     73:     PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);
     74:     DMDAVecRestoreArray(dm,F,&f);
     75:   } break;
     76:   case ADD_VALUES: {
     77:     Vec Floc;
     78:     DMGetLocalVector(dm,&Floc);
     79:     VecZeroEntries(Floc);
     80:     DMDAVecGetArray(dm,Floc,&f);
     81:     PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);
     82:     CHKMEMQ;
     83:     (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
     84:     CHKMEMQ;
     85:     PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);
     86:     DMDAVecRestoreArray(dm,Floc,&f);
     87:     VecZeroEntries(F);
     88:     DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
     89:     DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
     90:     DMRestoreLocalVector(dm,&Floc);
     91:   } break;
     92:   default: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
     93:   }
     94:   DMDAVecRestoreArray(dm,Xloc,&x);
     95:   DMRestoreLocalVector(dm,&Xloc);
     96:   if (snes->domainerror) {
     97:     VecSetInf(F);
     98:   }
     99:   return 0;
    100: }

    102: static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx)
    103: {
    104:   DM             dm;
    105:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    106:   DMDALocalInfo  info;
    107:   Vec            Xloc;
    108:   void           *x;

    114:   SNESGetDM(snes,&dm);
    115:   DMGetLocalVector(dm,&Xloc);
    116:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    117:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    118:   DMDAGetLocalInfo(dm,&info);
    119:   DMDAVecGetArray(dm,Xloc,&x);
    120:   CHKMEMQ;
    121:   (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);
    122:   CHKMEMQ;
    123:   DMDAVecRestoreArray(dm,Xloc,&x);
    124:   DMRestoreLocalVector(dm,&Xloc);
    125:   return 0;
    126: }

    128: /* Routine is called by example, hence must be labeled PETSC_EXTERN */
    129: PETSC_EXTERN PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
    130: {
    131:   DM             dm;
    132:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    133:   DMDALocalInfo  info;
    134:   Vec            Xloc;
    135:   void           *x;

    138:   SNESGetDM(snes,&dm);

    140:   if (dmdasnes->jacobianlocal) {
    141:     DMGetLocalVector(dm,&Xloc);
    142:     DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    143:     DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    144:     DMDAGetLocalInfo(dm,&info);
    145:     DMDAVecGetArray(dm,Xloc,&x);
    146:     CHKMEMQ;
    147:     (*dmdasnes->jacobianlocal)(&info,x,A,B,dmdasnes->jacobianlocalctx);
    148:     CHKMEMQ;
    149:     DMDAVecRestoreArray(dm,Xloc,&x);
    150:     DMRestoreLocalVector(dm,&Xloc);
    151:   } else {
    152:     MatFDColoring fdcoloring;
    153:     PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);
    154:     if (!fdcoloring) {
    155:       ISColoring coloring;

    157:       DMCreateColoring(dm,dm->coloringtype,&coloring);
    158:       MatFDColoringCreate(B,coloring,&fdcoloring);
    159:       switch (dm->coloringtype) {
    160:       case IS_COLORING_GLOBAL:
    161:         MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))SNESComputeFunction_DMDA,dmdasnes);
    162:         break;
    163:       default: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]);
    164:       }
    165:       PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);
    166:       MatFDColoringSetFromOptions(fdcoloring);
    167:       MatFDColoringSetUp(B,coloring,fdcoloring);
    168:       ISColoringDestroy(&coloring);
    169:       PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);
    170:       PetscObjectDereference((PetscObject)fdcoloring);

    172:       /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
    173:        * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
    174:        * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
    175:        * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
    176:        * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
    177:        */
    178:       PetscObjectDereference((PetscObject)dm);
    179:     }
    180:     MatFDColoringApply(B,fdcoloring,X,snes);
    181:   }
    182:   /* This will be redundant if the user called both, but it's too common to forget. */
    183:   if (A != B) {
    184:     MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    185:     MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    186:   }
    187:   return 0;
    188: }

    190: /*@C
    191:    DMDASNESSetFunctionLocal - set a local residual evaluation function

    193:    Logically Collective

    195:    Input Parameters:
    196: +  dm - DM to associate callback with
    197: .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
    198: .  func - local residual evaluation
    199: -  ctx - optional context for local residual evaluation

    201:    Calling sequence:
    202:    For PetscErrorCode (*func)(DMDALocalInfo *info,void *x, void *f, void *ctx),
    203: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    204: .  x - dimensional pointer to state at which to evaluate residual (e.g. PetscScalar *x or **x or ***x)
    205: .  f - dimensional pointer to residual, write the residual here (e.g. PetscScalar *f or **f or ***f)
    206: -  ctx - optional context passed above

    208:    Level: beginner

    210: .seealso: DMDASNESSetJacobianLocal(), DMSNESSetFunction(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    211: @*/
    212: PetscErrorCode DMDASNESSetFunctionLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),void *ctx)
    213: {
    214:   DMSNES         sdm;
    215:   DMSNES_DA      *dmdasnes;

    218:   DMGetDMSNESWrite(dm,&sdm);
    219:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    221:   dmdasnes->residuallocalimode = imode;
    222:   dmdasnes->residuallocal      = func;
    223:   dmdasnes->residuallocalctx   = ctx;

    225:   DMSNESSetFunction(dm,SNESComputeFunction_DMDA,dmdasnes);
    226:   if (!sdm->ops->computejacobian) {  /* Call us for the Jacobian too, can be overridden by the user. */
    227:     DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
    228:   }
    229:   return 0;
    230: }

    232: /*@C
    233:    DMDASNESSetJacobianLocal - set a local Jacobian evaluation function

    235:    Logically Collective

    237:    Input Parameters:
    238: +  dm - DM to associate callback with
    239: .  func - local Jacobian evaluation
    240: -  ctx - optional context for local Jacobian evaluation

    242:    Calling sequence:
    243:    For PetscErrorCode (*func)(DMDALocalInfo *info,void *x,Mat J,Mat M,void *ctx),
    244: +  info - DMDALocalInfo defining the subdomain to evaluate the Jacobian at
    245: .  x - dimensional pointer to state at which to evaluate Jacobian (e.g. PetscScalar *x or **x or ***x)
    246: .  J - Mat object for the Jacobian
    247: .  M - Mat object for the Jacobian preconditioner matrix
    248: -  ctx - optional context passed above

    250:    Level: beginner

    252: .seealso: DMDASNESSetFunctionLocal(), DMSNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    253: @*/
    254: PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
    255: {
    256:   DMSNES         sdm;
    257:   DMSNES_DA      *dmdasnes;

    260:   DMGetDMSNESWrite(dm,&sdm);
    261:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    263:   dmdasnes->jacobianlocal    = func;
    264:   dmdasnes->jacobianlocalctx = ctx;

    266:   DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
    267:   return 0;
    268: }

    270: /*@C
    271:    DMDASNESSetObjectiveLocal - set a local residual evaluation function

    273:    Logically Collective

    275:    Input Parameters:
    276: +  dm - DM to associate callback with
    277: .  func - local objective evaluation
    278: -  ctx - optional context for local residual evaluation

    280:    Calling sequence for func:
    281: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    282: .  x - dimensional pointer to state at which to evaluate residual
    283: .  ob - eventual objective value
    284: -  ctx - optional context passed above

    286:    Level: beginner

    288: .seealso: DMSNESSetFunction(), DMDASNESSetJacobianLocal(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    289: @*/
    290: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx)
    291: {
    292:   DMSNES         sdm;
    293:   DMSNES_DA      *dmdasnes;

    296:   DMGetDMSNESWrite(dm,&sdm);
    297:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    299:   dmdasnes->objectivelocal    = func;
    300:   dmdasnes->objectivelocalctx = ctx;

    302:   DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);
    303:   return 0;
    304: }

    306: static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx)
    307: {
    308:   DM             dm;
    309:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    310:   DMDALocalInfo  info;
    311:   Vec            Xloc;
    312:   void           *x,*f;

    318:   SNESGetDM(snes,&dm);
    319:   DMGetLocalVector(dm,&Xloc);
    320:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    321:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    322:   DMDAGetLocalInfo(dm,&info);
    323:   DMDAVecGetArray(dm,Xloc,&x);
    324:   switch (dmdasnes->residuallocalimode) {
    325:   case INSERT_VALUES: {
    326:     DMDAVecGetArray(dm,F,&f);
    327:     CHKMEMQ;
    328:     (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
    329:     CHKMEMQ;
    330:     DMDAVecRestoreArray(dm,F,&f);
    331:   } break;
    332:   case ADD_VALUES: {
    333:     Vec Floc;
    334:     DMGetLocalVector(dm,&Floc);
    335:     VecZeroEntries(Floc);
    336:     DMDAVecGetArray(dm,Floc,&f);
    337:     CHKMEMQ;
    338:     (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
    339:     CHKMEMQ;
    340:     DMDAVecRestoreArray(dm,Floc,&f);
    341:     VecZeroEntries(F);
    342:     DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
    343:     DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
    344:     DMRestoreLocalVector(dm,&Floc);
    345:   } break;
    346:   default: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
    347:   }
    348:   DMDAVecRestoreArray(dm,Xloc,&x);
    349:   DMRestoreLocalVector(dm,&Xloc);
    350:   return 0;
    351: }

    353: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
    354: {
    355:   DM             dm;
    356:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    357:   DMDALocalInfo  info;
    358:   Vec            Xloc;
    359:   void           *x;

    362:   SNESGetDM(snes,&dm);

    364:   DMGetLocalVector(dm,&Xloc);
    365:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    366:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    367:   DMDAGetLocalInfo(dm,&info);
    368:   DMDAVecGetArray(dm,Xloc,&x);
    369:   CHKMEMQ;
    370:   (*dmdasnes->jacobianplocal)(&info,x,A,B,dmdasnes->picardlocalctx);
    371:   CHKMEMQ;
    372:   DMDAVecRestoreArray(dm,Xloc,&x);
    373:   DMRestoreLocalVector(dm,&Xloc);
    374:   if (A != B) {
    375:     MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    376:     MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    377:   }
    378:   return 0;
    379: }

    381: /*@C
    382:    DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration

    384:    Logically Collective

    386:    Input Parameters:
    387: +  dm - DM to associate callback with
    388: .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
    389: .  func - local residual evaluation
    390: -  ctx - optional context for local residual evaluation

    392:    Calling sequence for func:
    393: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    394: .  x - dimensional pointer to state at which to evaluate residual
    395: .  f - dimensional pointer to residual, write the residual here
    396: -  ctx - optional context passed above

    398:    Notes:
    399:     The user must use
    400:     SNESSetFunction(snes,NULL,SNESPicardComputeFunction,&user);
    401:     in their code before calling this routine.

    403:    Level: beginner

    405: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    406: @*/
    407: PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),
    408:                                       PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
    409: {
    410:   DMSNES         sdm;
    411:   DMSNES_DA      *dmdasnes;

    414:   DMGetDMSNESWrite(dm,&sdm);
    415:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    417:   dmdasnes->residuallocalimode = imode;
    418:   dmdasnes->rhsplocal          = func;
    419:   dmdasnes->jacobianplocal     = jac;
    420:   dmdasnes->picardlocalctx     = ctx;

    422:   DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);
    423:   DMSNESSetMFFunction(dm,SNESComputeFunction_DMDA,dmdasnes);
    424:   return 0;
    425: }