Actual source code: ex77.c

  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 {
 45:   RUN_FULL,
 46:   RUN_TEST
 47: } RunType;

 49: typedef struct {
 50:   RunType   runType; /* Whether to run tests, or solve the full problem */
 51:   PetscReal mu;      /* The shear modulus */
 52:   PetscReal p_wall;  /* The wall pressure */
 53: } AppCtx;

 55: #if 0
 56: static inline void Det2D(PetscReal *detJ, const PetscReal J[])
 57: {
 58:   *detJ = J[0]*J[3] - J[1]*J[2];
 59: }
 60: #endif

 62: static inline void Det3D(PetscReal *detJ, const PetscScalar J[])
 63: {
 64:   *detJ = PetscRealPart(J[0 * 3 + 0] * (J[1 * 3 + 1] * J[2 * 3 + 2] - J[1 * 3 + 2] * J[2 * 3 + 1]) + J[0 * 3 + 1] * (J[1 * 3 + 2] * J[2 * 3 + 0] - J[1 * 3 + 0] * J[2 * 3 + 2]) + J[0 * 3 + 2] * (J[1 * 3 + 0] * J[2 * 3 + 1] - J[1 * 3 + 1] * J[2 * 3 + 0]));
 65: }

 67: #if 0
 68: static inline void Cof2D(PetscReal C[], const PetscReal A[])
 69: {
 70:   C[0] =  A[3];
 71:   C[1] = -A[2];
 72:   C[2] = -A[1];
 73:   C[3] =  A[0];
 74: }
 75: #endif

 77: static inline void Cof3D(PetscReal C[], const PetscScalar A[])
 78: {
 79:   C[0 * 3 + 0] = PetscRealPart(A[1 * 3 + 1] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 1]);
 80:   C[0 * 3 + 1] = PetscRealPart(A[1 * 3 + 2] * A[2 * 3 + 0] - A[1 * 3 + 0] * A[2 * 3 + 2]);
 81:   C[0 * 3 + 2] = PetscRealPart(A[1 * 3 + 0] * A[2 * 3 + 1] - A[1 * 3 + 1] * A[2 * 3 + 0]);
 82:   C[1 * 3 + 0] = PetscRealPart(A[0 * 3 + 2] * A[2 * 3 + 1] - A[0 * 3 + 1] * A[2 * 3 + 2]);
 83:   C[1 * 3 + 1] = PetscRealPart(A[0 * 3 + 0] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 0]);
 84:   C[1 * 3 + 2] = PetscRealPart(A[0 * 3 + 1] * A[2 * 3 + 0] - A[0 * 3 + 0] * A[2 * 3 + 1]);
 85:   C[2 * 3 + 0] = PetscRealPart(A[0 * 3 + 1] * A[1 * 3 + 2] - A[0 * 3 + 2] * A[1 * 3 + 1]);
 86:   C[2 * 3 + 1] = PetscRealPart(A[0 * 3 + 2] * A[1 * 3 + 0] - A[0 * 3 + 0] * A[1 * 3 + 2]);
 87:   C[2 * 3 + 2] = PetscRealPart(A[0 * 3 + 0] * A[1 * 3 + 1] - A[0 * 3 + 1] * A[1 * 3 + 0]);
 88: }

 90: PetscErrorCode zero_scalar(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
 91: {
 92:   u[0] = 0.0;
 93:   return PETSC_SUCCESS;
 94: }

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

100:   PetscInt comp;
101:   for (comp = 0; comp < Ncomp; ++comp) u[comp] = 0.0;
102:   return PETSC_SUCCESS;
103: }

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

109:   PetscInt comp;
110:   for (comp = 0; comp < Ncomp; ++comp) u[comp] = x[comp];
111:   return PETSC_SUCCESS;
112: }

