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*/