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: {
 61:   Ctx            ctx;
 62:   Vec            velocity,stress;
 63:   PetscInt       timestep;

 65:   /* Initialize PETSc */
 66:   PetscInitialize(&argc,&argv,0,help);if (ierr) return ierr;

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

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

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

 91:     switch (ctx.dim) {
 92:       case 2:
 93:         dof0 = 0; dof1 = 1; dof2 = 0; /* 1 dof per cell boundary */
 94:         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);
 95:         break;
 96:       case 3:
 97:         dof0 = 0; dof1 = 0; dof2 = 1; dof3 = 0; /* 1 dof per cell boundary */
 98:         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);
 99:         break;
100:       default: SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not Implemented for dimension %D",ctx.dim);
101:     }
102:   }
103:   DMSetFromOptions(ctx.dm_velocity); /* Options control velocity DM */
104:   DMSetUp(ctx.dm_velocity);
105:   DMStagSetUniformCoordinatesProduct(ctx.dm_velocity,ctx.xmin,ctx.xmax,ctx.ymin,ctx.ymax,ctx.zmin,ctx.zmax);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

312:   VecAssemblyBegin(stress);
313:   VecAssemblyEnd(stress);
314:   return(0);
315: }

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


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

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

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

355:   /* Prepare read-only access to coordinate data */
356:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
357:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
358:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
359:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);

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

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

372:         arr_velocity[ey][ex][slot_vy_down] += B * ctx->dt * (
373:               (arr_stress[ey][ex][slot_txy_downright] - arr_stress[ey  ][ex][slot_txy_downleft]) / dx
374:             + (arr_stress[ey][ex][slot_tyy]           - arr_stress[ey-1][ex][slot_tyy]) / dy);
375:       }

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

383:         arr_velocity[ey][ex][slot_vx_left] += B * ctx->dt * (
384:               (arr_stress[ey][ex][slot_txx]        - arr_stress[ey][ex-1][slot_txx]) / dx
385:             + (arr_stress[ey][ex][slot_txy_upleft] - arr_stress[ey][ex  ][slot_txy_downleft]) / dy);
386:       }
387:     }
388:   }

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

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


419:   /* Prepare direct access to buoyancy data */
420:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_LEFT,0,&slot_buoyancy_left);
421:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_DOWN,0,&slot_buoyancy_down);
422:   DMStagGetLocationSlot(ctx->dm_buoyancy,DMSTAG_BACK,0,&slot_buoyancy_back);
423:   DMGetLocalVector(ctx->dm_buoyancy,&buoyancy_local);
424:   DMGlobalToLocal(ctx->dm_buoyancy,buoyancy,INSERT_VALUES,buoyancy_local);
425:   DMStagVecGetArrayRead(ctx->dm_buoyancy,buoyancy_local,&arr_buoyancy);

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

444:   /* Prepare read-write access to velocity data */
445:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,0,&slot_vx_left);
446:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN,0,&slot_vy_down);
447:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_BACK,0,&slot_vz_back);
448:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
449:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
450:   DMStagVecGetArray(ctx->dm_velocity,velocity_local,&arr_velocity);

452:   /* Prepare read-only access to coordinate data */
453:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
454:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
455:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
456:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);