114: PetscErrorCode elasticityMaterial(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
115: {
116:   AppCtx *user = (AppCtx *)ctx;
117:   u[0]         = user->mu;
118:   return PETSC_SUCCESS;
119: }

121: PetscErrorCode wallPressure(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
122: {
123:   AppCtx *user = (AppCtx *)ctx;
124:   u[0]         = user->p_wall;
125:   return PETSC_SUCCESS;
126: }

128: void f1_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
129: {
130:   const PetscInt  Ncomp = dim;
131:   const PetscReal mu = PetscRealPart(a[0]), kappa = 3.0;
132:   PetscReal       cofu_x[9 /* Ncomp*dim */], detu_x, p = PetscRealPart(u[Ncomp]);
133:   PetscInt        comp, d;

135:   Cof3D(cofu_x, u_x);
136:   Det3D(&detu_x, u_x);
137:   p += kappa * (detu_x - 1.0);

139:   /* f1 is the first Piola-Kirchhoff tensor */
140:   for (comp = 0; comp < Ncomp; ++comp) {
141:     for (d = 0; d < dim; ++d) f1[comp * dim + d] = mu * u_x[comp * dim + d] + p * cofu_x[comp * dim + d];
142:   }
143: }

145: void g3_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
146: {
147:   const PetscInt  Ncomp = dim;
148:   const PetscReal mu = PetscRealPart(a[0]), kappa = 3.0;
149:   PetscReal       cofu_x[9 /* Ncomp*dim */], detu_x, pp, pm, p = PetscRealPart(u[Ncomp]);
150:   PetscInt        compI, compJ, d1, d2;

152:   Cof3D(cofu_x, u_x);
153:   Det3D(&detu_x, u_x);
154:   p += kappa * (detu_x - 1.0);
155:   pp = p / detu_x + kappa;
156:   pm = p / detu_x;

158:   /* 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} */
159:   for (compI = 0; compI < Ncomp; ++compI) {
160:     for (compJ = 0; compJ < Ncomp; ++compJ) {
161:       const PetscReal G = (compI == compJ) ? 1.0 : 0.0;

163:       for (d1 = 0; d1 < dim; ++d1) {
164:         for (d2 = 0; d2 < dim; ++d2) {
165:           const PetscReal g = (d1 == d2) ? 1.0 : 0.0;

167:           g3[((compI * Ncomp + compJ) * dim + d1) * dim + d2] = g * G * mu + pp * cofu_x[compI * dim + d1] * cofu_x[compJ * dim + d2] - pm * cofu_x[compI * dim + d2] * cofu_x[compJ * dim + d1];
168:         }
169:       }
170:     }
171:   }
172: }

174: void f0_bd_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
175: {
176:   const PetscInt    Ncomp = dim;
177:   const PetscScalar p     = a[aOff[1]];
178:   PetscReal         cofu_x[9 /* Ncomp*dim */];
179:   PetscInt          comp, d;

181:   Cof3D(cofu_x, u_x);
182:   for (comp = 0; comp < Ncomp; ++comp) {
183:     for (d = 0, f0[comp] = 0.0; d < dim; ++d) f0[comp] += cofu_x[comp * dim + d] * n[d];
184:     f0[comp] *= p;
185:   }
186: }

188: void g1_bd_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
189: {
190:   const PetscInt Ncomp = dim;
191:   PetscScalar    p     = a[aOff[1]];
192:   PetscReal      cofu_x[9 /* Ncomp*dim */], m[3 /* Ncomp */], detu_x;
193:   PetscInt       comp, compI, compJ, d;

195:   Cof3D(cofu_x, u_x);
196:   Det3D(&detu_x, u_x);
197:   p /= detu_x;

199:   for (comp = 0; comp < Ncomp; ++comp)
200:     for (d = 0, m[comp] = 0.0; d < dim; ++d) m[comp] += cofu_x[comp * dim + d] * n[d];
201:   for (compI = 0; compI < Ncomp; ++compI) {
202:     for (compJ = 0; compJ < Ncomp; ++compJ) {
203:       for (d = 0; d < dim; ++d) g1[(compI * Ncomp + compJ) * dim + d] = p * (m[compI] * cofu_x[compJ * dim + d] - cofu_x[compI * dim + d] * m[compJ]);
204:     }
205:   }
206: }

208: void f0_p_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
209: {
210:   PetscReal detu_x;
211:   Det3D(&detu_x, u_x);
212:   f0[0] = detu_x - 1.0;
213: }

215: void g1_pu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
216: {
217:   PetscReal cofu_x[9 /* Ncomp*dim */];
218:   PetscInt  compI, d;

220:   Cof3D(cofu_x, u_x);
221:   for (compI = 0; compI < dim; ++compI)
222:     for (d = 0; d < dim; ++d) g1[compI * dim + d] = cofu_x[compI * dim + d];
223: }

225: void g2_up_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
226: {
227:   PetscReal cofu_x[9 /* Ncomp*dim */];
228:   PetscInt  compI, d;

230:   Cof3D(cofu_x, u_x);
231:   for (compI = 0; compI < dim; ++compI)
232:     for (d = 0; d < dim; ++d) g2[compI * dim + d] = cofu_x[compI * dim + d];
233: }

235: PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
236: {
237:   const char *runTypes[2] = {"full", "test"};
238:   PetscInt    run;

240:   PetscFunctionBeginUser;
241:   options->runType = RUN_FULL;
242:   options->mu      = 1.0;
243:   options->p_wall  = 0.4;
244:   PetscOptionsBegin(comm, "", "Nonlinear elasticity problem options", "DMPLEX");
245:   run = options->runType;
246:   PetscCall(PetscOptionsEList("-run_type", "The run type", "ex77.c", runTypes, 2, runTypes[options->runType], &run, NULL));
247:   options->runType = (RunType)run;
248:   PetscCall(PetscOptionsReal("-shear_modulus", "The shear modulus", "ex77.c", options->mu, &options->mu, NULL));
249:   PetscCall(PetscOptionsReal("-wall_pressure", "The wall pressure", "ex77.c", options->p_wall, &options->p_wall, NULL));
250:   PetscOptionsEnd();
251:   PetscFunctionReturn(PETSC_SUCCESS);
252: }

254: PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
255: {
256:   PetscFunctionBeginUser;
257:   /* TODO The P1 coordinate space gives wrong results when compared to the affine version. Track this down */
258:   if (0) {
259:     PetscCall(DMPlexCreateBoxMesh(comm, 3, PETSC_TRUE, NULL, NULL, NULL, NULL, PETSC_TRUE, dm));
260:   } else {
261:     PetscCall(DMCreate(comm, dm));
262:     PetscCall(DMSetType(*dm, DMPLEX));
263:   }
264:   PetscCall(DMSetFromOptions(*dm));
265:   /* Label the faces (bit of a hack here, until it is properly implemented for simplices) */
266:   PetscCall(DMViewFromOptions(*dm, NULL, "-orig_dm_view"));
267:   {
268:     DM              cdm;
269:     DMLabel         label;
270:     IS              is;
271:     PetscInt        d, dim, b, f, Nf;
272:     const PetscInt *faces;
273:     PetscInt        csize;
274:     PetscScalar    *coords = NULL;
275:     PetscSection    cs;
276:     Vec             coordinates;

278:     PetscCall(DMGetDimension(*dm, &dim));
279:     PetscCall(DMCreateLabel(*dm, "boundary"));
280:     PetscCall(DMGetLabel(*dm, "boundary", &label));
281:     PetscCall(DMPlexMarkBoundaryFaces(*dm, 1, label));
282:     PetscCall(DMGetStratumIS(*dm, "boundary", 1, &is));
283:     if (is) {
284:       PetscReal faceCoord;
285:       PetscInt  v;

287:       PetscCall(ISGetLocalSize(is, &Nf));
288:       PetscCall(ISGetIndices(is, &faces));

290:       PetscCall(DMGetCoordinatesLocal(*dm, &coordinates));
291:       PetscCall(DMGetCoordinateDM(*dm, &cdm));
292:       PetscCall(DMGetLocalSection(cdm, &cs));

294:       /* Check for each boundary face if any component of its centroid is either 0.0 or 1.0 */
295:       for (f = 0; f < Nf; ++f) {
296:         PetscCall(DMPlexVecGetClosure(cdm, cs, coordinates, faces[f], &csize, &coords));
297:         /* Calculate mean coordinate vector */
298:         for (d = 0; d < dim; ++d) {
299:           const PetscInt Nv = csize / dim;
300:           faceCoord         = 0.0;
301:           for (v = 0; v < Nv; ++v) faceCoord += PetscRealPart(coords[v * dim + d]);
302:           faceCoord /= Nv;
303:           for (b = 0; b < 2; ++b) {
304:             if (PetscAbs(faceCoord - b * 1.0) < PETSC_SMALL) PetscCall(DMSetLabelValue(*dm, "Faces", faces[f], d * 2 + b + 1));
305:           }
306:         }
307:         PetscCall(DMPlexVecRestoreClosure(cdm, cs, coordinates, faces[f], &csize, &coords));
308:       }
309:       PetscCall(ISRestoreIndices(is, &faces));
310:     }
311:     PetscCall(ISDestroy(&is));
312:   }
313:   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
314:   PetscFunctionReturn(PETSC_SUCCESS);
315: }

317: PetscErrorCode SetupProblem(DM dm, PetscInt dim, AppCtx *user)
318: {
319:   PetscDS       ds;
320:   PetscWeakForm wf;
321:   DMLabel       label;
322:   PetscInt      bd;

324:   PetscFunctionBeginUser;
325:   PetscCall(DMGetDS(dm, &ds));
326:   PetscCall(PetscDSSetResidual(ds, 0, NULL, f1_u_3d));
327:   PetscCall(PetscDSSetResidual(ds, 1, f0_p_3d, NULL));
328:   PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_uu_3d));
329:   PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_up_3d, NULL));
330:   PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_pu_3d, NULL, NULL));

