Actual source code: ex77.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  1: static char help[] = "Nonlinear elasticity problem in 3d with simplicial finite elements.\n\
  2: We solve a nonlinear elasticity problem, modelled as an incompressible Neo-Hookean solid, \n\
  3:  with pressure loading in a rectangular domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\n\n";

  5: /*
  6: Nonlinear elasticity problem, which we discretize using the finite
  7: element method on an unstructured mesh. This uses both Dirichlet boundary conditions (fixed faces) 
  8: and nonlinear Neumann boundary conditions (pressure loading).
  9: The Lagrangian density (modulo boundary conditions) for this problem is given by 
 10: \begin{equation}
 11:   \frac{\mu}{2} (\mathrm{Tr}{C}-3) + J p + \frac{\kappa}{2} (J-1).
 12: \end{equation}

 14: Discretization:

 16: We use PetscFE to generate a tabulation of the finite element basis functions
 17: at quadrature points. We can currently generate an arbitrary order Lagrange
 18: element.

 20: Field Data:

 22:   DMPLEX data is organized by point, and the closure operation just stacks up the
 23: data from each sieve point in the closure. Thus, for a P_2-P_1 Stokes element, we
 24: have

 26:   cl{e} = {f e_0 e_1 e_2 v_0 v_1 v_2}
 27:   x     = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} p_{v_0} u_{v_1} v_{v_1} p_{v_1} u_{v_2} v_{v_2} p_{v_2}]

 29: The problem here is that we would like to loop over each field separately for
 30: integration. Therefore, the closure visitor in DMPlexVecGetClosure() reorders
 31: the data so that each field is contiguous

 33:   x'    = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} u_{v_1} v_{v_1} u_{v_2} v_{v_2} p_{v_0} p_{v_1} p_{v_2}]

 35: Likewise, DMPlexVecSetClosure() takes data partitioned by field, and correctly
 36: puts it into the Sieve ordering.

 38: */

 40: #include <petscdmplex.h>
 41: #include <petscsnes.h>
 42: #include <petscds.h>

 44: typedef enum {RUN_FULL, RUN_TEST} RunType;

 46: typedef struct {
 47:   PetscInt      debug;             /* The debugging level */
 48:   RunType       runType;           /* Whether to run tests, or solve the full problem */
 49:   PetscLogEvent createMeshEvent;
 50:   PetscBool     showInitial, showSolution;
 51:   /* Domain and mesh definition */
 52:   PetscInt      dim;               /* The topological mesh dimension */
 53:   PetscBool     interpolate;       /* Generate intermediate mesh elements */
 54:   PetscBool     simplex;           /* Use simplices or tensor product cells */
 55:   PetscReal     refinementLimit;   /* The largest allowable cell volume */
 56:   PetscBool     testPartition;     /* Use a fixed partitioning for testing */
 57:   PetscReal     mu;                /* The shear modulus */
 58: } AppCtx;

 60: /* Kronecker-delta */
 61: static const PetscInt delta2D[2*2] = {1,0,0,1};
 62: static const PetscInt delta3D[3*3] = {1,0,0,0,1,0,0,0,1};

 64: /* Levi-Civita symbol */
 65: static const PetscInt epsilon2D[2*2] = {0,1,-1,0};
 66: static const PetscInt epsilon3D[3*3*3] = {0,0,0,0,0,1,0,-1,0,0,0,-1,0,0,0,1,0,0,0,1,0,-1,0,0,0,0,0};

 68: PETSC_STATIC_INLINE void Det2D(PetscReal *detJ, const PetscReal J[])
 69: {
 70:   *detJ = J[0]*J[3] - J[1]*J[2];
 71: }

 73: PETSC_STATIC_INLINE void Det3D(PetscReal *detJ, const PetscReal J[])
 74: {
 75:   *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
 76:            J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
 77:            J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
 78: }

 80: PETSC_STATIC_INLINE void Cof2D(PetscReal C[], const PetscReal A[])
 81: {
 82:   C[0] =  A[3];
 83:   C[1] = -A[2];
 84:   C[2] = -A[1];
 85:   C[3] =  A[0];
 86: }

 88: PETSC_STATIC_INLINE void Cof3D(PetscReal C[], const PetscReal A[])
 89: {
 90:   C[0*3+0] = A[1*3+1]*A[2*3+2] - A[1*3+2]*A[2*3+1];
 91:   C[0*3+1] = A[1*3+2]*A[2*3+0] - A[1*3+0]*A[2*3+2];
 92:   C[0*3+2] = A[1*3+0]*A[2*3+1] - A[1*3+1]*A[2*3+0];
 93:   C[1*3+0] = A[0*3+2]*A[2*3+1] - A[0*3+1]*A[2*3+2];
 94:   C[1*3+1] = A[0*3+0]*A[2*3+2] - A[0*3+2]*A[2*3+0];
 95:   C[1*3+2] = A[0*3+1]*A[2*3+0] - A[0*3+0]*A[2*3+1];
 96:   C[2*3+0] = A[0*3+1]*A[1*3+2] - A[0*3+2]*A[1*3+1];
 97:   C[2*3+1] = A[0*3+2]*A[1*3+0] - A[0*3+0]*A[1*3+2];
 98:   C[2*3+2] = A[0*3+0]*A[1*3+1] - A[0*3+1]*A[1*3+0];
 99: }