458:   /* Iterate over interior of the domain, updating the velocities */
459:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
460:   for (ez = startz; ez < startz + nz; ++ez) {
461:     for (ey = starty; ey < starty + ny; ++ey) {
462:       for (ex = startx; ex < startx + nx; ++ex) {

464:         /* Update y-velocity */
465:         if (ey > 0) {
466:           const PetscScalar dx = arr_coord_x[ex][slot_coord_next]    - arr_coord_x[ex  ][slot_coord_prev];
467:           const PetscScalar dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
468:           const PetscScalar dz = arr_coord_z[ez][slot_coord_next]    - arr_coord_z[ez  ][slot_coord_prev];
469:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_down];

471:           arr_velocity[ez][ey][ex][slot_vy_down] += B * ctx->dt * (
472:                 (arr_stress[ez][ey][ex][slot_txy_downright] - arr_stress[ez][ey  ][ex][slot_txy_downleft]) / dx
473:               + (arr_stress[ez][ey][ex][slot_tyy]           - arr_stress[ez][ey-1][ex][slot_tyy]) / dy
474:               + (arr_stress[ez][ey][ex][slot_tyz_frontdown] - arr_stress[ez][ey  ][ex][slot_tyz_backdown]) / dz);
475:         }

477:         /* Update x-velocity */
478:         if (ex > 0) {
479:           const PetscScalar dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
480:           const PetscScalar dy = arr_coord_y[ey][slot_coord_next]    - arr_coord_y[ey  ][slot_coord_prev];
481:           const PetscScalar dz = arr_coord_z[ez][slot_coord_next]    - arr_coord_z[ez  ][slot_coord_prev];
482:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_left];

484:           arr_velocity[ez][ey][ex][slot_vx_left] += B * ctx->dt * (
485:                 (arr_stress[ez][ey][ex][slot_txx]           - arr_stress[ez][ey][ex-1][slot_txx]) / dx
486:               + (arr_stress[ez][ey][ex][slot_txy_upleft]    - arr_stress[ez][ey][ex  ][slot_txy_downleft]) / dy
487:               + (arr_stress[ez][ey][ex][slot_txz_frontleft] - arr_stress[ez][ey][ex  ][slot_txz_backleft]) / dz);
488:         }

490:         /* Update z-velocity */
491:         if (ez > 0) {
492:           const PetscScalar dx = arr_coord_x[ex][slot_coord_next]    - arr_coord_x[ex  ][slot_coord_prev];
493:           const PetscScalar dy = arr_coord_y[ey][slot_coord_next]    - arr_coord_y[ey  ][slot_coord_prev];
494:           const PetscScalar dz = arr_coord_z[ez][slot_coord_element] - arr_coord_z[ez-1][slot_coord_element];
495:           const PetscScalar B = arr_buoyancy[ez][ey][ex][slot_buoyancy_back];

497:           arr_velocity[ez][ey][ex][slot_vz_back] += B * ctx->dt * (
498:               (arr_stress[ez][ey][ex][slot_txz_backright] - arr_stress[ez  ][ey][ex][slot_txz_backleft]) / dx
499:             + (arr_stress[ez][ey][ex][slot_tyz_backup]    - arr_stress[ez  ][ey][ex][slot_tyz_backdown]) / dy
500:             + (arr_stress[ez][ey][ex][slot_tzz]           - arr_stress[ez-1][ey][ex][slot_tzz]) / dz);
501:         }
502:       }
503:     }
504:   }

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

518: static PetscErrorCode UpdateVelocity(const Ctx *ctx,Vec velocity,Vec stress, Vec buoyancy)
519: {

523:   if (ctx->dim == 2) {
524:     UpdateVelocity_2d(ctx,velocity,stress,buoyancy);
525:   } else if (ctx->dim == 3) {
526:     UpdateVelocity_3d(ctx,velocity,stress,buoyancy);
527:   } else SETERRQ1(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
528:   return(0);
529: }

531: static PetscErrorCode UpdateStress_2d(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
532: {
533:   PetscErrorCode    ierr;
534:   Vec               velocity_local,stress_local,lame_local;
535:   PetscInt          ex,ey,startx,starty,nx,ny;
536:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
537:   PetscInt          slot_vx_left,slot_vy_down,slot_vx_right,slot_vy_up;
538:   PetscInt          slot_mu_element,slot_lambda_element,slot_mu_downleft;
539:   PetscInt          slot_txx,slot_tyy,slot_txy_downleft;
540:   const PetscScalar **arr_coord_x,**arr_coord_y;
541:   const PetscScalar ***arr_velocity,***arr_lame;
542:   PetscScalar       ***arr_stress;


546:   /* Prepare read-write access to stress data */
547:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,0,&slot_txx);
548:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,1,&slot_tyy);
549:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT,0,&slot_txy_downleft);
550:   DMGetLocalVector(ctx->dm_stress,&stress_local);
551:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
552:   DMStagVecGetArray(ctx->dm_stress,stress_local,&arr_stress);