332:   PetscCall(DMGetLabel(dm, "Faces", &label));
333:   PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "pressure", label, 0, NULL, 0, 0, NULL, NULL, NULL, user, &bd));
334:   PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
335:   PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, 1, 0, 0, 0, f0_bd_u_3d, 0, NULL));
336:   PetscCall(PetscWeakFormSetIndexBdJacobian(wf, label, 1, 0, 0, 0, 0, NULL, 0, g1_bd_uu_3d, 0, NULL, 0, NULL));

338:   PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed", label, 0, NULL, 0, 0, NULL, (void (*)(void))coordinates, NULL, user, NULL));
339:   PetscFunctionReturn(PETSC_SUCCESS);
340: }

342: PetscErrorCode SetupMaterial(DM dm, DM dmAux, AppCtx *user)
343: {
344:   PetscErrorCode (*matFuncs[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx) = {elasticityMaterial, wallPressure};
345:   Vec   A;
346:   void *ctxs[2];

348:   PetscFunctionBegin;
349:   ctxs[0] = user;
350:   ctxs[1] = user;
351:   PetscCall(DMCreateLocalVector(dmAux, &A));
352:   PetscCall(DMProjectFunctionLocal(dmAux, 0.0, matFuncs, ctxs, INSERT_ALL_VALUES, A));
353:   PetscCall(DMSetAuxiliaryVec(dm, NULL, 0, 0, A));
354:   PetscCall(VecDestroy(&A));
355:   PetscFunctionReturn(PETSC_SUCCESS);
356: }

358: PetscErrorCode SetupNearNullSpace(DM dm, AppCtx *user)
359: {
360:   /* Set up the near null space (a.k.a. rigid body modes) that will be used by the multigrid preconditioner */
361:   DM           subdm;
362:   MatNullSpace nearNullSpace;
363:   PetscInt     fields = 0;
364:   PetscObject  deformation;

366:   PetscFunctionBeginUser;
367:   PetscCall(DMCreateSubDM(dm, 1, &fields, NULL, &subdm));
368:   PetscCall(DMPlexCreateRigidBody(subdm, 0, &nearNullSpace));
369:   PetscCall(DMGetField(dm, 0, NULL, &deformation));
370:   PetscCall(PetscObjectCompose(deformation, "nearnullspace", (PetscObject)nearNullSpace));
371:   PetscCall(DMDestroy(&subdm));
372:   PetscCall(MatNullSpaceDestroy(&nearNullSpace));
373:   PetscFunctionReturn(PETSC_SUCCESS);
374: }

376: static PetscErrorCode SetupAuxDM(DM dm, PetscInt NfAux, PetscFE feAux[], AppCtx *user)
377: {
378:   DM       dmAux, coordDM;
379:   PetscInt f;

381:   PetscFunctionBegin;
382:   /* MUST call DMGetCoordinateDM() in order to get p4est setup if present */
383:   PetscCall(DMGetCoordinateDM(dm, &coordDM));
384:   if (!feAux) PetscFunctionReturn(PETSC_SUCCESS);
385:   PetscCall(DMClone(dm, &dmAux));
386:   PetscCall(DMSetCoordinateDM(dmAux, coordDM));
387:   for (f = 0; f < NfAux; ++f) PetscCall(DMSetField(dmAux, f, NULL, (PetscObject)feAux[f]));
388:   PetscCall(DMCreateDS(dmAux));
389:   PetscCall(SetupMaterial(dm, dmAux, user));
390:   PetscCall(DMDestroy(&dmAux));
391:   PetscFunctionReturn(PETSC_SUCCESS);
392: }

394: PetscErrorCode SetupDiscretization(DM dm, AppCtx *user)
395: {
396:   DM        cdm = dm;
397:   PetscFE   fe[2], feAux[2];
398:   PetscBool simplex;
399:   PetscInt  dim;
400:   MPI_Comm  comm;

402:   PetscFunctionBeginUser;
403:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
404:   PetscCall(DMGetDimension(dm, &dim));
405:   PetscCall(DMPlexIsSimplex(dm, &simplex));
406:   /* Create finite element */
407:   PetscCall(PetscFECreateDefault(comm, dim, dim, simplex, "def_", PETSC_DEFAULT, &fe[0]));
408:   PetscCall(PetscObjectSetName((PetscObject)fe[0], "deformation"));
409:   PetscCall(PetscFECreateDefault(comm, dim, 1, simplex, "pres_", PETSC_DEFAULT, &fe[1]));
410:   PetscCall(PetscFECopyQuadrature(fe[0], fe[1]));

412:   PetscCall(PetscObjectSetName((PetscObject)fe[1], "pressure"));

414:   PetscCall(PetscFECreateDefault(comm, dim, 1, simplex, "elastMat_", PETSC_DEFAULT, &feAux[0]));
415:   PetscCall(PetscObjectSetName((PetscObject)feAux[0], "elasticityMaterial"));
416:   PetscCall(PetscFECopyQuadrature(fe[0], feAux[0]));
417:   /* It is not yet possible to define a field on a submesh (e.g. a boundary), so we will use a normal finite element */
418:   PetscCall(PetscFECreateDefault(comm, dim, 1, simplex, "wall_pres_", PETSC_DEFAULT, &feAux[1]));
419:   PetscCall(PetscObjectSetName((PetscObject)feAux[1], "wall_pressure"));
420:   PetscCall(PetscFECopyQuadrature(fe[0], feAux[1]));

422:   /* Set discretization and boundary conditions for each mesh */
423:   PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe[0]));
424:   PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fe[1]));
425:   PetscCall(DMCreateDS(dm));
426:   PetscCall(SetupProblem(dm, dim, user));
427:   while (cdm) {
428:     PetscCall(SetupAuxDM(cdm, 2, feAux, user));
429:     PetscCall(DMCopyDisc(dm, cdm));
430:     PetscCall(DMGetCoarseDM(cdm, &cdm));
431:   }
432:   PetscCall(PetscFEDestroy(&fe[0]));
433:   PetscCall(PetscFEDestroy(&fe[1]));
434:   PetscCall(PetscFEDestroy(&feAux[0]));
435:   PetscCall(PetscFEDestroy(&feAux[1]));
436:   PetscFunctionReturn(PETSC_SUCCESS);
437: }