101: PetscErrorCode zero_scalar(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
102: {
103:   u[0] = 0.0;
104:   return 0;
105: }

107: PetscErrorCode zero_vector(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
108: {
109:   const PetscInt Ncomp = dim;

111:   PetscInt       comp;
112:   for (comp = 0; comp < Ncomp; ++comp) u[comp] = 0.0;
113:   return 0;
114: }

116: PetscErrorCode coordinates(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
117: {
118:   const PetscInt Ncomp = dim;

120:   PetscInt       comp;
121:   for (comp = 0; comp < Ncomp; ++comp) u[comp] = x[comp];
122:   return 0;
123: }

125: PetscErrorCode elasticityMaterial(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
126: {
127:   AppCtx *user = (AppCtx *) ctx;
128:   u[0] = user->mu;
129:   return 0;
130: }

132: void f0_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
133:           const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
134:           const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
135:           PetscReal t, const PetscReal x[], PetscScalar f0[])
136: {
137:   const PetscInt Ncomp = dim;

139:   PetscInt comp;
140:   for (comp = 0; comp < Ncomp; ++comp) f0[comp] = 0.0;
141: }

143: void f1_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
144:           const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
145:           const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
146:           PetscReal t, const PetscReal x[], PetscScalar f1[])
147: {
148:   const PetscInt  Ncomp = dim;
149:   const PetscReal mu = a[0], p = u[Ncomp], kappa = 3.0;
150:   PetscReal       cofu_x[Ncomp*dim], detu_x;

152:   Cof3D(cofu_x, u_x);
153:   Det3D(&detu_x, u_x);

155:   /* f1 is the first Piola-Kirchhoff tensor */
156:   PetscInt        comp, d;
157:   for (comp = 0; comp < Ncomp; ++comp) {
158:     for (d = 0; d < dim; ++d) {
159:       f1[comp*dim+d] = mu * u_x[comp*dim+d] + cofu_x[comp*dim+d] * (p + kappa * (detu_x - 1.0));
160:     }
161:   }
162: }

164: void g3_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
165:           const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
166:           const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
167:           PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[])
168: {
169:   const PetscInt  Ncomp = dim;
170:   const PetscReal mu = a[0], p = u[Ncomp], kappa = 3.0;
171:   PetscReal       cofu_x[Ncomp*dim], detu_x;

173:   Cof3D(cofu_x, u_x);
174:   Det3D(&detu_x, u_x);

176:   /* g3 is the first elasticity tensor, i.e. A_i^I_j^J = S^{IJ} g_{ij} + C^{KILJ} F^k_K F^l_L g_{kj} g_{li} */
177:   PetscInt compI, compJ, compK, d1, d2, d3;
178:   for (compI = 0; compI < Ncomp; ++compI) {
179:     for (compJ = 0; compJ < Ncomp; ++compJ) {
180:       for (d1 = 0; d1 < dim; ++d1) {
181:         for (d2 = 0; d2 < dim; ++d2) {
182:           for (compK = 0; compK < Ncomp; ++compK) {
183:             for (d3 = 0; d3 < dim; ++d3) {
184:               g3[((compI*Ncomp+compJ)*dim+d1)*dim+d2] += (p + kappa * (detu_x - 1.0)) * epsilon3D[(compI*Ncomp+compJ)*Ncomp+compK] * epsilon3D[(d1*dim+d2)*dim+d3] * u_x[compK*dim+d3];
185:             }
186:           }
187:           g3[((compI*Ncomp+compJ)*dim+d1)*dim+d2] += kappa * cofu_x[compI*dim+d1] * cofu_x[compJ*dim+d2] + delta3D[compI*Ncomp+compJ] * delta3D[d1*dim+d2] * mu;
188:         }
189:       }
190:     }
191:   }
192: }

194: void f0_bd_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
195:     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
196:     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
197:     PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
198: {
199:   const PetscInt  Ncomp = dim;
200:   const PetscReal p = 0.4; /* Should this be specified as an auxiliary field? */
201:   PetscReal       cofu_x[Ncomp*dim];

203:   Cof3D(cofu_x, u_x);

205:   PetscInt comp, d;
206:   for (comp = 0; comp < Ncomp; ++comp) {
207:     for (d = 0, f0[comp] = 0.0; d < dim; ++d) f0[comp] += cofu_x[comp*dim+d] * n[d];
208:     f0[comp] *= p;
209:   }
210: }

212: void f1_bd_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
213:                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
214:                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
215:                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f1[])
216: {
217:   const PetscInt Ncomp = dim;

219:   PetscInt       comp, d;
220:   for (comp = 0; comp < Ncomp; ++comp) {
221:     for (d = 0; d < dim; ++d) {
222:       f1[comp*dim+d] = 0.0;
223:     }
224:   }
225: }