554:   /* Prepare read-only access to velocity data */
555:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,0,&slot_vx_left);
556:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,0,&slot_vx_right);
557:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN,0,&slot_vy_down);
558:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_UP,0,&slot_vy_up);
559:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
560:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
561:   DMStagVecGetArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);

563:   /* Prepare read-only access to Lame' data */
564:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,0,&slot_lambda_element);
565:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,1,&slot_mu_element);
566:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_DOWN_LEFT,0,&slot_mu_downleft);
567:   DMGetLocalVector(ctx->dm_lame,&lame_local);
568:   DMGlobalToLocal(ctx->dm_lame,lame,INSERT_VALUES,lame_local);
569:   DMStagVecGetArrayRead(ctx->dm_lame,lame_local,&arr_lame);

571:   /* Prepare read-only access to coordinate data */
572:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
573:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
574:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
575:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);

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

582:       /* Update tau_xx and tau_yy*/
583:       {
584:         const PetscScalar dx   = arr_coord_x[ex][slot_coord_next] - arr_coord_x[ex][slot_coord_prev];
585:         const PetscScalar dy   = arr_coord_y[ey][slot_coord_next] - arr_coord_y[ey][slot_coord_prev];
586:         const PetscScalar L    = arr_lame[ey][ex][slot_lambda_element];
587:         const PetscScalar Lp2M = arr_lame[ey][ex][slot_lambda_element] + 2 * arr_lame[ey][ex][slot_mu_element];

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

593:         arr_stress[ey][ex][slot_tyy] +=
594:             Lp2M * ctx->dt * (arr_velocity[ey][ex][slot_vy_up]    - arr_velocity[ey][ex][slot_vy_down]) / dy
595:           + L    * ctx->dt * (arr_velocity[ey][ex][slot_vx_right] - arr_velocity[ey][ex][slot_vx_left]) / dx;
596:       }

598:       /* Update tau_xy */
599:       if (ex > 0 && ey > 0) {
600:         const PetscScalar dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
601:         const PetscScalar dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
602:         const PetscScalar M  = arr_lame[ey][ex][slot_mu_downleft];

604:         arr_stress[ey][ex][slot_txy_downleft] += M * ctx->dt * (
605:             (arr_velocity[ey][ex][slot_vx_left] - arr_velocity[ey-1][ex][slot_vx_left]) / dy
606:           + (arr_velocity[ey][ex][slot_vy_down] - arr_velocity[ey][ex-1][slot_vy_down]) / dx);
607:       }
608:     }
609:   }

611:   /* Restore all access */
612:   DMStagVecRestoreArray(ctx->dm_stress,stress_local,&arr_stress);
613:   DMLocalToGlobal(ctx->dm_stress,stress_local,INSERT_VALUES,stress);
614:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
615:   DMStagVecRestoreArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);
616:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
617:   DMStagVecRestoreArrayRead(ctx->dm_lame,lame_local,&arr_lame);
618:   DMRestoreLocalVector(ctx->dm_lame,&lame_local);
619:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,NULL);
620:   return(0);
621: }

