Date: 2013-07-02T14:50:43+00:00

Actual source code: dmdasnes.c
petsc-3.4.2 2013-07-02

      1: #include <petscdmda.h>          /*I "petscdmda.h" I*/
      2: #include <petsc-private/dmimpl.h>
      3: #include <petsc-private/snesimpl.h>   /*I "petscsnes.h" I*/

      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,MatStructure*,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,MatStructure*,void*);
     18:   void *picardlocalctx;
     19: } DMSNES_DA;

     23: static PetscErrorCode DMSNESDestroy_DMDA(DMSNES sdm)
     24: {

     28:   PetscFree(sdm->data);
     29:   return(0);
     30: }

     34: static PetscErrorCode DMSNESDuplicate_DMDA(DMSNES oldsdm,DMSNES sdm)
     35: {

     39:   PetscNewLog(sdm,DMSNES_DA,&sdm->data);
     40:   if (oldsdm->data) {
     41:     PetscMemcpy(sdm->data,oldsdm->data,sizeof(DMSNES_DA));
     42:   }
     43:   return(0);
     44: }

     49: static PetscErrorCode DMDASNESGetContext(DM dm,DMSNES sdm,DMSNES_DA  **dmdasnes)
     50: {

     54:   *dmdasnes = NULL;
     55:   if (!sdm->data) {
     56:     PetscNewLog(dm,DMSNES_DA,&sdm->data);
     57:     sdm->ops->destroy   = DMSNESDestroy_DMDA;
     58:     sdm->ops->duplicate = DMSNESDuplicate_DMDA;
     59:   }
     60:   *dmdasnes = (DMSNES_DA*)sdm->data;
     61:   return(0);
     62: }

     66: /*
     67:   This function should eventually replace:
     68:     DMDAComputeFunction() and DMDAComputeFunction1()
     69:  */
     70: static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx)
     71: {
     73:   DM             dm;
     74:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
     75:   DMDALocalInfo  info;
     76:   Vec            Xloc;
     77:   void           *x,*f;

     83:   if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
     84:   SNESGetDM(snes,&dm);
     85:   DMGetLocalVector(dm,&Xloc);
     86:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
     87:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
     88:   DMDAGetLocalInfo(dm,&info);
     89:   DMDAVecGetArray(dm,Xloc,&x);
     90:   switch (dmdasnes->residuallocalimode) {
     91:   case INSERT_VALUES: {
     92:     DMDAVecGetArray(dm,F,&f);
     93:     CHKMEMQ;
     94:     (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
     95:     CHKMEMQ;
     96:     DMDAVecRestoreArray(dm,F,&f);
     97:   } break;
     98:   case ADD_VALUES: {
     99:     Vec Floc;
    100:     DMGetLocalVector(dm,&Floc);
    101:     VecZeroEntries(Floc);
    102:     DMDAVecGetArray(dm,Floc,&f);
    103:     CHKMEMQ;
    104:     (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
    105:     CHKMEMQ;
    106:     DMDAVecRestoreArray(dm,Floc,&f);
    107:     VecZeroEntries(F);
    108:     DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
    109:     DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
    110:     DMRestoreLocalVector(dm,&Floc);
    111:   } break;
    112:   default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
    113:   }
    114:   DMDAVecRestoreArray(dm,Xloc,&x);
    115:   DMRestoreLocalVector(dm,&Xloc);
    116:   return(0);
    117: }

    121: /*
    122:   This function should eventually replace:
    123:     DMDAComputeFunction() and DMDAComputeFunction1()
    124:  */
    125: static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx)
    126: {
    128:   DM             dm;
    129:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    130:   DMDALocalInfo  info;
    131:   Vec            Xloc;
    132:   void           *x;

    138:   if (!dmdasnes->objectivelocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
    139:   SNESGetDM(snes,&dm);
    140:   DMGetLocalVector(dm,&Xloc);
    141:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    142:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    143:   DMDAGetLocalInfo(dm,&info);
    144:   DMDAVecGetArray(dm,Xloc,&x);
    145:   CHKMEMQ;
    146:   (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);
    147:   CHKMEMQ;
    148:   DMDAVecRestoreArray(dm,Xloc,&x);
    149:   DMRestoreLocalVector(dm,&Xloc);
    150:   return(0);
    151: }

    156: static PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx)
    157: {
    159:   DM             dm;
    160:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    161:   DMDALocalInfo  info;
    162:   Vec            Xloc;
    163:   void           *x;

    166:   if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
    167:   SNESGetDM(snes,&dm);

    169:   if (dmdasnes->jacobianlocal) {
    170:     DMGetLocalVector(dm,&Xloc);
    171:     DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    172:     DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    173:     DMDAGetLocalInfo(dm,&info);
    174:     DMDAVecGetArray(dm,Xloc,&x);
    175:     CHKMEMQ;
    176:     (*dmdasnes->jacobianlocal)(&info,x,*A,*B,mstr,dmdasnes->jacobianlocalctx);
    177:     CHKMEMQ;
    178:     DMDAVecRestoreArray(dm,Xloc,&x);
    179:     DMRestoreLocalVector(dm,&Xloc);
    180:   } else {
    181:     MatFDColoring fdcoloring;
    182:     PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);
    183:     if (!fdcoloring) {
    184:       ISColoring coloring;

    186:       DMCreateColoring(dm,dm->coloringtype,dm->mattype,&coloring);
    187:       MatFDColoringCreate(*B,coloring,&fdcoloring);
    188:       ISColoringDestroy(&coloring);
    189:       switch (dm->coloringtype) {
    190:       case IS_COLORING_GLOBAL:
    191:         MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))SNESComputeFunction_DMDA,dmdasnes);
    192:         break;
    193:       default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]);
    194:       }
    195:       PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);
    196:       MatFDColoringSetFromOptions(fdcoloring);
    197:       PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);
    198:       PetscObjectDereference((PetscObject)fdcoloring);

    200:       /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
    201:        * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
    202:        * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
    203:        * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
    204:        * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
    205:        */
    206:       PetscObjectDereference((PetscObject)dm);
    207:     }
    208:     *mstr = SAME_NONZERO_PATTERN;
    209:     MatFDColoringApply(*B,fdcoloring,X,mstr,snes);
    210:   }
    211:   /* This will be redundant if the user called both, but it's too common to forget. */
    212:   if (*A != *B) {
    213:     MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);
    214:     MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);
    215:   }
    216:   return(0);
    217: }

    221: /*@C
    222:    DMDASNESSetFunctionLocal - set a local residual evaluation function

    224:    Logically Collective

    226:    Input Arguments:
    227: +  dm - DM to associate callback with
    228: .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
    229: .  func - local residual evaluation
    230: -  ctx - optional context for local residual evaluation

    232:    Calling sequence for func:
    233: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    234: .  x - dimensional pointer to state at which to evaluate residual
    235: .  f - dimensional pointer to residual, write the residual here
    236: -  ctx - optional context passed above

    238:    Level: beginner

    240: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    241: @*/
    242: PetscErrorCode DMDASNESSetFunctionLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),void *ctx)
    243: {
    245:   DMSNES         sdm;
    246:   DMSNES_DA      *dmdasnes;

    250:   DMGetDMSNESWrite(dm,&sdm);
    251:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    253:   dmdasnes->residuallocalimode = imode;
    254:   dmdasnes->residuallocal      = func;
    255:   dmdasnes->residuallocalctx   = ctx;

    257:   DMSNESSetFunction(dm,SNESComputeFunction_DMDA,dmdasnes);
    258:   if (!sdm->ops->computejacobian) {  /* Call us for the Jacobian too, can be overridden by the user. */
    259:     DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
    260:   }
    261:   return(0);
    262: }

    266: /*@C
    267:    DMDASNESSetJacobianLocal - set a local residual evaluation function

    269:    Logically Collective

    271:    Input Arguments:
    272: +  dm - DM to associate callback with
    273: .  func - local residual evaluation
    274: -  ctx - optional context for local residual evaluation

    276:    Calling sequence for func:
    277: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    278: .  x - dimensional pointer to state at which to evaluate residual
    279: .  f - dimensional pointer to residual, write the residual here
    280: -  ctx - optional context passed above

    282:    Level: beginner

    284: .seealso: DMSNESSetJacobian(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    285: @*/
    286: PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx)
    287: {
    289:   DMSNES         sdm;
    290:   DMSNES_DA      *dmdasnes;

    294:   DMGetDMSNESWrite(dm,&sdm);
    295:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    297:   dmdasnes->jacobianlocal    = func;
    298:   dmdasnes->jacobianlocalctx = ctx;

    300:   DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
    301:   return(0);
    302: }

    307: /*@C
    308:    DMDASNESSetObjectiveLocal - set a local residual evaluation function

    310:    Logically Collective

    312:    Input Arguments:
    313: +  dm - DM to associate callback with
    314: .  func - local objective evaluation
    315: -  ctx - optional context for local residual evaluation

    317:    Calling sequence for func:
    318: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    319: .  x - dimensional pointer to state at which to evaluate residual
    320: .  ob - eventual objective value
    321: -  ctx - optional context passed above

    323:    Level: beginner

    325: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    326: @*/
    327: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx)
    328: {
    330:   DMSNES         sdm;
    331:   DMSNES_DA      *dmdasnes;

    335:   DMGetDMSNESWrite(dm,&sdm);
    336:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    338:   dmdasnes->objectivelocal    = func;
    339:   dmdasnes->objectivelocalctx = ctx;

    341:   DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);
    342:   return(0);
    343: }

    347: static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx)
    348: {
    350:   DM             dm;
    351:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    352:   DMDALocalInfo  info;
    353:   Vec            Xloc;
    354:   void           *x,*f;

    360:   if (!dmdasnes->rhsplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
    361:   SNESGetDM(snes,&dm);
    362:   DMGetLocalVector(dm,&Xloc);
    363:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    364:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    365:   DMDAGetLocalInfo(dm,&info);
    366:   DMDAVecGetArray(dm,Xloc,&x);
    367:   switch (dmdasnes->residuallocalimode) {
    368:   case INSERT_VALUES: {
    369:     DMDAVecGetArray(dm,F,&f);
    370:     CHKMEMQ;
    371:     (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
    372:     CHKMEMQ;
    373:     DMDAVecRestoreArray(dm,F,&f);
    374:   } break;
    375:   case ADD_VALUES: {
    376:     Vec Floc;
    377:     DMGetLocalVector(dm,&Floc);
    378:     VecZeroEntries(Floc);
    379:     DMDAVecGetArray(dm,Floc,&f);
    380:     CHKMEMQ;
    381:     (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
    382:     CHKMEMQ;
    383:     DMDAVecRestoreArray(dm,Floc,&f);
    384:     VecZeroEntries(F);
    385:     DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
    386:     DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
    387:     DMRestoreLocalVector(dm,&Floc);
    388:   } break;
    389:   default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
    390:   }
    391:   DMDAVecRestoreArray(dm,Xloc,&x);
    392:   DMRestoreLocalVector(dm,&Xloc);
    393:   return(0);
    394: }

    398: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx)
    399: {
    401:   DM             dm;
    402:   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
    403:   DMDALocalInfo  info;
    404:   Vec            Xloc;
    405:   void           *x;

    408:   if (!dmdasnes->jacobianplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
    409:   SNESGetDM(snes,&dm);

    411:   DMGetLocalVector(dm,&Xloc);
    412:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    413:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    414:   DMDAGetLocalInfo(dm,&info);
    415:   DMDAVecGetArray(dm,Xloc,&x);
    416:   CHKMEMQ;
    417:   (*dmdasnes->jacobianplocal)(&info,x,*A,*B,mstr,dmdasnes->picardlocalctx);
    418:   CHKMEMQ;
    419:   DMDAVecRestoreArray(dm,Xloc,&x);
    420:   DMRestoreLocalVector(dm,&Xloc);
    421:   *mstr = SAME_NONZERO_PATTERN;
    422:   if (*A != *B) {
    423:     MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);
    424:     MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);
    425:   }
    426:   return(0);
    427: }

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

    434:    Logically Collective

    436:    Input Arguments:
    437: +  dm - DM to associate callback with
    438: .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
    439: .  func - local residual evaluation
    440: -  ctx - optional context for local residual evaluation

    442:    Calling sequence for func:
    443: +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
    444: .  x - dimensional pointer to state at which to evaluate residual
    445: .  f - dimensional pointer to residual, write the residual here
    446: -  ctx - optional context passed above

    448:    Notes:  The user must use
    449:     extern PetscErrorCode  SNESPicardComputeFunction(SNES,Vec,Vec,void*);
    450:     extern PetscErrorCode  SNESPicardComputeJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
    451:     SNESSetFunction(snes,NULL,SNESPicardComputeFunction,&user);
    452:     in their code before calling this routine.

    455:    Level: beginner

    457: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
    458: @*/
    459: PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),
    460:                                       PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx)
    461: {
    463:   DMSNES         sdm;
    464:   DMSNES_DA      *dmdasnes;

    468:   DMGetDMSNESWrite(dm,&sdm);
    469:   DMDASNESGetContext(dm,sdm,&dmdasnes);

    471:   dmdasnes->residuallocalimode = imode;
    472:   dmdasnes->rhsplocal          = func;
    473:   dmdasnes->jacobianplocal     = jac;
    474:   dmdasnes->picardlocalctx     = ctx;

    476:   DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);
    477:   return(0);
    478: }