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:   PetscCall(DMCreate(comm, dm));
258:   PetscCall(DMSetType(*dm, DMPLEX));
259:   PetscCall(DMSetFromOptions(*dm));
260:   /* Label the faces (bit of a hack here, until it is properly implemented for simplices) */
261:   PetscCall(DMViewFromOptions(*dm, NULL, "-orig_dm_view"));
262:   {
263:     DM              cdm;
264:     DMLabel         label;
265:     IS              is;
266:     PetscInt        d, dim, b, f, Nf;
267:     const PetscInt *faces;
268:     PetscInt        csize;
269:     PetscScalar    *coords = NULL;
270:     PetscSection    cs;
271:     Vec             coordinates;

273:     PetscCall(DMGetDimension(*dm, &dim));
274:     PetscCall(DMCreateLabel(*dm, "boundary"));
275:     PetscCall(DMGetLabel(*dm, "boundary", &label));
276:     PetscCall(DMPlexMarkBoundaryFaces(*dm, 1, label));
277:     PetscCall(DMGetStratumIS(*dm, "boundary", 1, &is));
278:     if (is) {
279:       PetscReal faceCoord;
280:       PetscInt  v;

282:       PetscCall(ISGetLocalSize(is, &Nf));
283:       PetscCall(ISGetIndices(is, &faces));

285:       PetscCall(DMGetCoordinatesLocal(*dm, &coordinates));
286:       PetscCall(DMGetCoordinateDM(*dm, &cdm));
287:       PetscCall(DMGetLocalSection(cdm, &cs));

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

312: PetscErrorCode SetupProblem(DM dm, PetscInt dim, AppCtx *user)
313: {
314:   PetscDS       ds;
315:   PetscWeakForm wf;
316:   DMLabel       label;
317:   PetscInt      bd;

319:   PetscFunctionBeginUser;
320:   PetscCall(DMGetDS(dm, &ds));
321:   PetscCall(PetscDSSetResidual(ds, 0, NULL, f1_u_3d));
322:   PetscCall(PetscDSSetResidual(ds, 1, f0_p_3d, NULL));
323:   PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_uu_3d));
324:   PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_up_3d, NULL));
325:   PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_pu_3d, NULL, NULL));

327:   PetscCall(DMGetLabel(dm, "Faces", &label));
328:   PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "pressure", label, 0, NULL, 0, 0, NULL, NULL, NULL, user, &bd));
329:   PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
330:   PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, 1, 0, 0, 0, f0_bd_u_3d, 0, NULL));
331:   PetscCall(PetscWeakFormSetIndexBdJacobian(wf, label, 1, 0, 0, 0, 0, NULL, 0, g1_bd_uu_3d, 0, NULL, 0, NULL));

333:   PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed", label, 0, NULL, 0, 0, NULL, (void (*)(void))coordinates, NULL, user, NULL));
334:   PetscFunctionReturn(PETSC_SUCCESS);
335: }

337: PetscErrorCode SetupMaterial(DM dm, DM dmAux, AppCtx *user)
338: {
339:   PetscErrorCode (*matFuncs[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx) = {elasticityMaterial, wallPressure};
340:   Vec   A;
341:   void *ctxs[2];

343:   PetscFunctionBegin;
344:   ctxs[0] = user;
345:   ctxs[1] = user;
346:   PetscCall(DMCreateLocalVector(dmAux, &A));
347:   PetscCall(DMProjectFunctionLocal(dmAux, 0.0, matFuncs, ctxs, INSERT_ALL_VALUES, A));
348:   PetscCall(DMSetAuxiliaryVec(dm, NULL, 0, 0, A));
349:   PetscCall(VecDestroy(&A));
350:   PetscFunctionReturn(PETSC_SUCCESS);
351: }

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

361:   PetscFunctionBeginUser;
362:   PetscCall(DMCreateSubDM(dm, 1, &fields, NULL, &subdm));
363:   PetscCall(DMPlexCreateRigidBody(subdm, 0, &nearNullSpace));
364:   PetscCall(DMGetField(dm, 0, NULL, &deformation));
365:   PetscCall(PetscObjectCompose(deformation, "nearnullspace", (PetscObject)nearNullSpace));
366:   PetscCall(DMDestroy(&subdm));
367:   PetscCall(MatNullSpaceDestroy(&nearNullSpace));
368:   PetscFunctionReturn(PETSC_SUCCESS);
369: }

371: static PetscErrorCode SetupAuxDM(DM dm, PetscInt NfAux, PetscFE feAux[], AppCtx *user)
372: {
373:   DM       dmAux, coordDM;
374:   PetscInt f;

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

389: PetscErrorCode SetupDiscretization(DM dm, AppCtx *user)
390: {
391:   DM        cdm = dm;
392:   PetscFE   fe[2], feAux[2];
393:   PetscBool simplex;
394:   PetscInt  dim;
395:   MPI_Comm  comm;

397:   PetscFunctionBeginUser;
398:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
399:   PetscCall(DMGetDimension(dm, &dim));
400:   PetscCall(DMPlexIsSimplex(dm, &simplex));
401:   /* Create finite element */
402:   PetscCall(PetscFECreateDefault(comm, dim, dim, simplex, "def_", PETSC_DEFAULT, &fe[0]));
403:   PetscCall(PetscObjectSetName((PetscObject)fe[0], "deformation"));
404:   PetscCall(PetscFECreateDefault(comm, dim, 1, simplex, "pres_", PETSC_DEFAULT, &fe[1]));
405:   PetscCall(PetscFECopyQuadrature(fe[0], fe[1]));

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

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

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

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

443:   PetscFunctionBeginUser;
444:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
445:   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
446:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
447:   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
448:   PetscCall(SNESSetDM(snes, dm));
449:   PetscCall(DMSetApplicationContext(dm, &user));

451:   PetscCall(SetupDiscretization(dm, &user));
452:   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
453:   PetscCall(SetupNearNullSpace(dm, &user));

455:   PetscCall(DMCreateGlobalVector(dm, &u));
456:   PetscCall(PetscObjectSetName((PetscObject)u, "u"));
457:   PetscCall(VecDuplicate(u, &r));

459:   PetscCall(DMSetMatType(dm, MATAIJ));
460:   PetscCall(DMCreateMatrix(dm, &J));
461:   A = J;

463:   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, &user));
464:   PetscCall(SNESSetJacobian(snes, A, J, NULL, NULL));

466:   PetscCall(SNESSetFromOptions(snes));

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

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

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

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

512:   if (A != J) PetscCall(MatDestroy(&A));
513:   PetscCall(MatDestroy(&J));
514:   PetscCall(VecDestroy(&u));
515:   PetscCall(VecDestroy(&r));
516:   PetscCall(SNESDestroy(&snes));
517:   PetscCall(DMDestroy(&dm));
518:   PetscCall(PetscFinalize());
519:   return 0;
520: }

522: /*TEST

524:   build:
525:     requires: !complex

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

537:     test:
538:       suffix: 0
539:       requires: !single
540:       args: -dm_refine 2 \
541:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4

543:     test:
544:       suffix: 1
545:       requires: superlu_dist
546:       nsize: 2
547:       args: -dm_refine 0 -petscpartitioner_type simple \
548:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4
549:       timeoutfactor: 2

551:     test:
552:       suffix: 4
553:       requires: superlu_dist
554:       nsize: 2
555:       args: -dm_refine 0 -petscpartitioner_type simple \
556:             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4
557:       output_file: output/ex77_1.out

559:     test:
560:       suffix: 2
561:       requires: !single
562:       args: -dm_refine 2 \
563:             -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0

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

573: TEST*/