227: void g1_bd_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
228:     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
229:     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
230:     PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g1[])
231: {
232:   const PetscInt  Ncomp = dim;
233:   const PetscReal p = 0.4; /* Should this be specified as an auxiliary field? */

235:   PetscInt compI, compJ, compK, d1, d2, d3;
236:   for (compI = 0; compI < Ncomp; ++compI) {
237:     for (compJ = 0; compJ < Ncomp; ++compJ) {
238:       for (d2 = 0; d2 < dim; ++d2) {
239:         for (compK = 0; compK < Ncomp; ++compK) {
240:           for (d3 = 0; d3 < dim; ++d3) {
241:             for (d1 = 0; d1 < dim; ++d1) {
242:               g1[(compI*Ncomp+compJ)*dim+d2] += epsilon3D[(compI*Ncomp+compJ)*Ncomp+compK] * epsilon3D[(d2*dim+d3)*dim+d1] * u_x[compK*dim+d3] * n[d1];
243:             }
244:           }
245:         }
246:         g1[(compI*Ncomp+compJ)*dim+d2] *= p;
247:       }
248:     }
249:   }
250: }

252: void f0_p_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
253:           const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
254:           const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
255:           PetscReal t, const PetscReal x[], PetscScalar f0[])
256: {
257:   PetscReal detu_x;
258:   Det3D(&detu_x, u_x);
259:   f0[0] = detu_x - 1.0;
260: }

262: void f1_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
263:           const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
264:           const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
265:           PetscReal t, const PetscReal x[], PetscScalar f1[])
266: {
267:   PetscInt d;
268:   for (d = 0; d < dim; ++d) f1[d] = 0.0;
269: }

271: void f0_bd_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
272:     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
273:     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
274:     PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
275: {
276:   f0[0] = 0.0;
277: }
278: void f1_bd_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
279:                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
280:                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
281:                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f1[])
282: {
283:   PetscInt d;
284:   for (d = 0; d < dim; ++d) f1[d] = 0.0;
285: }

287: void g1_pu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
288:            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
289:            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
290:            PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[])
291: {
292:   Cof3D(g1, u_x);
293: }

