Actual source code: ex6.c

      1: static const char help[] = "Simple 2D or 3D finite difference seismic wave propagation, using\n"
      2: "a staggered grid represented with DMStag objects.\n"
      3: "-dim <2,3>  : dimension of problem\n"
      4: "-nsteps <n> : number of timesteps\n"
      5: "-dt <dt>    : length of timestep\n"
      6: "\n";

      8: /*
      9: Reference:

     11: @article{Virieux1986,
     12:   title     = {{P-SV} Wave Propagation in Heterogeneous Media: {V}elocity-Stress Finite-Difference Method},
     13:   author    = {Virieux, Jean},
     14:   journal   = {Geophysics},
     15:   volume    = {51},
     16:   number    = {4},
     17:   pages     = {889--901},
     18:   publisher = {Society of Exploration Geophysicists},
     19:   year      = {1986},
     20: }

     22: Notes:

     24:   This example uses y in 2 dimensions, where the paper uses z.
     25:   This example uses the dual grid of the one pictured in Fig. 1. of the paper,
     26: so that velocities are on face boundaries, shear stresses are defined on vertices,
     27: and normal stresses are defined on elements.
     28:   There is a typo in the paragraph after (5) in the paper: Sigma, Xi, and Tau
     29: represent tau_xx, tau_xz, and tau_zz, respectively (the last two entries are
     30: transposed in the paper).
     31:   This example treats the boundaries naively (by leaving ~zero velocity and stress there).

     33: */

     35: #include <petscdmstag.h>
     36: #include <petscts.h>

     38: /* A struct defining the parameters of the problem */
     39: typedef struct {
     40:   DM          dm_velocity,dm_stress;
     41:   DM          dm_buoyancy,dm_lame;
     42:   Vec         buoyancy,lame; /* Global, but for efficiency one could store local vectors */
     43:   PetscInt    dim; /* 2 or 3 */
     44:   PetscScalar rho,lambda,mu; /* constant material properties */
     45:   PetscReal   xmin,xmax,ymin,ymax,zmin,zmax;
     46:   PetscReal   dt;
     47:   PetscInt    timesteps;
     48:   PetscBool   dump_output;
     49: } Ctx;

     51: static PetscErrorCode CreateLame(Ctx*);
     52: static PetscErrorCode ForceStress(const Ctx*,Vec,PetscReal);
     53: static PetscErrorCode DumpVelocity(const Ctx*,Vec,PetscInt);
     54: static PetscErrorCode DumpStress(const Ctx*,Vec,PetscInt);
     55: static PetscErrorCode UpdateVelocity(const Ctx*,Vec,Vec,Vec);
     56: static PetscErrorCode UpdateStress(const Ctx*,Vec,Vec,Vec);

     58: int main(int argc,char *argv[])
     59: {
     60:   Ctx            ctx;
     61:   Vec            velocity,stress;
     62:   PetscInt       timestep;

     64:   /* Initialize PETSc */
     65:   PetscInitialize(&argc,&argv,0,help);

     67:   /* Populate application context */
     68:   ctx.dim         = 2;
     69:   ctx.rho         = 1.0;
     70:   ctx.lambda      = 1.0;
     71:   ctx.mu          = 1.0;
     72:   ctx.xmin        = 0.0; ctx.xmax = 1.0;
     73:   ctx.ymin        = 0.0; ctx.ymax = 1.0;
     74:   ctx.zmin        = 0.0; ctx.zmax = 1.0;
     75:   ctx.dt          = 0.001;
     76:   ctx.timesteps   = 100;
     77:   ctx.dump_output = PETSC_TRUE;

     79:   /* Update context from command line options */
     80:   PetscOptionsGetInt(NULL,NULL,"-dim",&ctx.dim,NULL);
     81:   PetscOptionsGetReal(NULL,NULL,"-dt",&ctx.dt,NULL);
     82:   PetscOptionsGetInt(NULL,NULL,"-nsteps",&ctx.timesteps,NULL);
     83:   PetscOptionsGetBool(NULL,NULL,"-dump_output",&ctx.dump_output,NULL);

     85:   /* Create a DMStag, with uniform coordinates, for the velocities */
     86:   {
     87:     PetscInt dof0,dof1,dof2,dof3;
     88:     const PetscInt stencilWidth = 1;

     90:     switch (ctx.dim) {
     91:       case 2:
     92:         dof0 = 0; dof1 = 1; dof2 = 0; /* 1 dof per cell boundary */
     93:         DMStagCreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE,100,100,PETSC_DECIDE,PETSC_DECIDE,dof0,dof1,dof2,DMSTAG_STENCIL_BOX,stencilWidth,NULL,NULL,&ctx.dm_velocity);
     94:         break;
     95:       case 3:
     96:         dof0 = 0; dof1 = 0; dof2 = 1; dof3 = 0; /* 1 dof per cell boundary */
     97:         DMStagCreate3d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE,30,30,30,PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE,dof0,dof1,dof2,dof3,DMSTAG_STENCIL_BOX,stencilWidth,NULL,NULL,NULL,&ctx.dm_velocity);
     98:         break;
     99:       default: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not Implemented for dimension %D",ctx.dim);
    100:     }
    101:   }
    102:   DMSetFromOptions(ctx.dm_velocity); /* Options control velocity DM */
    103:   DMSetUp(ctx.dm_velocity);
    104:   DMStagSetUniformCoordinatesProduct(ctx.dm_velocity,ctx.xmin,ctx.xmax,ctx.ymin,ctx.ymax,ctx.zmin,ctx.zmax);

    106:   /* Create a second, compatible DMStag for the stresses */
    107:   switch (ctx.dim) {
    108:     case 2:
    109:       /* One shear stress component on element corners, two shear stress components on elements */
    110:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,1,0,2,0,&ctx.dm_stress);
    111:       break;
    112:     case 3:
    113:       /* One shear stress component on element edges, three shear stress components on elements */
    114:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,0,1,0,3,&ctx.dm_stress);
    115:       break;
    116:     default: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not Implemented for dimension %D",ctx.dim);
    117:   }
    118:   DMSetUp(ctx.dm_stress);
    119:   DMStagSetUniformCoordinatesProduct(ctx.dm_stress,ctx.xmin,ctx.xmax,ctx.ymin,ctx.ymax,ctx.zmin,ctx.zmax);

    121:   /* Create two additional DMStag objects for the buoyancy and Lame parameters */
    122:   switch (ctx.dim) {
    123:     case 2:
    124:       /* buoyancy on element boundaries (edges) */
    125:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,0,1,0,0,&ctx.dm_buoyancy);
    126:       break;
    127:     case 3:
    128:       /* buoyancy on element boundaries (faces) */
    129:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,0,0,1,0,&ctx.dm_buoyancy);
    130:       break;
    131:     default: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not Implemented for dimension %D",ctx.dim);
    132:   }
    133:   DMSetUp(ctx.dm_buoyancy);

    135:   switch (ctx.dim) {
    136:     case 2:
    137:       /* mu and lambda + 2*mu on element centers, mu on corners */
    138:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,1,0,2,0,&ctx.dm_lame);
    139:       break;
    140:     case 3:
    141:       /* mu and lambda + 2*mu on element centers, mu on edges */
    142:       DMStagCreateCompatibleDMStag(ctx.dm_velocity,0,1,0,2,&ctx.dm_lame);
    143:       break;
    144:     default: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not Implemented for dimension %D",ctx.dim);
    145:   }
    146:   DMSetUp(ctx.dm_lame);

    148:   /* Print out some info */
    149:   {
    150:     PetscInt    N[3];
    151:     PetscScalar dx,Vp;

    153:     DMStagGetGlobalSizes(ctx.dm_velocity,&N[0],&N[1],&N[2]);
    154:     dx = (ctx.xmax - ctx.xmin)/N[0];
    155:     Vp = PetscSqrtScalar((ctx.lambda + 2 * ctx.mu) / ctx.rho);
    156:     if (ctx.dim == 2) {
    157:       PetscPrintf(PETSC_COMM_WORLD,"Using a %D x %D mesh\n",N[0],N[1]);
    158:     } else if (ctx.dim == 3) {
    159:       PetscPrintf(PETSC_COMM_WORLD,"Using a %D x %D x %D mesh\n",N[0],N[1],N[2]);
    160:     }
    161:     PetscPrintf(PETSC_COMM_WORLD,"dx: %g\n",dx);
    162:     PetscPrintf(PETSC_COMM_WORLD,"dt: %g\n",ctx.dt);
    163:     PetscPrintf(PETSC_COMM_WORLD,"P-wave velocity: %g\n",PetscSqrtScalar((ctx.lambda + 2 * ctx.mu) / ctx.rho));
    164:     PetscPrintf(PETSC_COMM_WORLD,"V_p dt / dx: %g\n",Vp * ctx.dt / dx);
    165:   }

    167:   /* Populate the coefficient arrays */
    168:   CreateLame(&ctx);
    169:   DMCreateGlobalVector(ctx.dm_buoyancy,&ctx.buoyancy);
    170:   VecSet(ctx.buoyancy,1.0/ctx.rho);

    172:   /* Create vectors to store the system state */
    173:   DMCreateGlobalVector(ctx.dm_velocity,&velocity);
    174:   DMCreateGlobalVector(ctx.dm_stress,&stress);

    176:   /* Initial State */
    177:   VecSet(velocity,0.0);
    178:   VecSet(stress,0.0);
    179:   ForceStress(&ctx,stress,0.0);
    180:   if (ctx.dump_output) {
    181:     DumpVelocity(&ctx,velocity,0);
    182:     DumpStress(&ctx,stress,0);
    183:   }

    185:   /* Time Loop */
    186:   for (timestep = 1; timestep <= ctx.timesteps; ++timestep) {
    187:     const PetscReal t = timestep * ctx.dt;

    189:     UpdateVelocity(&ctx,velocity,stress,ctx.buoyancy);
    190:     UpdateStress(&ctx,velocity,stress,ctx.lame);
    191:     ForceStress(&ctx,stress,t);
    192:     PetscPrintf(PETSC_COMM_WORLD,"Timestep %d, t = %g\n",timestep,(double)t);
    193:     if (ctx.dump_output) {
    194:       DumpVelocity(&ctx,velocity,timestep);
    195:       DumpStress(&ctx,stress,timestep);
    196:     }
    197:   }

    199:   /* Clean up and finalize PETSc */
    200:   VecDestroy(&velocity);
    201:   VecDestroy(&stress);
    202:   VecDestroy(&ctx.lame);
    203:   VecDestroy(&ctx.buoyancy);
    204:   DMDestroy(&ctx.dm_velocity);
    205:   DMDestroy(&ctx.dm_stress);
    206:   DMDestroy(&ctx.dm_buoyancy);
    207:   DMDestroy(&ctx.dm_lame);
    208:   PetscFinalize();
    209:   return 0;
    210: }

    212: static PetscErrorCode CreateLame(Ctx *ctx)
    213: {
    214:   PetscInt       N[3],ex,ey,ez,startx,starty,startz,nx,ny,nz,extrax,extray,extraz;

    217:   DMCreateGlobalVector(ctx->dm_lame,&ctx->lame);
    218:   DMStagGetGlobalSizes(ctx->dm_lame,&N[0],&N[1],&N[2]);
    219:   DMStagGetCorners(ctx->dm_buoyancy,&startx,&starty,&startz,&nx,&ny,&nz,&extrax,&extray,&extraz);
    220:   if (ctx->dim == 2) {
    221:     /* Element values */
    222:     for (ey=starty; ey<starty+ny; ++ey) {
    223:       for (ex=startx; ex<startx+nx; ++ex) {
    224:         DMStagStencil pos;

    226:         pos.i = ex; pos.j = ey; pos.c = 0; pos.loc = DMSTAG_ELEMENT;
    227:         DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->lambda,INSERT_VALUES);
    228:         pos.i = ex; pos.j = ey; pos.c = 1; pos.loc = DMSTAG_ELEMENT;
    229:         DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    230:       }
    231:     }
    232:     /* Vertex Values */
    233:     for (ey=starty; ey<starty+ny+extray; ++ey) {
    234:       for (ex=startx; ex<startx+nx+extrax; ++ex) {
    235:         DMStagStencil pos;

    237:         pos.i = ex; pos.j = ey; pos.c = 0; pos.loc = DMSTAG_DOWN_LEFT;
    238:         DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    239:       }
    240:     }
    241:   } else if (ctx->dim == 3) {
    242:     /* Element values */
    243:     for (ez=startz; ez<startz+nz; ++ez) {
    244:       for (ey=starty; ey<starty+ny; ++ey) {
    245:         for (ex=startx; ex<startx+nx; ++ex) {
    246:         DMStagStencil pos;

    248:         pos.i = ex; pos.j = ey; pos.k = ez; pos.c = 0; pos.loc = DMSTAG_ELEMENT;
    249:         DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->lambda,INSERT_VALUES);
    250:         pos.i = ex; pos.j = ey; pos.k = ez; pos.c = 1; pos.loc = DMSTAG_ELEMENT;
    251:         DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    252:         }
    253:       }
    254:     }
    255:     /* Edge Values */
    256:     for (ez=startz; ez<startz+nz+extraz; ++ez) {
    257:       for (ey=starty; ey<starty+ny+extray; ++ey) {
    258:         for (ex=startx; ex<startx+nx+extrax; ++ex) {
    259:           DMStagStencil   pos;

    261:           if (ex < N[0]) {
    262:             pos.i = ex; pos.j = ey; pos.k = ez; pos.c = 0; pos.loc = DMSTAG_BACK_DOWN;
    263:             DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    264:           }
    265:           if (ey < N[1]) {
    266:             pos.i = ex; pos.j = ey; pos.k = ez; pos.c = 0; pos.loc = DMSTAG_BACK_LEFT;
    267:             DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    268:           }
    269:           if (ez < N[2]) {
    270:             pos.i = ex; pos.j = ey; pos.k = ez; pos.c = 0; pos.loc = DMSTAG_DOWN_LEFT;
    271:             DMStagVecSetValuesStencil(ctx->dm_lame,ctx->lame,1,&pos,&ctx->mu,INSERT_VALUES);
    272:           }
    273:         }
    274:       }
    275:     }
    276:   } else SETERRQ(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
    277:   VecAssemblyBegin(ctx->lame);
    278:   VecAssemblyEnd(ctx->lame);
    279:   return 0;
    280: }

    282: static PetscErrorCode ForceStress(const Ctx *ctx,Vec stress, PetscReal t)
    283: {
    284:   PetscInt          start[3],n[3],N[3];
    285:   DMStagStencil     pos;
    286:   PetscBool         this_rank;
    287:   const PetscScalar val = PetscExpReal(-100.0 * t);

    290:   DMStagGetGlobalSizes(ctx->dm_stress,&N[0],&N[1],&N[2]);
    291:   DMStagGetCorners(ctx->dm_stress,&start[0],&start[1],&start[2],&n[0],&n[1],&n[2],NULL,NULL,NULL);

    293:   /* Normal stresses at a single point */
    294:   this_rank = (PetscBool) (start[0] <= N[0]/2 && N[0]/2 <= start[0] + n[0]);
    295:   this_rank = (PetscBool) (this_rank && start[1] <= N[1]/2 && N[1]/2 <= start[1] + n[1]);
    296:   if (ctx->dim == 3) this_rank = (PetscBool) (this_rank && start[2] <= N[2]/2 && N[2]/2 <= start[2] + n[2]);
    297:   if (this_rank) {
    298:     /* Note integer division to pick element near the center */
    299:     pos.i = N[0]/2; pos.j = N[1]/2; pos.k = N[2]/2; pos.c = 0; pos.loc = DMSTAG_ELEMENT;
    300:     DMStagVecSetValuesStencil(ctx->dm_stress,stress,1,&pos,&val,INSERT_VALUES);
    301:     pos.i = N[0]/2; pos.j = N[1]/2; pos.k = N[2]/2; pos.c = 1; pos.loc = DMSTAG_ELEMENT;
    302:     DMStagVecSetValuesStencil(ctx->dm_stress,stress,1,&pos,&val,INSERT_VALUES);
    303:     if (ctx->dim == 3) {
    304:       pos.i = N[0]/2; pos.j = N[1]/2; pos.k = N[2]/2; pos.c = 2; pos.loc = DMSTAG_ELEMENT;
    305:       DMStagVecSetValuesStencil(ctx->dm_stress,stress,1,&pos,&val,INSERT_VALUES);
    306:     }
    307:   }

    309:   VecAssemblyBegin(stress);
    310:   VecAssemblyEnd(stress);
    311:   return 0;
    312: }

    314: static PetscErrorCode UpdateVelocity_2d(const Ctx *ctx,Vec velocity,Vec stress, Vec buoyancy)
    315: {
    316:   Vec               velocity_local,stress_local,buoyancy_local;
    317:   PetscInt          ex,ey,startx,starty,nx,ny;
    318:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
    319:   PetscInt          slot_vx_left,slot_vy_down,slot_buoyancy_down,slot_buoyancy_left;
    320:   PetscInt          slot_txx,slot_tyy,slot_txy_downleft,slot_txy_downright,slot_txy_upleft;
    321:   const PetscScalar **arr_coord_x,**arr_coord_y;
    322:   const PetscScalar ***arr_stress,***arr_buoyancy;
    323:   PetscScalar       ***arr_velocity;

    327:   /* Prepare direct access to buoyancy data */
    328:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_LEFT,0,&slot_buoyancy_left);
    329:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_DOWN,0,&slot_buoyancy_down);
    330:   DMGetLocalVector(ctx->dm_buoyancy,&buoyancy_local);
    331:   DMGlobalToLocal(ctx->dm_buoyancy,buoyancy,INSERT_VALUES,buoyancy_local);
    332:   DMStagVecGetArrayRead(ctx->dm_buoyancy,buoyancy_local,&arr_buoyancy);

    334:   /* Prepare read-only access to stress data */
    335:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,   0,&slot_txx);
    336:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,   1,&slot_tyy);
    337:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_UP_LEFT,   0,&slot_txy_upleft);
    338:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT, 0,&slot_txy_downleft);
    339:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_RIGHT,0,&slot_txy_downright);
    340:   DMGetLocalVector(ctx->dm_stress,&stress_local);
    341:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
    342:   DMStagVecGetArrayRead(ctx->dm_stress,stress_local,&arr_stress);

    344:   /* Prepare read-write access to velocity data */
    345:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,0,&slot_vx_left);
    346:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN,0,&slot_vy_down);
    347:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
    348:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
    349:   DMStagVecGetArray(ctx->dm_velocity,velocity_local,&arr_velocity);

    351:   /* Prepare read-only access to coordinate data */
    352:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
    353:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
    354:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
    355:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);

    357:   /* Iterate over interior of the domain, updating the velocities */
    358:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,NULL,&nx,&ny,NULL,NULL,NULL,NULL);
    359:   for (ey = starty; ey < starty + ny; ++ey) {
    360:     for (ex = startx; ex < startx + nx; ++ex) {

    362:       /* Update y-velocity */
    363:       if (ey > 0) {
    364:         const PetscScalar dx = arr_coord_x[ex][slot_coord_next]    - arr_coord_x[ex  ][slot_coord_prev];
    365:         const PetscScalar dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
    366:         const PetscScalar B = arr_buoyancy[ey][ex][slot_buoyancy_down];

    368:         arr_velocity[ey][ex][slot_vy_down] += B * ctx->dt * (
    369:               (arr_stress[ey][ex][slot_txy_downright] - arr_stress[ey  ][ex][slot_txy_downleft]) / dx
    370:             + (arr_stress[ey][ex][slot_tyy]           - arr_stress[ey-1][ex][slot_tyy]) / dy);
    371:       }

    373:       /* Update x-velocity */
    374:       if (ex > 0) {
    375:         const PetscScalar dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
    376:         const PetscScalar dy = arr_coord_y[ey][slot_coord_next]    - arr_coord_y[ey  ][slot_coord_prev];
    377:         const PetscScalar B = arr_buoyancy[ey][ex][slot_buoyancy_left];

    379:         arr_velocity[ey][ex][slot_vx_left] += B * ctx->dt * (
    380:               (arr_stress[ey][ex][slot_txx]        - arr_stress[ey][ex-1][slot_txx]) / dx
    381:             + (arr_stress[ey][ex][slot_txy_upleft] - arr_stress[ey][ex  ][slot_txy_downleft]) / dy);
    382:       }
    383:     }
    384:   }

    386:   /* Restore all access */
    387:   DMStagVecRestoreArrayRead(ctx->dm_buoyancy,buoyancy_local,&arr_buoyancy);
    388:   DMRestoreLocalVector(ctx->dm_buoyancy,&buoyancy_local);
    389:   DMStagVecRestoreArrayRead(ctx->dm_stress,stress_local,&arr_stress);
    390:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
    391:   DMStagVecRestoreArray(ctx->dm_velocity,velocity_local,&arr_velocity);
    392:   DMLocalToGlobal(ctx->dm_velocity,velocity_local,INSERT_VALUES,velocity);
    393:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
    394:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);
    395:   return 0;
    396: }

    398: static PetscErrorCode UpdateVelocity_3d(const Ctx *ctx,Vec velocity,Vec stress, Vec buoyancy)
    399: {
    400:   Vec               velocity_local,stress_local,buoyancy_local;
    401:   PetscInt          ex,ey,ez,startx,starty,startz,nx,ny,nz;
    402:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
    403:   PetscInt          slot_vx_left,slot_vy_down,slot_vz_back,slot_buoyancy_down,slot_buoyancy_left,slot_buoyancy_back;
    404:   PetscInt          slot_txx,slot_tyy,slot_tzz;
    405:   PetscInt          slot_txy_downleft,slot_txy_downright,slot_txy_upleft;
    406:   PetscInt          slot_txz_backleft,slot_txz_backright,slot_txz_frontleft;
    407:   PetscInt          slot_tyz_backdown,slot_tyz_frontdown,slot_tyz_backup;
    408:   const PetscScalar **arr_coord_x,**arr_coord_y,**arr_coord_z;
    409:   const PetscScalar ****arr_stress,****arr_buoyancy;
    410:   PetscScalar       ****arr_velocity;

    414:   /* Prepare direct access to buoyancy data */
    415:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_LEFT,0,&slot_buoyancy_left);
    416:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_DOWN,0,&slot_buoyancy_down);
    417:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_BACK,0,&slot_buoyancy_back);
    418:   DMGetLocalVector(ctx->dm_buoyancy,&buoyancy_local);
    419:   DMGlobalToLocal(ctx->dm_buoyancy,buoyancy,INSERT_VALUES,buoyancy_local);
    420:   DMStagVecGetArrayRead(ctx->dm_buoyancy,buoyancy_local,&arr_buoyancy);

    422:   /* Prepare read-only access to stress data */
    423:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,   0,&slot_txx);
    424:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,   1,&slot_tyy);
    425:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,   2,&slot_tzz);
    426:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_UP_LEFT,   0,&slot_txy_upleft);
    427:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT, 0,&slot_txy_downleft);
    428:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_RIGHT,0,&slot_txy_downright);
    429:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_LEFT, 0,&slot_txz_backleft);
    430:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_RIGHT,0,&slot_txz_backright);
    431:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_FRONT_LEFT,0,&slot_txz_frontleft);
    432:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_DOWN, 0,&slot_tyz_backdown);
    433:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_UP,   0,&slot_tyz_backup);
    434:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_FRONT_DOWN,0,&slot_tyz_frontdown);
    435:   DMGetLocalVector(ctx->dm_stress,&stress_local);
    436:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
    437:   DMStagVecGetArrayRead(ctx->dm_stress,stress_local,&arr_stress);

    439:   /* Prepare read-write access to velocity data */
    440:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,0,&slot_vx_left);
    441:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN,0,&slot_vy_down);
    442:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_BACK,0,&slot_vz_back);
    443:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
    444:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
    445:   DMStagVecGetArray(ctx->dm_velocity,velocity_local,&arr_velocity);

    447:   /* Prepare read-only access to coordinate data */
    448:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
    449:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
    450:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
    451:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);

    453:   /* Iterate over interior of the domain, updating the velocities */
    454:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
    455:   for (ez = startz; ez < startz + nz; ++ez) {
    456:     for (ey = starty; ey < starty + ny; ++ey) {
    457:       for (ex = startx; ex < startx + nx; ++ex) {

    459:         /* Update y-velocity */
    460:         if (ey > 0) {
    461:           const PetscScalar dx = arr_coord_x[ex][slot_coord_next]    - arr_coord_x[ex  ][slot_coord_prev];
    462:           const PetscScalar dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
    463:           const PetscScalar dz = arr_coord_z[ez][slot_coord_next]    - arr_coord_z[ez  ][slot_coord_prev];
    464:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_down];

    466:           arr_velocity[ez][ey][ex][slot_vy_down] += B * ctx->dt * (
    467:                 (arr_stress[ez][ey][ex][slot_txy_downright] - arr_stress[ez][ey  ][ex][slot_txy_downleft]) / dx
    468:               + (arr_stress[ez][ey][ex][slot_tyy]           - arr_stress[ez][ey-1][ex][slot_tyy]) / dy
    469:               + (arr_stress[ez][ey][ex][slot_tyz_frontdown] - arr_stress[ez][ey  ][ex][slot_tyz_backdown]) / dz);
    470:         }

    472:         /* Update x-velocity */
    473:         if (ex > 0) {
    474:           const PetscScalar dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
    475:           const PetscScalar dy = arr_coord_y[ey][slot_coord_next]    - arr_coord_y[ey  ][slot_coord_prev];
    476:           const PetscScalar dz = arr_coord_z[ez][slot_coord_next]    - arr_coord_z[ez  ][slot_coord_prev];
    477:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_left];

    479:           arr_velocity[ez][ey][ex][slot_vx_left] += B * ctx->dt * (
    480:                 (arr_stress[ez][ey][ex][slot_txx]           - arr_stress[ez][ey][ex-1][slot_txx]) / dx
    481:               + (arr_stress[ez][ey][ex][slot_txy_upleft]    - arr_stress[ez][ey][ex  ][slot_txy_downleft]) / dy
    482:               + (arr_stress[ez][ey][ex][slot_txz_frontleft] - arr_stress[ez][ey][ex  ][slot_txz_backleft]) / dz);
    483:         }

    485:         /* Update z-velocity */
    486:         if (ez > 0) {
    487:           const PetscScalar dx = arr_coord_x[ex][slot_coord_next]    - arr_coord_x[ex  ][slot_coord_prev];
    488:           const PetscScalar dy = arr_coord_y[ey][slot_coord_next]    - arr_coord_y[ey  ][slot_coord_prev];
    489:           const PetscScalar dz = arr_coord_z[ez][slot_coord_element] - arr_coord_z[ez-1][slot_coord_element];
    490:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_back];

    492:           arr_velocity[ez][ey][ex][slot_vz_back] += B * ctx->dt * (
    493:               (arr_stress[ez][ey][ex][slot_txz_backright] - arr_stress[ez  ][ey][ex][slot_txz_backleft]) / dx
    494:             + (arr_stress[ez][ey][ex][slot_tyz_backup]    - arr_stress[ez  ][ey][ex][slot_tyz_backdown]) / dy
    495:             + (arr_stress[ez][ey][ex][slot_tzz]           - arr_stress[ez-1][ey][ex][slot_tzz]) / dz);
    496:         }
    497:       }
    498:     }
    499:   }

    501:   /* Restore all access */
    502:   DMStagVecRestoreArrayRead(ctx->dm_buoyancy,buoyancy_local,&arr_buoyancy);
    503:   DMRestoreLocalVector(ctx->dm_buoyancy,&buoyancy_local);
    504:   DMStagVecRestoreArrayRead(ctx->dm_stress,stress_local,&arr_stress);
    505:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
    506:   DMStagVecRestoreArray(ctx->dm_velocity,velocity_local,&arr_velocity);
    507:   DMLocalToGlobal(ctx->dm_velocity,velocity_local,INSERT_VALUES,velocity);
    508:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
    509:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);
    510:   return 0;
    511: }

    513: static PetscErrorCode UpdateVelocity(const Ctx *ctx,Vec velocity,Vec stress, Vec buoyancy)
    514: {
    516:   if (ctx->dim == 2) {
    517:     UpdateVelocity_2d(ctx,velocity,stress,buoyancy);
    518:   } else if (ctx->dim == 3) {
    519:     UpdateVelocity_3d(ctx,velocity,stress,buoyancy);
    520:   } else SETERRQ(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
    521:   return 0;
    522: }

    524: static PetscErrorCode UpdateStress_2d(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
    525: {
    526:   Vec               velocity_local,stress_local,lame_local;
    527:   PetscInt          ex,ey,startx,starty,nx,ny;
    528:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
    529:   PetscInt          slot_vx_left,slot_vy_down,slot_vx_right,slot_vy_up;
    530:   PetscInt          slot_mu_element,slot_lambda_element,slot_mu_downleft;
    531:   PetscInt          slot_txx,slot_tyy,slot_txy_downleft;
    532:   const PetscScalar **arr_coord_x,**arr_coord_y;
    533:   const PetscScalar ***arr_velocity,***arr_lame;
    534:   PetscScalar       ***arr_stress;

    538:   /* Prepare read-write access to stress data */
    539:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,0,&slot_txx);
    540:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,1,&slot_tyy);
    541:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT,0,&slot_txy_downleft);
    542:   DMGetLocalVector(ctx->dm_stress,&stress_local);
    543:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
    544:   DMStagVecGetArray(ctx->dm_stress,stress_local,&arr_stress);

    546:   /* Prepare read-only access to velocity data */
    547:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,0,&slot_vx_left);
    548:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,0,&slot_vx_right);
    549:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN,0,&slot_vy_down);
    550:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_UP,0,&slot_vy_up);
    551:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
    552:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
    553:   DMStagVecGetArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);

    555:   /* Prepare read-only access to Lame' data */
    556:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,0,&slot_lambda_element);
    557:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,1,&slot_mu_element);
    558:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_DOWN_LEFT,0,&slot_mu_downleft);
    559:   DMGetLocalVector(ctx->dm_lame,&lame_local);
    560:   DMGlobalToLocal(ctx->dm_lame,lame,INSERT_VALUES,lame_local);
    561:   DMStagVecGetArrayRead(ctx->dm_lame,lame_local,&arr_lame);

    563:   /* Prepare read-only access to coordinate data */
    564:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
    565:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
    566:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
    567:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);

    569:   /* Iterate over the interior of the domain, updating the stresses */
    570:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,NULL,&nx,&ny,NULL,NULL,NULL,NULL);
    571:   for (ey = starty; ey < starty + ny; ++ey) {
    572:     for (ex = startx; ex < startx + nx; ++ex) {

    574:       /* Update tau_xx and tau_yy*/
    575:       {
    576:         const PetscScalar dx   = arr_coord_x[ex][slot_coord_next] - arr_coord_x[ex][slot_coord_prev];
    577:         const PetscScalar dy   = arr_coord_y[ey][slot_coord_next] - arr_coord_y[ey][slot_coord_prev];
    578:         const PetscScalar L    = arr_lame[ey][ex][slot_lambda_element];
    579:         const PetscScalar Lp2M = arr_lame[ey][ex][slot_lambda_element] + 2 * arr_lame[ey][ex][slot_mu_element];

    581:         arr_stress[ey][ex][slot_txx] +=
    582:             Lp2M * ctx->dt * (arr_velocity[ey][ex][slot_vx_right] - arr_velocity[ey][ex][slot_vx_left]) / dx
    583:           + L    * ctx->dt * (arr_velocity[ey][ex][slot_vy_up]    - arr_velocity[ey][ex][slot_vy_down]) / dy;

    585:         arr_stress[ey][ex][slot_tyy] +=
    586:             Lp2M * ctx->dt * (arr_velocity[ey][ex][slot_vy_up]    - arr_velocity[ey][ex][slot_vy_down]) / dy
    587:           + L    * ctx->dt * (arr_velocity[ey][ex][slot_vx_right] - arr_velocity[ey][ex][slot_vx_left]) / dx;
    588:       }

    590:       /* Update tau_xy */
    591:       if (ex > 0 && ey > 0) {
    592:         const PetscScalar dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
    593:         const PetscScalar dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
    594:         const PetscScalar M  = arr_lame[ey][ex][slot_mu_downleft];

    596:         arr_stress[ey][ex][slot_txy_downleft] += M * ctx->dt * (
    597:             (arr_velocity[ey][ex][slot_vx_left] - arr_velocity[ey-1][ex][slot_vx_left]) / dy
    598:           + (arr_velocity[ey][ex][slot_vy_down] - arr_velocity[ey][ex-1][slot_vy_down]) / dx);
    599:       }
    600:     }
    601:   }

    603:   /* Restore all access */
    604:   DMStagVecRestoreArray(ctx->dm_stress,stress_local,&arr_stress);
    605:   DMLocalToGlobal(ctx->dm_stress,stress_local,INSERT_VALUES,stress);
    606:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
    607:   DMStagVecRestoreArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);
    608:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
    609:   DMStagVecRestoreArrayRead(ctx->dm_lame,lame_local,&arr_lame);
    610:   DMRestoreLocalVector(ctx->dm_lame,&lame_local);
    611:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);
    612:   return 0;
    613: }

    615: static PetscErrorCode UpdateStress_3d(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
    616: {
    617:   Vec               velocity_local,stress_local,lame_local;
    618:   PetscInt          ex,ey,ez,startx,starty,startz,nx,ny,nz;
    619:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
    620:   PetscInt          slot_vx_left,slot_vy_down,slot_vx_right,slot_vy_up,slot_vz_back,slot_vz_front;
    621:   PetscInt          slot_mu_element,slot_lambda_element,slot_mu_downleft,slot_mu_backdown,slot_mu_backleft;
    622:   PetscInt          slot_txx,slot_tyy,slot_tzz,slot_txy_downleft,slot_txz_backleft,slot_tyz_backdown;
    623:   const PetscScalar **arr_coord_x,**arr_coord_y,**arr_coord_z;
    624:   const PetscScalar ****arr_velocity,****arr_lame;
    625:   PetscScalar       ****arr_stress;

    629:   /* Prepare read-write access to stress data */
    630:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,0,&slot_txx);
    631:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,1,&slot_tyy);
    632:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,2,&slot_tzz);
    633:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT,0,&slot_txy_downleft);
    634:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_LEFT,0,&slot_txz_backleft);
    635:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_DOWN,0,&slot_tyz_backdown);
    636:   DMGetLocalVector(ctx->dm_stress,&stress_local);
    637:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
    638:   DMStagVecGetArray(ctx->dm_stress,stress_local,&arr_stress);

    640:   /* Prepare read-only access to velocity data */
    641:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT, 0,&slot_vx_left);
    642:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,0,&slot_vx_right);
    643:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN, 0,&slot_vy_down);
    644:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_UP,   0,&slot_vy_up);
    645:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_BACK, 0,&slot_vz_back);
    646:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_FRONT,0,&slot_vz_front);
    647:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
    648:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
    649:   DMStagVecGetArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);

    651:   /* Prepare read-only access to Lame' data */
    652:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,  0,&slot_lambda_element);
    653:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,  1,&slot_mu_element);
    654:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_DOWN_LEFT,0,&slot_mu_downleft);
    655:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_BACK_LEFT,0,&slot_mu_backleft);
    656:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_BACK_DOWN,0,&slot_mu_backdown);
    657:   DMGetLocalVector(ctx->dm_lame,&lame_local);
    658:   DMGlobalToLocal(ctx->dm_lame,lame,INSERT_VALUES,lame_local);
    659:   DMStagVecGetArrayRead(ctx->dm_lame,lame_local,&arr_lame);

    661:   /* Prepare read-only access to coordinate data */
    662:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
    663:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
    664:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
    665:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);

    667:   /* Iterate over the interior of the domain, updating the stresses */
    668:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
    669:   for (ez = startz; ez < startz + nz; ++ez) {
    670:     for (ey = starty; ey < starty + ny; ++ey) {
    671:       for (ex = startx; ex < startx + nx; ++ex) {

    673:         /* Update tau_xx, tau_yy, and tau_zz*/
    674:         {
    675:           const PetscScalar dx   = arr_coord_x[ex][slot_coord_next] - arr_coord_x[ex][slot_coord_prev];
    676:           const PetscScalar dy   = arr_coord_y[ey][slot_coord_next] - arr_coord_y[ey][slot_coord_prev];
    677:           const PetscScalar dz   = arr_coord_z[ez][slot_coord_next] - arr_coord_z[ez][slot_coord_prev];
    678:           const PetscScalar L    = arr_lame[ez][ey][ex][slot_lambda_element];
    679:           const PetscScalar Lp2M = arr_lame[ez][ey][ex][slot_lambda_element] + 2 * arr_lame[ez][ey][ex][slot_mu_element];

    681:           arr_stress[ez][ey][ex][slot_txx] +=
    682:               Lp2M * ctx->dt * (arr_velocity[ez][ey][ex][slot_vx_right] - arr_velocity[ez][ey][ex][slot_vx_left]) / dx
    683:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vy_up]    - arr_velocity[ez][ey][ex][slot_vy_down]) / dy
    684:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vz_front] - arr_velocity[ez][ey][ex][slot_vz_back]) / dz;

    686:           arr_stress[ez][ey][ex][slot_tyy] +=
    687:               Lp2M * ctx->dt * (arr_velocity[ez][ey][ex][slot_vy_up]    - arr_velocity[ez][ey][ex][slot_vy_down]) / dy
    688:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vz_front] - arr_velocity[ez][ey][ex][slot_vz_back]) / dz
    689:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vx_right] - arr_velocity[ez][ey][ex][slot_vx_left]) / dx;

    691:           arr_stress[ez][ey][ex][slot_tzz] +=
    692:               Lp2M * ctx->dt * (arr_velocity[ez][ey][ex][slot_vz_front] - arr_velocity[ez][ey][ex][slot_vz_back]) / dz
    693:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vx_right] - arr_velocity[ez][ey][ex][slot_vx_left]) / dx
    694:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vy_up]    - arr_velocity[ez][ey][ex][slot_vy_down]) / dy;
    695:         }

    697:         /* Update tau_xy, tau_xz, tau_yz */
    698:         {
    699:           PetscScalar dx,dy,dz;

    701:           if (ex > 0)  dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
    702:           if (ey > 0)  dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
    703:           if (ez > 0)  dz = arr_coord_z[ez][slot_coord_element] - arr_coord_z[ez-1][slot_coord_element];

    705:           if (ex > 0 && ey > 0) {
    706:             const PetscScalar M = arr_lame[ez][ey][ex][slot_mu_downleft];

    708:             arr_stress[ez][ey][ex][slot_txy_downleft] += M * ctx->dt * (
    709:                   (arr_velocity[ez][ey][ex][slot_vx_left] - arr_velocity[ez][ey-1][ex][slot_vx_left]) / dy
    710:                 + (arr_velocity[ez][ey][ex][slot_vy_down] - arr_velocity[ez][ey][ex-1][slot_vy_down]) / dx);
    711:           }

    713:           /* Update tau_xz */
    714:           if (ex > 0 && ez > 0) {
    715:             const PetscScalar M  = arr_lame[ez][ey][ex][slot_mu_backleft];

    717:             arr_stress[ez][ey][ex][slot_txz_backleft] += M * ctx->dt * (
    718:                 (arr_velocity[ez][ey][ex][slot_vx_left] - arr_velocity[ez-1][ey][ex][slot_vx_left]) / dz
    719:               + (arr_velocity[ez][ey][ex][slot_vz_back] - arr_velocity[ez][ey][ex-1][slot_vz_back]) / dx);
    720:           }

    722:           /* Update tau_yz */
    723:           if (ey > 0 && ez > 0) {
    724:             const PetscScalar M  = arr_lame[ez][ey][ex][slot_mu_backdown];

    726:             arr_stress[ez][ey][ex][slot_tyz_backdown] += M * ctx->dt * (
    727:                 (arr_velocity[ez][ey][ex][slot_vy_down] - arr_velocity[ez-1][ey][ex][slot_vy_down]) / dz
    728:               + (arr_velocity[ez][ey][ex][slot_vz_back] - arr_velocity[ez][ey-1][ex][slot_vz_back]) / dy);
    729:           }
    730:         }
    731:       }
    732:     }
    733:   }

    735:   /* Restore all access */
    736:   DMStagVecRestoreArray(ctx->dm_stress,stress_local,&arr_stress);
    737:   DMLocalToGlobal(ctx->dm_stress,stress_local,INSERT_VALUES,stress);
    738:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
    739:   DMStagVecRestoreArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);
    740:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
    741:   DMStagVecRestoreArrayRead(ctx->dm_lame,lame_local,&arr_lame);
    742:   DMRestoreLocalVector(ctx->dm_lame,&lame_local);
    743:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);
    744:   return 0;
    745: }

    747: static PetscErrorCode UpdateStress(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
    748: {
    750:   if (ctx->dim == 2) {
    751:     UpdateStress_2d(ctx,velocity,stress,lame);
    752:   } else if (ctx->dim ==3) {
    753:     UpdateStress_3d(ctx,velocity,stress,lame);
    754:   }
    755:   return 0;
    756: }

    758: static PetscErrorCode DumpStress(const Ctx *ctx,Vec stress,PetscInt timestep)
    759: {
    760:   DM             da_normal,da_shear = NULL;
    761:   Vec            vec_normal,vec_shear = NULL;

    765:     DMStagVecSplitToDMDA(ctx->dm_stress,stress,DMSTAG_ELEMENT,-ctx->dim,&da_normal,&vec_normal);
    766:     PetscObjectSetName((PetscObject)vec_normal,"normal stresses");

    768:     /* Dump element-based fields to a .vtr file */
    769:     {
    770:       PetscViewer viewer;
    771:       char        filename[PETSC_MAX_PATH_LEN];

    773:       PetscSNPrintf(filename,sizeof(filename),"ex6_stress_normal_%.4D.vtr",timestep);
    774:       PetscViewerVTKOpen(PetscObjectComm((PetscObject)da_normal),filename,FILE_MODE_WRITE,&viewer);
    775:       VecView(vec_normal,viewer);
    776:       PetscViewerDestroy(&viewer);
    777:       PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
    778:     }

    780:   if (ctx->dim == 2) {
    781:     /* (2D only) Dump vertex-based fields to a second .vtr file */
    782:     DMStagVecSplitToDMDA(ctx->dm_stress,stress,DMSTAG_DOWN_LEFT,0,&da_shear,&vec_shear);
    783:     PetscObjectSetName((PetscObject)vec_shear,"shear stresses");

    785:     {
    786:       PetscViewer viewer;
    787:       char        filename[PETSC_MAX_PATH_LEN];

    789:       PetscSNPrintf(filename,sizeof(filename),"ex6_stress_shear_%.4D.vtr",timestep);
    790:       PetscViewerVTKOpen(PetscObjectComm((PetscObject)da_normal),filename,FILE_MODE_WRITE,&viewer);
    791:       VecView(vec_shear,viewer);
    792:       PetscViewerDestroy(&viewer);
    793:       PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
    794:     }
    795:   }

    797:   /* Destroy DMDAs and Vecs */
    798:   DMDestroy(&da_normal);
    799:   DMDestroy(&da_shear);
    800:   VecDestroy(&vec_normal);
    801:   VecDestroy(&vec_shear);
    802:   return 0;
    803: }

    805: static PetscErrorCode DumpVelocity(const Ctx *ctx,Vec velocity,PetscInt timestep)
    806: {
    807:   DM             dmVelAvg;
    808:   Vec            velAvg;
    809:   DM             daVelAvg;
    810:   Vec            vecVelAvg;
    811:   Vec            velocity_local;
    812:   PetscInt       ex,ey,ez,startx,starty,startz,nx,ny,nz;

    816:   if (ctx->dim == 2) {
    817:     DMStagCreateCompatibleDMStag(ctx->dm_velocity,0,0,2,0,&dmVelAvg); /* 2 dof per element */
    818:   } else if (ctx->dim == 3) {
    819:     DMStagCreateCompatibleDMStag(ctx->dm_velocity,0,0,0,3,&dmVelAvg); /* 3 dof per element */
    820:   } else SETERRQ(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
    821:   DMSetUp(dmVelAvg);
    822:   DMStagSetUniformCoordinatesProduct(dmVelAvg,ctx->xmin,ctx->xmax,ctx->ymin,ctx->ymax,ctx->zmin,ctx->zmax);
    823:   DMCreateGlobalVector(dmVelAvg,&velAvg);
    824:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
    825:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
    826:   DMStagGetCorners(dmVelAvg,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
    827:   if (ctx->dim == 2) {
    828:     for (ey = starty; ey<starty+ny; ++ey) {
    829:       for (ex = startx; ex<startx+nx; ++ex) {
    830:         DMStagStencil from[4],to[2];
    831:         PetscScalar   valFrom[4],valTo[2];

    833:         from[0].i = ex; from[0].j = ey; from[0].loc = DMSTAG_UP;    from[0].c = 0;
    834:         from[1].i = ex; from[1].j = ey; from[1].loc = DMSTAG_DOWN;  from[1].c = 0;
    835:         from[2].i = ex; from[2].j = ey; from[2].loc = DMSTAG_LEFT;  from[2].c = 0;
    836:         from[3].i = ex; from[3].j = ey; from[3].loc = DMSTAG_RIGHT; from[3].c = 0;
    837:         DMStagVecGetValuesStencil(ctx->dm_velocity,velocity_local,4,from,valFrom);
    838:         to[0].i = ex; to[0].j = ey; to[0].loc = DMSTAG_ELEMENT;    to[0].c = 0; valTo[0] = 0.5 * (valFrom[2] + valFrom[3]);
    839:         to[1].i = ex; to[1].j = ey; to[1].loc = DMSTAG_ELEMENT;    to[1].c = 1; valTo[1] = 0.5 * (valFrom[0] + valFrom[1]);
    840:         DMStagVecSetValuesStencil(dmVelAvg,velAvg,2,to,valTo,INSERT_VALUES);
    841:       }
    842:     }
    843:   } else if (ctx->dim == 3) {
    844:     for (ez = startz; ez<startz+nz; ++ez) {
    845:       for (ey = starty; ey<starty+ny; ++ey) {
    846:         for (ex = startx; ex<startx+nx; ++ex) {
    847:           DMStagStencil from[6],to[3];
    848:           PetscScalar   valFrom[6],valTo[3];

    850:           from[0].i = ex; from[0].j = ey; from[0].k = ez; from[0].loc = DMSTAG_UP;    from[0].c = 0;
    851:           from[1].i = ex; from[1].j = ey; from[1].k = ez; from[1].loc = DMSTAG_DOWN;  from[1].c = 0;
    852:           from[2].i = ex; from[2].j = ey; from[2].k = ez; from[2].loc = DMSTAG_LEFT;  from[2].c = 0;
    853:           from[3].i = ex; from[3].j = ey; from[3].k = ez; from[3].loc = DMSTAG_RIGHT; from[3].c = 0;
    854:           from[4].i = ex; from[4].j = ey; from[4].k = ez; from[4].loc = DMSTAG_FRONT; from[4].c = 0;
    855:           from[5].i = ex; from[5].j = ey; from[5].k = ez; from[5].loc = DMSTAG_BACK;  from[5].c = 0;
    856:           DMStagVecGetValuesStencil(ctx->dm_velocity,velocity_local,6,from,valFrom);
    857:           to[0].i = ex; to[0].j = ey; to[0].k = ez; to[0].loc = DMSTAG_ELEMENT;    to[0].c = 0; valTo[0] = 0.5 * (valFrom[2] + valFrom[3]);
    858:           to[1].i = ex; to[1].j = ey; to[1].k = ez; to[1].loc = DMSTAG_ELEMENT;    to[1].c = 1; valTo[1] = 0.5 * (valFrom[0] + valFrom[1]);
    859:           to[2].i = ex; to[2].j = ey; to[2].k = ez; to[2].loc = DMSTAG_ELEMENT;    to[2].c = 2; valTo[2] = 0.5 * (valFrom[4] + valFrom[5]);
    860:           DMStagVecSetValuesStencil(dmVelAvg,velAvg,3,to,valTo,INSERT_VALUES);
    861:         }
    862:       }
    863:     }
    864:   } else SETERRQ(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
    865:   VecAssemblyBegin(velAvg);
    866:   VecAssemblyEnd(velAvg);
    867:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);

    869:   DMStagVecSplitToDMDA(dmVelAvg,velAvg,DMSTAG_ELEMENT,-3,&daVelAvg,&vecVelAvg); /* note -3 : pad with zero in 2D case */
    870:   PetscObjectSetName((PetscObject)vecVelAvg,"Velocity (Averaged)");

    872:   /* Dump element-based fields to a .vtr file */
    873:   {
    874:     PetscViewer viewer;
    875:     char        filename[PETSC_MAX_PATH_LEN];

    877:     PetscSNPrintf(filename,sizeof(filename),"ex6_velavg_%.4D.vtr",timestep);
    878:     PetscViewerVTKOpen(PetscObjectComm((PetscObject)daVelAvg),filename,FILE_MODE_WRITE,&viewer);
    879:     VecView(vecVelAvg,viewer);
    880:     PetscViewerDestroy(&viewer);
    881:     PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
    882:   }

    884:   /* Destroy DMDAs and Vecs */
    885:   VecDestroy(&vecVelAvg);
    886:   DMDestroy(&daVelAvg);
    887:   VecDestroy(&velAvg);
    888:   DMDestroy(&dmVelAvg);
    889:   return 0;
    890: }

    892: /*TEST

    894:    test:
    895:       suffix: 1
    896:       requires: !complex
    897:       nsize: 1
    898:       args: -stag_grid_x 12 -stag_grid_y 7 -nsteps 4 -dump_output 0

    900:    test:
    901:       suffix: 2
    902:       requires: !complex
    903:       nsize: 9
    904:       args: -stag_grid_x 12 -stag_grid_y 15 -nsteps 3 -dump_output 0

    906:    test:
    907:       suffix: 3
    908:       requires: !complex
    909:       nsize: 1
    910:       args: -stag_grid_x 12 -stag_grid_y 7 -stag_grid_z 11 -nsteps 2 -dim 3 -dump_output 0

    912:    test:
    913:       suffix: 4
    914:       requires: !complex
    915:       nsize: 12
    916:       args: -stag_grid_x 12 -stag_grid_y 15 -stag_grid_z 8 -nsteps 3 -dim 3 -dump_output 0

    918: TEST*/