xref: /petsc/src/snes/tutorials/ex77.c (revision 9140fee14acbea959c6ed74f4836a1a89f708038)
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";
4 
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}
13 
14 Discretization:
15 
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.
19 
20 Field Data:
21 
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
25 
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}]
28 
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
32 
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}]
34 
35 Likewise, DMPlexVecSetClosure() takes data partitioned by field, and correctly
36 puts it into the Sieve ordering.
37 
38 */
39 
40 #include <petscdmplex.h>
41 #include <petscsnes.h>
42 #include <petscds.h>
43 
44 typedef enum {
45   RUN_FULL,
46   RUN_TEST
47 } RunType;
48 
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;
54 
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
61 
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 }
66 
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
76 
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 }
89 
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 }
95 
96 PetscErrorCode zero_vector(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
97 {
98   const PetscInt Ncomp = dim;
99 
100   PetscInt comp;
101   for (comp = 0; comp < Ncomp; ++comp) u[comp] = 0.0;
102   return PETSC_SUCCESS;
103 }
104 
105 PetscErrorCode coordinates(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
106 {
107   const PetscInt Ncomp = dim;
108 
109   PetscInt comp;
110   for (comp = 0; comp < Ncomp; ++comp) u[comp] = x[comp];
111   return PETSC_SUCCESS;
112 }
113 
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 }
120 
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 }
127 
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;
134 
135   Cof3D(cofu_x, u_x);
136   Det3D(&detu_x, u_x);
137   p += kappa * (detu_x - 1.0);
138 
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 }
144 
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;
151 
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;
157 
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;
162 
163       for (d1 = 0; d1 < dim; ++d1) {
164         for (d2 = 0; d2 < dim; ++d2) {
165           const PetscReal g = (d1 == d2) ? 1.0 : 0.0;
166 
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 }
173 
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;
180 
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 }
187 
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;
194 
195   Cof3D(cofu_x, u_x);
196   Det3D(&detu_x, u_x);
197   p /= detu_x;
198 
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 }
207 
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 }
214 
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;
219 
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 }
224 
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;
229 
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 }
234 
235 PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
236 {
237   const char *runTypes[2] = {"full", "test"};
238   PetscInt    run;
239 
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 }
253 
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;
272 
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;
281 
282       PetscCall(ISGetLocalSize(is, &Nf));
283       PetscCall(ISGetIndices(is, &faces));
284 
285       PetscCall(DMGetCoordinatesLocal(*dm, &coordinates));
286       PetscCall(DMGetCoordinateDM(*dm, &cdm));
287       PetscCall(DMGetLocalSection(cdm, &cs));
288 
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 }
311 
312 PetscErrorCode SetupProblem(DM dm, PetscInt dim, AppCtx *user)
313 {
314   PetscDS       ds;
315   PetscWeakForm wf;
316   DMLabel       label;
317   PetscInt      bd;
318 
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));
326 
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));
332 
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 }
336 
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];
342 
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 }
352 
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;
360 
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 }
370 
371 static PetscErrorCode SetupAuxDM(DM dm, PetscInt NfAux, PetscFE feAux[], AppCtx *user)
372 {
373   DM       dmAux, coordDM;
374   PetscInt f;
375 
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 }
388 
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;
396 
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]));
406 
407   PetscCall(PetscObjectSetName((PetscObject)fe[1], "pressure"));
408 
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]));
416 
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 }
433 
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 */
442 
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));
450 
451   PetscCall(SetupDiscretization(dm, &user));
452   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
453   PetscCall(SetupNearNullSpace(dm, &user));
454 
455   PetscCall(DMCreateGlobalVector(dm, &u));
456   PetscCall(PetscObjectSetName((PetscObject)u, "u"));
457   PetscCall(VecDuplicate(u, &r));
458 
459   PetscCall(DMSetMatType(dm, MATAIJ));
460   PetscCall(DMCreateMatrix(dm, &J));
461   A = J;
462 
463   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, &user));
464   PetscCall(SNESSetJacobian(snes, A, J, NULL, NULL));
465 
466   PetscCall(SNESSetFromOptions(snes));
467 
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   }
474 
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;
481 
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;
495 
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"));
511 
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 }
521 
522 /*TEST
523 
524   build:
525     requires: !complex
526 
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
536 
537     test:
538       suffix: 0
539       requires: !single
540       args: -dm_refine 2 \
541             -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4
542 
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
550 
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
558 
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
564 
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
572 
573 TEST*/
574