439: int main(int argc, char **argv)
440: {
441:   SNES     snes; /* nonlinear solver */
442:   DM       dm;   /* problem definition */
443:   Vec      u, r; /* solution, residual vectors */
444:   Mat      A, J; /* Jacobian matrix */
445:   AppCtx   user; /* user-defined work context */
446:   PetscInt its;  /* iterations for convergence */

448:   PetscFunctionBeginUser;
449:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
450:   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
451:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
452:   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
453:   PetscCall(SNESSetDM(snes, dm));
454:   PetscCall(DMSetApplicationContext(dm, &user));

456:   PetscCall(SetupDiscretization(dm, &user));
457:   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
458:   PetscCall(SetupNearNullSpace(dm, &user));

460:   PetscCall(DMCreateGlobalVector(dm, &u));
461:   PetscCall(VecDuplicate(u, &r));

463:   PetscCall(DMSetMatType(dm, MATAIJ));
464:   PetscCall(DMCreateMatrix(dm, &J));
465:   A = J;

467:   PetscCall(DMPlexSetSNESLocalFEM(dm, &user, &user, &user));
468:   PetscCall(SNESSetJacobian(snes, A, J, NULL, NULL));

470:   PetscCall(SNESSetFromOptions(snes));

472:   {
473:     PetscErrorCode (*initialGuess[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
474:     initialGuess[0] = coordinates;
475:     initialGuess[1] = zero_scalar;
476:     PetscCall(DMProjectFunction(dm, 0.0, initialGuess, NULL, INSERT_VALUES, u));
477:   }

479:   if (user.runType == RUN_FULL) {
480:     PetscCall(SNESSolve(snes, NULL, u));
481:     PetscCall(SNESGetIterationNumber(snes, &its));
482:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %" PetscInt_FMT "\n", its));
483:   } else {
484:     PetscReal res = 0.0;

486:     /* Check initial guess */
487:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n"));
488:     PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD));
489:     /* Check residual */
490:     PetscCall(SNESComputeFunction(snes, u, r));
491:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n"));
492:     PetscCall(VecChop(r, 1.0e-10));
493:     PetscCall(VecView(r, PETSC_VIEWER_STDOUT_WORLD));
494:     PetscCall(VecNorm(r, NORM_2, &res));
495:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", (double)res));
496:     /* Check Jacobian */
497:     {
498:       Vec b;

500:       PetscCall(SNESComputeJacobian(snes, u, A, A));
501:       PetscCall(VecDuplicate(u, &b));
502:       PetscCall(VecSet(r, 0.0));
503:       PetscCall(SNESComputeFunction(snes, r, b));
504:       PetscCall(MatMult(A, u, r));
505:       PetscCall(VecAXPY(r, 1.0, b));
506:       PetscCall(VecDestroy(&b));
507:       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n"));
508:       PetscCall(VecChop(r, 1.0e-10));
509:       PetscCall(VecView(r, PETSC_VIEWER_STDOUT_WORLD));
510:       PetscCall(VecNorm(r, NORM_2, &res));
511:       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", (double)res));
512:     }
513:   }
514:   PetscCall(VecViewFromOptions(u, NULL, "-sol_vec_view"));

516:   if (A != J) PetscCall(MatDestroy(&A));
517:   PetscCall(MatDestroy(&J));
518:   PetscCall(VecDestroy(&u));
519:   PetscCall(VecDestroy(&r));
520:   PetscCall(SNESDestroy(&snes));
521:   PetscCall(DMDestroy(&dm));
522:   PetscCall(PetscFinalize());
523:   return 0;
524: }