623: static PetscErrorCode UpdateStress_3d(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
624: {
625:   PetscErrorCode    ierr;
626:   Vec               velocity_local,stress_local,lame_local;
627:   PetscInt          ex,ey,ez,startx,starty,startz,nx,ny,nz;
628:   PetscInt          slot_coord_next,slot_coord_element,slot_coord_prev;
629:   PetscInt          slot_vx_left,slot_vy_down,slot_vx_right,slot_vy_up,slot_vz_back,slot_vz_front;
630:   PetscInt          slot_mu_element,slot_lambda_element,slot_mu_downleft,slot_mu_backdown,slot_mu_backleft;
631:   PetscInt          slot_txx,slot_tyy,slot_tzz,slot_txy_downleft,slot_txz_backleft,slot_tyz_backdown;
632:   const PetscScalar **arr_coord_x,**arr_coord_y,**arr_coord_z;
633:   const PetscScalar ****arr_velocity,****arr_lame;
634:   PetscScalar       ****arr_stress;


638:   /* Prepare read-write access to stress data */
639:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,0,&slot_txx);
640:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,1,&slot_tyy);
641:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_ELEMENT,2,&slot_tzz);
642:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_DOWN_LEFT,0,&slot_txy_downleft);
643:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_LEFT,0,&slot_txz_backleft);
644:   DMStagGetLocationSlot(ctx->dm_stress,DMSTAG_BACK_DOWN,0,&slot_tyz_backdown);
645:   DMGetLocalVector(ctx->dm_stress,&stress_local);
646:   DMGlobalToLocal(ctx->dm_stress,stress,INSERT_VALUES,stress_local);
647:   DMStagVecGetArray(ctx->dm_stress,stress_local,&arr_stress);

649:   /* Prepare read-only access to velocity data */
650:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_LEFT, 0,&slot_vx_left);
651:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,0,&slot_vx_right);
652:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_DOWN, 0,&slot_vy_down);
653:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_UP,   0,&slot_vy_up);
654:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_BACK, 0,&slot_vz_back);
655:   DMStagGetLocationSlot(ctx->dm_velocity,DMSTAG_FRONT,0,&slot_vz_front);
656:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
657:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
658:   DMStagVecGetArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);

660:   /* Prepare read-only access to Lame' data */
661:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,  0,&slot_lambda_element);
662:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_ELEMENT,  1,&slot_mu_element);
663:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_DOWN_LEFT,0,&slot_mu_downleft);
664:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_BACK_LEFT,0,&slot_mu_backleft);
665:   DMStagGetLocationSlot(ctx->dm_lame,DMSTAG_BACK_DOWN,0,&slot_mu_backdown);
666:   DMGetLocalVector(ctx->dm_lame,&lame_local);
667:   DMGlobalToLocal(ctx->dm_lame,lame,INSERT_VALUES,lame_local);
668:   DMStagVecGetArrayRead(ctx->dm_lame,lame_local,&arr_lame);

670:   /* Prepare read-only access to coordinate data */
671:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_LEFT,&slot_coord_prev);
672:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_RIGHT,&slot_coord_next);
673:   DMStagGetProductCoordinateLocationSlot(ctx->dm_velocity,DMSTAG_ELEMENT,&slot_coord_element);
674:   DMStagGetProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);