295: void g2_up_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
296:            const PetscInt uOff[], const PetscInt uOff_x[], const PetscReal u[], const PetscReal u_t[], const PetscReal u_x[],
297:            const PetscInt aOff[], const PetscInt aOff_x[], const PetscReal a[], const PetscReal a_t[], const PetscReal a_x[],
298:            PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscReal g2[])
299: {
300:   Cof3D(g2, u_x);
301: }

305: PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
306: {
307:   const char    *runTypes[2] = {"full", "test"};
308:   PetscInt       run;

312:   options->debug           = 0;
313:   options->runType         = RUN_FULL;
314:   options->dim             = 3;
315:   options->interpolate     = PETSC_FALSE;
316:   options->simplex         = PETSC_TRUE;
317:   options->refinementLimit = 0.0;
318:   options->mu              = 1.0;
319:   options->testPartition   = PETSC_FALSE;
320:   options->showInitial     = PETSC_FALSE;
321:   options->showSolution    = PETSC_TRUE;

323:   PetscOptionsBegin(comm, "", "Nonlinear elasticity problem options", "DMPLEX");
324:   PetscOptionsInt("-debug", "The debugging level", "ex77.c", options->debug, &options->debug, NULL);
325:   run  = options->runType;
326:   PetscOptionsEList("-run_type", "The run type", "ex77.c", runTypes, 2, runTypes[options->runType], &run, NULL);

328:   options->runType = (RunType) run;

330:   PetscOptionsInt("-dim", "The topological mesh dimension", "ex77.c", options->dim, &options->dim, NULL);
331:   PetscOptionsBool("-interpolate", "Generate intermediate mesh elements", "ex77.c", options->interpolate, &options->interpolate, NULL);
332:   PetscOptionsBool("-simplex", "Use simplices or tensor product cells", "ex77.c", options->simplex, &options->simplex, NULL);
333:   PetscOptionsReal("-refinement_limit", "The largest allowable cell volume", "ex77.c", options->refinementLimit, &options->refinementLimit, NULL);
334:   PetscOptionsBool("-test_partition", "Use a fixed partition for testing", "ex77.c", options->testPartition, &options->testPartition, NULL);
335:   PetscOptionsReal("-shear_modulus", "The shear modulus", "ex77.c", options->mu, &options->mu, NULL);

337:   PetscOptionsBool("-show_initial", "Output the initial guess for verification", "ex77.c", options->showInitial, &options->showInitial, NULL);
338:   PetscOptionsBool("-show_solution", "Output the solution for verification", "ex77.c", options->showSolution, &options->showSolution, NULL);
339:   PetscOptionsEnd();

341:   PetscLogEventRegister("CreateMesh", DM_CLASSID, &options->createMeshEvent);
342:   return(0);
343: }

347: PetscErrorCode DMVecViewLocal(DM dm, Vec v, PetscViewer viewer)
348: {
349:   Vec            lv;
350:   PetscInt       p;
351:   PetscMPIInt    rank, numProcs;

355:   MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
356:   MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);
357:   DMGetLocalVector(dm, &lv);
358:   DMGlobalToLocalBegin(dm, v, INSERT_VALUES, lv);
359:   DMGlobalToLocalEnd(dm, v, INSERT_VALUES, lv);
360:   PetscPrintf(PETSC_COMM_WORLD, "Local function\n");
361:   for (p = 0; p < numProcs; ++p) {
362:     if (p == rank) {VecView(lv, PETSC_VIEWER_STDOUT_SELF);}
363:     PetscBarrier((PetscObject) dm);
364:   }
365:   DMRestoreLocalVector(dm, &lv);
366:   return(0);
367: }