526: /*TEST

528:   build:
529:     requires: !complex

531:   testset:
532:     requires: ctetgen
533:     args: -run_type full -dm_plex_dim 3 \
534:           -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 \
535:           -snes_rtol 1e-05 -snes_monitor_short -snes_converged_reason \
536:           -ksp_type fgmres -ksp_rtol 1e-10 -ksp_monitor_short -ksp_converged_reason \
537:           -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper \
538:             -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu \
539:             -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi

541:     test:
542:       suffix: 0
543:       requires: !single
544:       args: -dm_refine 2 \
545:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4

547:     test:
548:       suffix: 1
549:       requires: superlu_dist
550:       nsize: 2
551:       args: -dm_refine 0 -petscpartitioner_type simple \
552:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4
553:       timeoutfactor: 2

555:     test:
556:       suffix: 4
557:       requires: superlu_dist
558:       nsize: 2
559:       args: -dm_refine 0 -petscpartitioner_type simple \
560:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4
561:       output_file: output/ex77_1.out

563:     test:
564:       suffix: 2
565:       requires: !single
566:       args: -dm_refine 2 \
567:             -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0

569:     test:
570:       suffix: 2_par
571:       requires: superlu_dist !single
572:       nsize: 4
573:       args: -dm_refine 2 -petscpartitioner_type simple \
574:             -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0
575:       output_file: output/ex77_2.out

577: TEST*/