676:   /* Iterate over the interior of the domain, updating the stresses */
677:   DMStagGetCorners(ctx->dm_velocity,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
678:   for (ez = startz; ez < startz + nz; ++ez) {
679:     for (ey = starty; ey < starty + ny; ++ey) {
680:       for (ex = startx; ex < startx + nx; ++ex) {

682:         /* Update tau_xx, tau_yy, and tau_zz*/
683:         {
684:           const PetscScalar dx   = arr_coord_x[ex][slot_coord_next] - arr_coord_x[ex][slot_coord_prev];
685:           const PetscScalar dy   = arr_coord_y[ey][slot_coord_next] - arr_coord_y[ey][slot_coord_prev];
686:           const PetscScalar dz   = arr_coord_z[ez][slot_coord_next] - arr_coord_z[ez][slot_coord_prev];
687:           const PetscScalar L    = arr_lame[ez][ey][ex][slot_lambda_element];
688:           const PetscScalar Lp2M = arr_lame[ez][ey][ex][slot_lambda_element] + 2 * arr_lame[ez][ey][ex][slot_mu_element];

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

695:           arr_stress[ez][ey][ex][slot_tyy] +=
696:               Lp2M * ctx->dt * (arr_velocity[ez][ey][ex][slot_vy_up]    - arr_velocity[ez][ey][ex][slot_vy_down]) / dy
697:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vz_front] - arr_velocity[ez][ey][ex][slot_vz_back]) / dz
698:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vx_right] - arr_velocity[ez][ey][ex][slot_vx_left]) / dx;

700:           arr_stress[ez][ey][ex][slot_tzz] +=
701:               Lp2M * ctx->dt * (arr_velocity[ez][ey][ex][slot_vz_front] - arr_velocity[ez][ey][ex][slot_vz_back]) / dz
702:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vx_right] - arr_velocity[ez][ey][ex][slot_vx_left]) / dx
703:             + L    * ctx->dt * (arr_velocity[ez][ey][ex][slot_vy_up]    - arr_velocity[ez][ey][ex][slot_vy_down]) / dy;
704:         }

706:         /* Update tau_xy, tau_xz, tau_yz */
707:         {
708:           PetscScalar dx,dy,dz;

710:           if (ex > 0)  dx = arr_coord_x[ex][slot_coord_element] - arr_coord_x[ex-1][slot_coord_element];
711:           if (ey > 0)  dy = arr_coord_y[ey][slot_coord_element] - arr_coord_y[ey-1][slot_coord_element];
712:           if (ez > 0)  dz = arr_coord_z[ez][slot_coord_element] - arr_coord_z[ez-1][slot_coord_element];

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

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

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

726:             arr_stress[ez][ey][ex][slot_txz_backleft] += M * ctx->dt * (
727:                 (arr_velocity[ez][ey][ex][slot_vx_left] - arr_velocity[ez-1][ey][ex][slot_vx_left]) / dz
728:               + (arr_velocity[ez][ey][ex][slot_vz_back] - arr_velocity[ez][ey][ex-1][slot_vz_back]) / dx);
729:           }

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

735:             arr_stress[ez][ey][ex][slot_tyz_backdown] += M * ctx->dt * (
736:                 (arr_velocity[ez][ey][ex][slot_vy_down] - arr_velocity[ez-1][ey][ex][slot_vy_down]) / dz
737:               + (arr_velocity[ez][ey][ex][slot_vz_back] - arr_velocity[ez][ey-1][ex][slot_vz_back]) / dy);
738:           }
739:         }
740:       }
741:     }
742:   }

744:   /* Restore all access */
745:   DMStagVecRestoreArray(ctx->dm_stress,stress_local,&arr_stress);
746:   DMLocalToGlobal(ctx->dm_stress,stress_local,INSERT_VALUES,stress);
747:   DMRestoreLocalVector(ctx->dm_stress,&stress_local);
748:   DMStagVecRestoreArrayRead(ctx->dm_velocity,velocity_local,&arr_velocity);
749:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);
750:   DMStagVecRestoreArrayRead(ctx->dm_lame,lame_local,&arr_lame);
751:   DMRestoreLocalVector(ctx->dm_lame,&lame_local);
752:   DMStagRestoreProductCoordinateArrays(ctx->dm_velocity,&arr_coord_x,&arr_coord_y,&arr_coord_z);
753:   return(0);
754: }

756: static PetscErrorCode UpdateStress(const Ctx *ctx,Vec velocity,Vec stress, Vec lame)
757: {

761:   if (ctx->dim == 2) {
762:     UpdateStress_2d(ctx,velocity,stress,lame);
763:   } else if (ctx->dim ==3) {
764:     UpdateStress_3d(ctx,velocity,stress,lame);
765:   }
766:   return(0);
767: }