371: PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
372: {
373:   PetscInt       dim             = user->dim;
374:   PetscBool      interpolate     = user->interpolate;
375:   PetscReal      refinementLimit = user->refinementLimit;
376:   const PetscInt cells[3]        = {3, 3, 3};

380:   PetscLogEventBegin(user->createMeshEvent,0,0,0,0);
381:   if (user->simplex) {DMPlexCreateBoxMesh(comm, dim, interpolate, dm);}
382:   else               {DMPlexCreateHexBoxMesh(comm, dim, cells, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, dm);}
383:   /* Label the faces (bit of a hack here, until it is properly implemented for simplices) */
384:   {
385:     DM              cdm;
386:     DMLabel         label;
387:     IS              is;
388:     PetscInt        d, dim = user->dim, b, f, Nf;
389:     const PetscInt *faces;
390:     PetscInt        csize;
391:     PetscReal      *coords = NULL;
392:     PetscSection    cs;
393:     Vec             coordinates ;

395:     DMCreateLabel(*dm, "boundary");
396:     DMGetLabel(*dm, "boundary", &label);
397:     DMPlexMarkBoundaryFaces(*dm, label);
398:     DMGetStratumIS(*dm, "boundary", 1,  &is);
399:     DMCreateLabel(*dm, "Faces");
400:     if (is) {
401:       ISGetLocalSize(is, &Nf);
402:       ISGetIndices(is, &faces);

404:       DMGetCoordinatesLocal(*dm, &coordinates);
405:       DMGetCoordinateDM(*dm, &cdm);
406:       DMGetDefaultSection(cdm, &cs);

408:       /* Check for each boundary face if any component of its centroid is either 0.0 or 1.0 */
409:       PetscReal faceCoord;
410:       PetscInt  v;
411:       for (f = 0; f < Nf; ++f) {
412:         DMPlexVecGetClosure(cdm, cs, coordinates, faces[f], &csize, &coords);
413:         /* Calculate mean coordinate vector */
414:         const PetscInt Nv = csize/dim;
415:         for (d = 0; d < dim; ++d) {
416:           faceCoord = 0.0;
417:           for (v = 0; v < Nv; ++v) faceCoord += coords[v*dim+d];
418:           faceCoord /= Nv;
419:           for (b = 0; b < 2; ++b) {
420:             if (PetscAbs(faceCoord - b*1.0) < PETSC_SMALL) {
421:               DMSetLabelValue(*dm, "Faces", faces[f], d*2+b+1);
422:             }
423:           }
424:         }
425:         DMPlexVecRestoreClosure(cdm, cs, coordinates, faces[f], &csize, &coords);
426:       }
427:       ISRestoreIndices(is, &faces);
428:     }
429:     ISDestroy(&is);
430:     DMGetLabel(*dm, "Faces", &label);
431:     DMPlexLabelComplete(*dm, label);
432:   }
433:   {
434:     DM refinedMesh     = NULL;
435:     DM distributedMesh = NULL;

437:     /* Refine mesh using a volume constraint */
438:     DMPlexSetRefinementLimit(*dm, refinementLimit);
439:     if (user->simplex) {DMRefine(*dm, comm, &refinedMesh);}
440:     if (refinedMesh) {
441:       DMDestroy(dm);
442:       *dm  = refinedMesh;
443:     }
444:     /* Setup test partitioning */
445:     if (user->testPartition) {
446:       PetscInt         triSizes_n2[2]       = {4, 4};
447:       PetscInt         triPoints_n2[8]      = {3, 5, 6, 7, 0, 1, 2, 4};
448:       PetscInt         triSizes_n3[3]       = {2, 3, 3};
449:       PetscInt         triPoints_n3[8]      = {3, 5, 1, 6, 7, 0, 2, 4};
450:       PetscInt         triSizes_n5[5]       = {1, 2, 2, 1, 2};
451:       PetscInt         triPoints_n5[8]      = {3, 5, 6, 4, 7, 0, 1, 2};
452:       PetscInt         triSizes_ref_n2[2]   = {8, 8};
453:       PetscInt         triPoints_ref_n2[16] = {1, 5, 6, 7, 10, 11, 14, 15, 0, 2, 3, 4, 8, 9, 12, 13};
454:       PetscInt         triSizes_ref_n3[3]   = {5, 6, 5};
455:       PetscInt         triPoints_ref_n3[16] = {1, 7, 10, 14, 15, 2, 6, 8, 11, 12, 13, 0, 3, 4, 5, 9};
456:       PetscInt         triSizes_ref_n5[5]   = {3, 4, 3, 3, 3};
457:       PetscInt         triPoints_ref_n5[16] = {1, 7, 10, 2, 11, 13, 14, 5, 6, 15, 0, 8, 9, 3, 4, 12};
458:       const PetscInt  *sizes = NULL;
459:       const PetscInt  *points = NULL;
460:       PetscPartitioner part;
461:       PetscInt         cEnd;
462:       PetscMPIInt      rank, numProcs;

464:       MPI_Comm_rank(comm, &rank);
465:       MPI_Comm_size(comm, &numProcs);
466:       DMPlexGetHeightStratum(*dm, 0, NULL, &cEnd);
467:       if (!rank) {
468:         if (dim == 2 && user->simplex && numProcs == 2 && cEnd == 8) {
469:            sizes = triSizes_n2; points = triPoints_n2;
470:         } else if (dim == 2 && user->simplex && numProcs == 3 && cEnd == 8) {
471:           sizes = triSizes_n3; points = triPoints_n3;
472:         } else if (dim == 2 && user->simplex && numProcs == 5 && cEnd == 8) {
473:           sizes = triSizes_n5; points = triPoints_n5;
474:         } else if (dim == 2 && user->simplex && numProcs == 2 && cEnd == 16) {
475:            sizes = triSizes_ref_n2; points = triPoints_ref_n2;
476:         } else if (dim == 2 && user->simplex && numProcs == 3 && cEnd == 16) {
477:           sizes = triSizes_ref_n3; points = triPoints_ref_n3;
478:         } else if (dim == 2 && user->simplex && numProcs == 5 && cEnd == 16) {
479:           sizes = triSizes_ref_n5; points = triPoints_ref_n5;
480:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "No stored partition matching run parameters");
481:       }
482:       DMPlexGetPartitioner(*dm, &part);
483:       PetscPartitionerSetType(part, PETSCPARTITIONERSHELL);
484:       PetscPartitionerShellSetPartition(part, numProcs, sizes, points);
485:     }
486:     /* Distribute mesh over processes */
487:     DMPlexDistribute(*dm, 0, NULL, &distributedMesh);
488:     if (distributedMesh) {
489:       DMDestroy(dm);
490:       *dm  = distributedMesh;
491:     }
492:   }
493:   DMSetFromOptions(*dm);
494:   DMViewFromOptions(*dm, NULL, "-dm_view");
495: 
496:   PetscLogEventEnd(user->createMeshEvent,0,0,0,0);
497:   return(0);
498: }