769: static PetscErrorCode DumpStress(const Ctx *ctx,Vec stress,PetscInt timestep)
770: {
772:   DM             da_normal,da_shear = NULL;
773:   Vec            vec_normal,vec_shear = NULL;


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

780:     /* Dump element-based fields to a .vtr file */
781:     {
782:       PetscViewer viewer;
783:       char        filename[PETSC_MAX_PATH_LEN];

785:       PetscSNPrintf(filename,sizeof(filename),"ex6_stress_normal_%.4D.vtr",timestep);
786:       PetscViewerVTKOpen(PetscObjectComm((PetscObject)da_normal),filename,FILE_MODE_WRITE,&viewer);
787:       VecView(vec_normal,viewer);
788:       PetscViewerDestroy(&viewer);
789:       PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
790:     }

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

797:     {
798:       PetscViewer viewer;
799:       char        filename[PETSC_MAX_PATH_LEN];

801:       PetscSNPrintf(filename,sizeof(filename),"ex6_stress_shear_%.4D.vtr",timestep);
802:       PetscViewerVTKOpen(PetscObjectComm((PetscObject)da_normal),filename,FILE_MODE_WRITE,&viewer);
803:       VecView(vec_shear,viewer);
804:       PetscViewerDestroy(&viewer);
805:       PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
806:     }
807:   }

809:   /* Destroy DMDAs and Vecs */
810:   DMDestroy(&da_normal);
811:   DMDestroy(&da_shear);
812:   VecDestroy(&vec_normal);
813:   VecDestroy(&vec_shear);
814:   return(0);
815: }

817: static PetscErrorCode DumpVelocity(const Ctx *ctx,Vec velocity,PetscInt timestep)
818: {
820:   DM             dmVelAvg;
821:   Vec            velAvg;
822:   DM             daVelAvg;
823:   Vec            vecVelAvg;
824:   Vec            velocity_local;
825:   PetscInt       ex,ey,ez,startx,starty,startz,nx,ny,nz;


829:   if (ctx->dim == 2) {
830:     DMStagCreateCompatibleDMStag(ctx->dm_velocity,0,0,2,0,&dmVelAvg); /* 2 dof per element */
831:   } else if (ctx->dim == 3) {
832:     DMStagCreateCompatibleDMStag(ctx->dm_velocity,0,0,0,3,&dmVelAvg); /* 3 dof per element */
833:   } else SETERRQ1(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
834:   DMSetUp(dmVelAvg);
835:   DMStagSetUniformCoordinatesProduct(dmVelAvg,ctx->xmin,ctx->xmax,ctx->ymin,ctx->ymax,ctx->zmin,ctx->zmax);
836:   DMCreateGlobalVector(dmVelAvg,&velAvg);
837:   DMGetLocalVector(ctx->dm_velocity,&velocity_local);
838:   DMGlobalToLocal(ctx->dm_velocity,velocity,INSERT_VALUES,velocity_local);
839:   DMStagGetCorners(dmVelAvg,&startx,&starty,&startz,&nx,&ny,&nz,NULL,NULL,NULL);
840:   if (ctx->dim == 2) {
841:     for (ey = starty; ey<starty+ny; ++ey) {
842:       for (ex = startx; ex<startx+nx; ++ex) {
843:         DMStagStencil from[4],to[2];
844:         PetscScalar   valFrom[4],valTo[2];

846:         from[0].i = ex; from[0].j = ey; from[0].loc = DMSTAG_UP;    from[0].c = 0;
847:         from[1].i = ex; from[1].j = ey; from[1].loc = DMSTAG_DOWN;  from[1].c = 0;
848:         from[2].i = ex; from[2].j = ey; from[2].loc = DMSTAG_LEFT;  from[2].c = 0;
849:         from[3].i = ex; from[3].j = ey; from[3].loc = DMSTAG_RIGHT; from[3].c = 0;
850:         DMStagVecGetValuesStencil(ctx->dm_velocity,velocity_local,4,from,valFrom);
851:         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]);
852:         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]);
853:         DMStagVecSetValuesStencil(dmVelAvg,velAvg,2,to,valTo,INSERT_VALUES);
854:       }
855:     }
856:   } else if (ctx->dim == 3) {
857:     for (ez = startz; ez<startz+nz; ++ez) {
858:       for (ey = starty; ey<starty+ny; ++ey) {
859:         for (ex = startx; ex<startx+nx; ++ex) {
860:           DMStagStencil from[6],to[3];
861:           PetscScalar   valFrom[6],valTo[3];

863:           from[0].i = ex; from[0].j = ey; from[0].k = ez; from[0].loc = DMSTAG_UP;    from[0].c = 0;
864:           from[1].i = ex; from[1].j = ey; from[1].k = ez; from[1].loc = DMSTAG_DOWN;  from[1].c = 0;
865:           from[2].i = ex; from[2].j = ey; from[2].k = ez; from[2].loc = DMSTAG_LEFT;  from[2].c = 0;
866:           from[3].i = ex; from[3].j = ey; from[3].k = ez; from[3].loc = DMSTAG_RIGHT; from[3].c = 0;
867:           from[4].i = ex; from[4].j = ey; from[4].k = ez; from[4].loc = DMSTAG_FRONT; from[4].c = 0;
868:           from[5].i = ex; from[5].j = ey; from[5].k = ez; from[5].loc = DMSTAG_BACK;  from[5].c = 0;
869:           DMStagVecGetValuesStencil(ctx->dm_velocity,velocity_local,6,from,valFrom);
870:           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]);
871:           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]);
872:           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]);
873:           DMStagVecSetValuesStencil(dmVelAvg,velAvg,3,to,valTo,INSERT_VALUES);
874:         }
875:       }
876:     }
877:   } else SETERRQ1(PetscObjectComm((PetscObject)ctx->dm_velocity),PETSC_ERR_SUP,"Unsupported dim %d",ctx->dim);
878:   VecAssemblyBegin(velAvg);
879:   VecAssemblyEnd(velAvg);
880:   DMRestoreLocalVector(ctx->dm_velocity,&velocity_local);

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