502: PetscErrorCode SetupProblem(DM dm, AppCtx *user)
503: {
504:   PetscDS        prob;

508:   DMGetDS(dm, &prob);
509:   PetscDSSetResidual(prob, 0, f0_u, f1_u_3d);
510:   PetscDSSetResidual(prob, 1, f0_p_3d, f1_p);
511:   PetscDSSetJacobian(prob, 0, 0, NULL, NULL,  NULL,  g3_uu_3d);
512:   PetscDSSetJacobian(prob, 0, 1, NULL, NULL,  g2_up_3d, NULL);
513:   PetscDSSetJacobian(prob, 1, 0, NULL, g1_pu_3d, NULL,  NULL);

515:   PetscDSSetBdResidual(prob, 0, f0_bd_u_3d, f1_bd_u);
516:   PetscDSSetBdResidual(prob, 1, f0_bd_p, f1_bd_p);
517:   PetscDSSetBdJacobian(prob, 0, 0, NULL, g1_bd_uu_3d, NULL, NULL);
518:   return(0);
519: }

523: PetscErrorCode SetupMaterial(DM dm, DM dmAux, AppCtx *user)
524: {
525:   PetscErrorCode (*matFuncs[1])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx) = {elasticityMaterial};
526:   Vec            nu;
527:   void *ctxs[] = {user};

531:   DMCreateLocalVector(dmAux, &nu);
532:   DMProjectFunctionLocal(dmAux, 0.0, matFuncs, ctxs, INSERT_ALL_VALUES, nu);
533:   PetscObjectCompose((PetscObject) dm, "A", (PetscObject) nu);
534:   VecDestroy(&nu);
535:   return(0);
536: }

540: PetscErrorCode SetupDiscretization(DM dm, AppCtx *user)
541: {
542:   DM              cdm   = dm, coordDM, dmAux;
543:   const PetscInt  dim   = user->dim;
544:   const PetscBool simplex = user->simplex;
545:   PetscFE         fe[2], feBd[2], feAux;
546:   PetscQuadrature q;
547:   PetscDS         prob, probAux;
548:   PetscInt        order;
549:   PetscErrorCode  ierr;

552:   /* Create finite element */
553:   PetscFECreateDefault(dm, dim, dim, simplex, "def_", -1, &fe[0]);
554:   PetscObjectSetName((PetscObject) fe[0], "deformation");
555:   PetscFEGetQuadrature(fe[0], &q);
556:   PetscQuadratureGetOrder(q, &order);
557:   PetscFECreateDefault(dm, dim, 1, simplex, "pres_", order, &fe[1]);
558:   PetscObjectSetName((PetscObject) fe[1], "pressure");
559:   PetscFECreateDefault(dm, dim-1, dim, simplex, "bd_def_", order, &feBd[0]);
560:   PetscObjectSetName((PetscObject) feBd[0], "deformation");
561:   PetscFECreateDefault(dm, dim-1, 1, simplex, "bd_pres_", order, &feBd[1]);
562:   PetscObjectSetName((PetscObject) feBd[1], "pressure");

564:   PetscFECreateDefault(dm, dim, 1, simplex, "elastMat_", order, &feAux);
565:   PetscObjectSetName((PetscObject) feAux, "elasticityMaterial");
566: 

568:   /* Set discretization and boundary conditions for each mesh */
569:   while (cdm) {
570:     DMGetDS(cdm, &prob);
571:     PetscDSSetDiscretization(prob, 0, (PetscObject) fe[0]);
572:     PetscDSSetDiscretization(prob, 1, (PetscObject) fe[1]);
573:     PetscDSSetBdDiscretization(prob, 0, (PetscObject) feBd[0]);
574:     PetscDSSetBdDiscretization(prob, 1, (PetscObject) feBd[1]);
575:     SetupProblem(cdm, user);

577:     DMClone(cdm, &dmAux);
578:     DMGetCoordinateDM(cdm, &coordDM);
579:     DMSetCoordinateDM(dmAux, coordDM);
580:     DMGetDS(dmAux, &probAux);
581:     PetscDSSetDiscretization(probAux, 0, (PetscObject) feAux);
582:     PetscObjectCompose((PetscObject) cdm, "dmAux", (PetscObject) dmAux);
583:     SetupMaterial(cdm, dmAux, user);
584:     DMDestroy(&dmAux);

586:     const PetscInt Ncomp = dim;
587:     const PetscInt components[] = {0,1,2};
588:     const PetscInt Nfid = 1;
589:     const PetscInt fid[] = {1}; /* The fixed faces */
590:     const PetscInt Npid = 1;
591:     const PetscInt pid[] = {2}; /* The faces with pressure loading */
592:     DMAddBoundary(cdm, PETSC_TRUE, "fixed", "Faces", 0, Ncomp, components, (void (*)()) coordinates, Nfid, fid, user);
593:     DMAddBoundary(cdm, PETSC_FALSE, "pressure", "Faces", 0, Ncomp, components, NULL, Npid, pid, user);
594:     DMGetCoarseDM(cdm, &cdm);
595:   }

597:   {
598:     /* Set up the near null space (a.k.a. rigid body modes) that will be used by the multigrid preconditioner */
599:     DM           subdm;
600:     MatNullSpace nearNullSpace;
601:     PetscInt     fields = 0;
602:     PetscObject  deformation;
603:     DMCreateSubDM(dm, 1, &fields, NULL, &subdm);
604:     DMPlexCreateRigidBody(subdm, &nearNullSpace);
605:     DMGetField(dm, 0, &deformation);
606:     PetscObjectCompose(deformation, "nearnullspace", (PetscObject) nearNullSpace);
607:     DMDestroy(&subdm);
608:     MatNullSpaceDestroy(&nearNullSpace);
609:   }

611:   PetscFEDestroy(&fe[0]);
612:   PetscFEDestroy(&fe[1]);
613:   PetscFEDestroy(&feBd[0]);
614:   PetscFEDestroy(&feBd[1]);
615:   PetscFEDestroy(&feAux);
616:   return(0);
617: }