885:   /* Dump element-based fields to a .vtr file */
886:   {
887:     PetscViewer viewer;
888:     char        filename[PETSC_MAX_PATH_LEN];

890:     PetscSNPrintf(filename,sizeof(filename),"ex6_velavg_%.4D.vtr",timestep);
891:     PetscViewerVTKOpen(PetscObjectComm((PetscObject)daVelAvg),filename,FILE_MODE_WRITE,&viewer);
892:     VecView(vecVelAvg,viewer);
893:     PetscViewerDestroy(&viewer);
894:     PetscPrintf(PETSC_COMM_WORLD,"Created %s\n",filename);
895:   }

897:   /* Destroy DMDAs and Vecs */
898:   VecDestroy(&vecVelAvg);
899:   DMDestroy(&daVelAvg);
900:   VecDestroy(&velAvg);
901:   DMDestroy(&dmVelAvg);
902:   return(0);
903: }

905: /*TEST

907:    test:
908:       suffix: 1
909:       requires: !complex
910:       nsize: 1
911:       args: -stag_grid_x 12 -stag_grid_y 7 -nsteps 4 -dump_output 0

913:    test:
914:       suffix: 2
915:       requires: !complex
916:       nsize: 9
917:       args: -stag_grid_x 12 -stag_grid_y 15 -nsteps 3 -dump_output 0

919:    test:
920:       suffix: 3
921:       requires: !complex
922:       nsize: 1
923:       args: -stag_grid_x 12 -stag_grid_y 7 -stag_grid_z 11 -nsteps 2 -dim 3 -dump_output 0

925:    test:
926:       suffix: 4
927:       requires: !complex
928:       nsize: 12
929:       args: -stag_grid_x 12 -stag_grid_y 15 -stag_grid_z 8 -nsteps 3 -dim 3 -dump_output 0

931: TEST*/