622: int main(int argc, char **argv)
623: {
624:   SNES           snes;                 /* nonlinear solver */
625:   DM             dm;                   /* problem definition */
626:   Vec            u,r;                  /* solution, residual vectors */
627:   Mat            A,J;                  /* Jacobian matrix */
628:   MatNullSpace   nullSpace;            /* May be necessary for pressure */
629:   AppCtx         user;                 /* user-defined work context */
630:   PetscInt       its;                  /* iterations for convergence */

633:   PetscInitialize(&argc, &argv, NULL, help);
634:   ProcessOptions(PETSC_COMM_WORLD, &user);
635:   SNESCreate(PETSC_COMM_WORLD, &snes);
636:   CreateMesh(PETSC_COMM_WORLD, &user, &dm);
637:   SNESSetDM(snes, dm);
638:   DMSetApplicationContext(dm, &user);

640:   SetupDiscretization(dm, &user);
641:   DMPlexCreateClosureIndex(dm, NULL);

643:   DMCreateGlobalVector(dm, &u);
644:   VecDuplicate(u, &r);

646:   DMSetMatType(dm,MATAIJ);
647:   DMCreateMatrix(dm, &J);
648:   A = J;

650:   DMPlexSetSNESLocalFEM(dm,&user,&user,&user);
651:   SNESSetJacobian(snes, A, J, NULL, NULL);

653:   SNESSetFromOptions(snes);

655:   PetscErrorCode (*initialGuess[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void* ctx) = {coordinates, zero_scalar};
656:   DMProjectFunction(dm, 0.0, initialGuess, NULL, INSERT_VALUES, u);
657:   if (user.showInitial) {DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);}

659:   if (user.runType == RUN_FULL) {
660:     if (user.debug) {
661:       PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
662:       VecView(u, PETSC_VIEWER_STDOUT_WORLD);
663:     }
664:     SNESSolve(snes, NULL, u);
665:     SNESGetIterationNumber(snes, &its);
666:     PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);
667:     if (user.showSolution) {
668:       PetscPrintf(PETSC_COMM_WORLD, "Solution\n");
669:       VecChop(u, 3.0e-9);
670:       VecView(u, PETSC_VIEWER_STDOUT_WORLD);
671:     }
672:   } else {
673:     PetscReal res = 0.0;

675:     /* Check initial guess */
676:     PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
677:     VecView(u, PETSC_VIEWER_STDOUT_WORLD);
678:     /* Check residual */
679:     SNESComputeFunction(snes, u, r);
680:     PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");
681:     VecChop(r, 1.0e-10);
682:     VecView(r, PETSC_VIEWER_STDOUT_WORLD);
683:     VecNorm(r, NORM_2, &res);
684:     PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);
685:     /* Check Jacobian */
686:     {
687:       Vec          b;
688:       PetscBool    isNull;

690:       SNESComputeJacobian(snes, u, A, A);
691:       VecDuplicate(u, &b);
692:       VecSet(r, 0.0);
693:       SNESComputeFunction(snes, r, b);
694:       MatMult(A, u, r);
695:       VecAXPY(r, 1.0, b);
696:       VecDestroy(&b);
697:       PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");
698:       VecChop(r, 1.0e-10);
699:       VecView(r, PETSC_VIEWER_STDOUT_WORLD);
700:       VecNorm(r, NORM_2, &res);
701:       PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);
702:     }
703:   }
704:   VecViewFromOptions(u, NULL, "-sol_vec_view");

706:   if (A != J) {MatDestroy(&A);}
707:   MatDestroy(&J);
708:   VecDestroy(&u);
709:   VecDestroy(&r);
710:   SNESDestroy(&snes);
711:   DMDestroy(&dm);
712:   PetscFinalize();
713:   return 0;
714: }