Actual source code: ex77.c
petsc-3.14.6 2021-03-30
1: static char help[] = "Nonlinear elasticity problem in 3d with simplicial finite elements.\n\
2: We solve a nonlinear elasticity problem, modelled as an incompressible Neo-Hookean solid, \n\
3: with pressure loading in a rectangular domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\n\n";
5: /*
6: Nonlinear elasticity problem, which we discretize using the finite
7: element method on an unstructured mesh. This uses both Dirichlet boundary conditions (fixed faces)
8: and nonlinear Neumann boundary conditions (pressure loading).
9: The Lagrangian density (modulo boundary conditions) for this problem is given by
10: \begin{equation}
11: \frac{\mu}{2} (\mathrm{Tr}{C}-3) + J p + \frac{\kappa}{2} (J-1).
12: \end{equation}
14: Discretization:
16: We use PetscFE to generate a tabulation of the finite element basis functions
17: at quadrature points. We can currently generate an arbitrary order Lagrange
18: element.
20: Field Data:
22: DMPLEX data is organized by point, and the closure operation just stacks up the
23: data from each sieve point in the closure. Thus, for a P_2-P_1 Stokes element, we
24: have
26: cl{e} = {f e_0 e_1 e_2 v_0 v_1 v_2}
27: x = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} p_{v_0} u_{v_1} v_{v_1} p_{v_1} u_{v_2} v_{v_2} p_{v_2}]
29: The problem here is that we would like to loop over each field separately for
30: integration. Therefore, the closure visitor in DMPlexVecGetClosure() reorders
31: the data so that each field is contiguous
33: x' = [u_{e_0} v_{e_0} u_{e_1} v_{e_1} u_{e_2} v_{e_2} u_{v_0} v_{v_0} u_{v_1} v_{v_1} u_{v_2} v_{v_2} p_{v_0} p_{v_1} p_{v_2}]
35: Likewise, DMPlexVecSetClosure() takes data partitioned by field, and correctly
36: puts it into the Sieve ordering.
38: */
40: #include <petscdmplex.h>
41: #include <petscsnes.h>
42: #include <petscds.h>
44: typedef enum {RUN_FULL, RUN_TEST} RunType;
46: typedef struct {
47: PetscInt debug; /* The debugging level */
48: RunType runType; /* Whether to run tests, or solve the full problem */
49: PetscLogEvent createMeshEvent;
50: PetscBool showInitial, showSolution;
51: /* Domain and mesh definition */
52: PetscInt dim; /* The topological mesh dimension */
53: PetscBool interpolate; /* Generate intermediate mesh elements */
54: PetscBool simplex; /* Use simplices or tensor product cells */
55: PetscReal refinementLimit; /* The largest allowable cell volume */
56: PetscBool testPartition; /* Use a fixed partitioning for testing */
57: PetscReal mu; /* The shear modulus */
58: PetscReal p_wall; /* The wall pressure */
59: } AppCtx;
61: #if 0
62: PETSC_STATIC_INLINE void Det2D(PetscReal *detJ, const PetscReal J[])
63: {
64: *detJ = J[0]*J[3] - J[1]*J[2];
65: }
66: #endif
68: PETSC_STATIC_INLINE void Det3D(PetscReal *detJ, const PetscScalar J[])
69: {
70: *detJ = PetscRealPart(J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
71: J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
72: J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
73: }
75: #if 0
76: PETSC_STATIC_INLINE void Cof2D(PetscReal C[], const PetscReal A[])
77: {
78: C[0] = A[3];
79: C[1] = -A[2];
80: C[2] = -A[1];
81: C[3] = A[0];
82: }
83: #endif
85: PETSC_STATIC_INLINE void Cof3D(PetscReal C[], const PetscScalar A[])
86: {
87: C[0*3+0] = PetscRealPart(A[1*3+1]*A[2*3+2] - A[1*3+2]*A[2*3+1]);
88: C[0*3+1] = PetscRealPart(A[1*3+2]*A[2*3+0] - A[1*3+0]*A[2*3+2]);
89: C[0*3+2] = PetscRealPart(A[1*3+0]*A[2*3+1] - A[1*3+1]*A[2*3+0]);
90: C[1*3+0] = PetscRealPart(A[0*3+2]*A[2*3+1] - A[0*3+1]*A[2*3+2]);
91: C[1*3+1] = PetscRealPart(A[0*3+0]*A[2*3+2] - A[0*3+2]*A[2*3+0]);
92: C[1*3+2] = PetscRealPart(A[0*3+1]*A[2*3+0] - A[0*3+0]*A[2*3+1]);
93: C[2*3+0] = PetscRealPart(A[0*3+1]*A[1*3+2] - A[0*3+2]*A[1*3+1]);
94: C[2*3+1] = PetscRealPart(A[0*3+2]*A[1*3+0] - A[0*3+0]*A[1*3+2]);
95: C[2*3+2] = PetscRealPart(A[0*3+0]*A[1*3+1] - A[0*3+1]*A[1*3+0]);
96: }
98: PetscErrorCode zero_scalar(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
99: {
100: u[0] = 0.0;
101: return 0;
102: }
104: PetscErrorCode zero_vector(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
105: {
106: const PetscInt Ncomp = dim;
108: PetscInt comp;
109: for (comp = 0; comp < Ncomp; ++comp) u[comp] = 0.0;
110: return 0;
111: }
113: PetscErrorCode coordinates(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
114: {
115: const PetscInt Ncomp = dim;
117: PetscInt comp;
118: for (comp = 0; comp < Ncomp; ++comp) u[comp] = x[comp];
119: return 0;
120: }
122: PetscErrorCode elasticityMaterial(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
123: {
124: AppCtx *user = (AppCtx *) ctx;
125: u[0] = user->mu;
126: return 0;
127: }
129: PetscErrorCode wallPressure(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
130: {
131: AppCtx *user = (AppCtx *) ctx;
132: u[0] = user->p_wall;
133: return 0;
134: }
136: void f1_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
137: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
138: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
139: PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
140: {
141: const PetscInt Ncomp = dim;
142: const PetscReal mu = PetscRealPart(a[0]), kappa = 3.0;
143: PetscReal cofu_x[9/*Ncomp*dim*/], detu_x, p = PetscRealPart(u[Ncomp]);
144: PetscInt comp, d;
146: Cof3D(cofu_x, u_x);
147: Det3D(&detu_x, u_x);
148: p += kappa * (detu_x - 1.0);
150: /* f1 is the first Piola-Kirchhoff tensor */
151: for (comp = 0; comp < Ncomp; ++comp) {
152: for (d = 0; d < dim; ++d) {
153: f1[comp*dim+d] = mu * u_x[comp*dim+d] + p * cofu_x[comp*dim+d];
154: }
155: }
156: }
158: void g3_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
159: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
160: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
161: PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
162: {
163: const PetscInt Ncomp = dim;
164: const PetscReal mu = PetscRealPart(a[0]), kappa = 3.0;
165: PetscReal cofu_x[9/*Ncomp*dim*/], detu_x, pp, pm, p = PetscRealPart(u[Ncomp]);
166: PetscInt compI, compJ, d1, d2;
168: Cof3D(cofu_x, u_x);
169: Det3D(&detu_x, u_x);
170: p += kappa * (detu_x - 1.0);
171: pp = p/detu_x + kappa;
172: pm = p/detu_x;
174: /* 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} */
175: for (compI = 0; compI < Ncomp; ++compI) {
176: for (compJ = 0; compJ < Ncomp; ++compJ) {
177: const PetscReal G = (compI == compJ) ? 1.0 : 0.0;
179: for (d1 = 0; d1 < dim; ++d1) {
180: for (d2 = 0; d2 < dim; ++d2) {
181: const PetscReal g = (d1 == d2) ? 1.0 : 0.0;
183: 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];
184: }
185: }
186: }
187: }
188: }
190: void f0_bd_u_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
191: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
192: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
193: PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
194: {
195: const PetscInt Ncomp = dim;
196: const PetscScalar p = a[aOff[1]];
197: PetscReal cofu_x[9/*Ncomp*dim*/];
198: PetscInt comp, d;
200: Cof3D(cofu_x, u_x);
201: for (comp = 0; comp < Ncomp; ++comp) {
202: for (d = 0, f0[comp] = 0.0; d < dim; ++d) f0[comp] += cofu_x[comp*dim+d] * n[d];
203: f0[comp] *= p;
204: }
205: }
207: void g1_bd_uu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
208: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
209: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
210: PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
211: {
212: const PetscInt Ncomp = dim;
213: PetscScalar p = a[aOff[1]];
214: PetscReal cofu_x[9/*Ncomp*dim*/], m[3/*Ncomp*/], detu_x;
215: PetscInt comp, compI, compJ, d;
217: Cof3D(cofu_x, u_x);
218: Det3D(&detu_x, u_x);
219: p /= detu_x;
221: for (comp = 0; comp < Ncomp; ++comp) for (d = 0, m[comp] = 0.0; d < dim; ++d) m[comp] += cofu_x[comp*dim+d] * n[d];
222: for (compI = 0; compI < Ncomp; ++compI) {
223: for (compJ = 0; compJ < Ncomp; ++compJ) {
224: for (d = 0; d < dim; ++d) {
225: g1[(compI*Ncomp+compJ)*dim+d] = p * (m[compI] * cofu_x[compJ*dim+d] - cofu_x[compI*dim+d] * m[compJ]);
226: }
227: }
228: }
229: }
231: void f0_p_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
232: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
233: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
234: PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
235: {
236: PetscReal detu_x;
237: Det3D(&detu_x, u_x);
238: f0[0] = detu_x - 1.0;
239: }
241: void g1_pu_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
242: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
243: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
244: PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
245: {
246: PetscReal cofu_x[9/*Ncomp*dim*/];
247: PetscInt compI, d;
249: Cof3D(cofu_x, u_x);
250: for (compI = 0; compI < dim; ++compI)
251: for (d = 0; d < dim; ++d) g1[compI*dim+d] = cofu_x[compI*dim+d];
252: }
254: void g2_up_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux,
255: const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
256: const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
257: PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
258: {
259: PetscReal cofu_x[9/*Ncomp*dim*/];
260: PetscInt compI, d;
262: Cof3D(cofu_x, u_x);
263: for (compI = 0; compI < dim; ++compI)
264: for (d = 0; d < dim; ++d) g2[compI*dim+d] = cofu_x[compI*dim+d];
265: }
267: PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
268: {
269: const char *runTypes[2] = {"full", "test"};
270: PetscInt run;
274: options->debug = 0;
275: options->runType = RUN_FULL;
276: options->dim = 3;
277: options->interpolate = PETSC_FALSE;
278: options->simplex = PETSC_TRUE;
279: options->refinementLimit = 0.0;
280: options->mu = 1.0;
281: options->p_wall = 0.4;
282: options->testPartition = PETSC_FALSE;
283: options->showInitial = PETSC_FALSE;
284: options->showSolution = PETSC_TRUE;
286: PetscOptionsBegin(comm, "", "Nonlinear elasticity problem options", "DMPLEX");
287: PetscOptionsInt("-debug", "The debugging level", "ex77.c", options->debug, &options->debug, NULL);
288: run = options->runType;
289: PetscOptionsEList("-run_type", "The run type", "ex77.c", runTypes, 2, runTypes[options->runType], &run, NULL);
291: options->runType = (RunType) run;
293: PetscOptionsInt("-dim", "The topological mesh dimension", "ex77.c", options->dim, &options->dim, NULL);
294: PetscOptionsBool("-interpolate", "Generate intermediate mesh elements", "ex77.c", options->interpolate, &options->interpolate, NULL);
295: PetscOptionsBool("-simplex", "Use simplices or tensor product cells", "ex77.c", options->simplex, &options->simplex, NULL);
296: PetscOptionsReal("-refinement_limit", "The largest allowable cell volume", "ex77.c", options->refinementLimit, &options->refinementLimit, NULL);
297: PetscOptionsBool("-test_partition", "Use a fixed partition for testing", "ex77.c", options->testPartition, &options->testPartition, NULL);
298: PetscOptionsReal("-shear_modulus", "The shear modulus", "ex77.c", options->mu, &options->mu, NULL);
299: PetscOptionsReal("-wall_pressure", "The wall pressure", "ex77.c", options->p_wall, &options->p_wall, NULL);
301: PetscOptionsBool("-show_initial", "Output the initial guess for verification", "ex77.c", options->showInitial, &options->showInitial, NULL);
302: PetscOptionsBool("-show_solution", "Output the solution for verification", "ex77.c", options->showSolution, &options->showSolution, NULL);
303: PetscOptionsEnd();
305: PetscLogEventRegister("CreateMesh", DM_CLASSID, &options->createMeshEvent);
306: return(0);
307: }
309: PetscErrorCode DMVecViewLocal(DM dm, Vec v, PetscViewer viewer)
310: {
311: Vec lv;
312: PetscInt p;
313: PetscMPIInt rank, size;
317: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
318: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
319: DMGetLocalVector(dm, &lv);
320: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, lv);
321: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, lv);
322: PetscPrintf(PETSC_COMM_WORLD, "Local function\n");
323: for (p = 0; p < size; ++p) {
324: if (p == rank) {VecView(lv, PETSC_VIEWER_STDOUT_SELF);}
325: PetscBarrier((PetscObject) dm);
326: }
327: DMRestoreLocalVector(dm, &lv);
328: return(0);
329: }
331: PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
332: {
333: PetscInt dim = user->dim;
334: PetscBool interpolate = user->interpolate;
335: PetscReal refinementLimit = user->refinementLimit;
336: const PetscInt cells[3] = {3, 3, 3};
340: PetscLogEventBegin(user->createMeshEvent,0,0,0,0);
341: DMPlexCreateBoxMesh(comm, dim, user->simplex, user->simplex ? NULL : cells, NULL, NULL, NULL, interpolate, dm);
342: /* Label the faces (bit of a hack here, until it is properly implemented for simplices) */
343: {
344: DM cdm;
345: DMLabel label;
346: IS is;
347: PetscInt d, dim = user->dim, b, f, Nf;
348: const PetscInt *faces;
349: PetscInt csize;
350: PetscScalar *coords = NULL;
351: PetscSection cs;
352: Vec coordinates ;
354: DMCreateLabel(*dm, "boundary");
355: DMGetLabel(*dm, "boundary", &label);
356: DMPlexMarkBoundaryFaces(*dm, 1, label);
357: DMGetStratumIS(*dm, "boundary", 1, &is);
358: if (is) {
359: PetscReal faceCoord;
360: PetscInt v;
362: ISGetLocalSize(is, &Nf);
363: ISGetIndices(is, &faces);
365: DMGetCoordinatesLocal(*dm, &coordinates);
366: DMGetCoordinateDM(*dm, &cdm);
367: DMGetLocalSection(cdm, &cs);
369: /* Check for each boundary face if any component of its centroid is either 0.0 or 1.0 */
370: for (f = 0; f < Nf; ++f) {
371: DMPlexVecGetClosure(cdm, cs, coordinates, faces[f], &csize, &coords);
372: /* Calculate mean coordinate vector */
373: for (d = 0; d < dim; ++d) {
374: const PetscInt Nv = csize/dim;
375: faceCoord = 0.0;
376: for (v = 0; v < Nv; ++v) faceCoord += PetscRealPart(coords[v*dim+d]);
377: faceCoord /= Nv;
378: for (b = 0; b < 2; ++b) {
379: if (PetscAbs(faceCoord - b*1.0) < PETSC_SMALL) {
380: DMSetLabelValue(*dm, "Faces", faces[f], d*2+b+1);
381: }
382: }
383: }
384: DMPlexVecRestoreClosure(cdm, cs, coordinates, faces[f], &csize, &coords);
385: }
386: ISRestoreIndices(is, &faces);
387: }
388: ISDestroy(&is);
389: }
390: {
391: DM refinedMesh = NULL;
392: DM distributedMesh = NULL;
393: PetscPartitioner part;
395: DMPlexGetPartitioner(*dm, &part);
397: /* Refine mesh using a volume constraint */
398: DMPlexSetRefinementLimit(*dm, refinementLimit);
399: if (user->simplex) {DMRefine(*dm, comm, &refinedMesh);}
400: if (refinedMesh) {
401: DMDestroy(dm);
402: *dm = refinedMesh;
403: }
404: /* Setup test partitioning */
405: if (user->testPartition) {
406: PetscInt triSizes_n2[2] = {4, 4};
407: PetscInt triPoints_n2[8] = {3, 5, 6, 7, 0, 1, 2, 4};
408: PetscInt triSizes_n3[3] = {2, 3, 3};
409: PetscInt triPoints_n3[8] = {3, 5, 1, 6, 7, 0, 2, 4};
410: PetscInt triSizes_n5[5] = {1, 2, 2, 1, 2};
411: PetscInt triPoints_n5[8] = {3, 5, 6, 4, 7, 0, 1, 2};
412: PetscInt triSizes_ref_n2[2] = {8, 8};
413: PetscInt triPoints_ref_n2[16] = {1, 5, 6, 7, 10, 11, 14, 15, 0, 2, 3, 4, 8, 9, 12, 13};
414: PetscInt triSizes_ref_n3[3] = {5, 6, 5};
415: PetscInt triPoints_ref_n3[16] = {1, 7, 10, 14, 15, 2, 6, 8, 11, 12, 13, 0, 3, 4, 5, 9};
416: PetscInt triSizes_ref_n5[5] = {3, 4, 3, 3, 3};
417: PetscInt triPoints_ref_n5[16] = {1, 7, 10, 2, 11, 13, 14, 5, 6, 15, 0, 8, 9, 3, 4, 12};
418: PetscInt tetSizes_n2[2] = {3, 3};
419: PetscInt tetPoints_n2[6] = {1, 2, 3, 0, 4, 5};
420: const PetscInt *sizes = NULL;
421: const PetscInt *points = NULL;
422: PetscInt cEnd;
423: PetscMPIInt rank, size;
425: MPI_Comm_rank(comm, &rank);
426: MPI_Comm_size(comm, &size);
427: DMPlexGetHeightStratum(*dm, 0, NULL, &cEnd);
428: if (!rank) {
429: if (dim == 2 && user->simplex && size == 2 && cEnd == 8) {
430: sizes = triSizes_n2; points = triPoints_n2;
431: } else if (dim == 2 && user->simplex && size == 3 && cEnd == 8) {
432: sizes = triSizes_n3; points = triPoints_n3;
433: } else if (dim == 2 && user->simplex && size == 5 && cEnd == 8) {
434: sizes = triSizes_n5; points = triPoints_n5;
435: } else if (dim == 2 && user->simplex && size == 2 && cEnd == 16) {
436: sizes = triSizes_ref_n2; points = triPoints_ref_n2;
437: } else if (dim == 2 && user->simplex && size == 3 && cEnd == 16) {
438: sizes = triSizes_ref_n3; points = triPoints_ref_n3;
439: } else if (dim == 2 && user->simplex && size == 5 && cEnd == 16) {
440: sizes = triSizes_ref_n5; points = triPoints_ref_n5;
441: } else if (dim == 3 && user->simplex && size == 2 && cEnd == 6) {
442: sizes = tetSizes_n2; points = tetPoints_n2;
443: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "No stored partition matching run parameters");
444: }
445: PetscPartitionerSetType(part, PETSCPARTITIONERSHELL);
446: PetscPartitionerShellSetPartition(part, size, sizes, points);
447: } else {
448: PetscPartitionerSetFromOptions(part);
449: }
450: /* Distribute mesh over processes */
451: DMPlexDistribute(*dm, 0, NULL, &distributedMesh);
452: if (distributedMesh) {
453: DMDestroy(dm);
454: *dm = distributedMesh;
455: }
456: }
457: DMSetFromOptions(*dm);
458: DMViewFromOptions(*dm, NULL, "-dm_view");
460: PetscLogEventEnd(user->createMeshEvent,0,0,0,0);
461: return(0);
462: }
464: PetscErrorCode SetupProblem(DM dm, PetscInt dim, AppCtx *user)
465: {
466: PetscDS prob;
470: DMGetDS(dm, &prob);
471: PetscDSSetResidual(prob, 0, NULL, f1_u_3d);
472: PetscDSSetResidual(prob, 1, f0_p_3d, NULL);
473: PetscDSSetJacobian(prob, 0, 0, NULL, NULL, NULL, g3_uu_3d);
474: PetscDSSetJacobian(prob, 0, 1, NULL, NULL, g2_up_3d, NULL);
475: PetscDSSetJacobian(prob, 1, 0, NULL, g1_pu_3d, NULL, NULL);
477: PetscDSSetBdResidual(prob, 0, f0_bd_u_3d, NULL);
478: PetscDSSetBdJacobian(prob, 0, 0, NULL, g1_bd_uu_3d, NULL, NULL);
480: DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed", "Faces", 0, 0, NULL, (void (*)(void)) coordinates, NULL, 0, NULL, user);
481: DMAddBoundary(dm, DM_BC_NATURAL, "pressure", "Faces", 0, 0, NULL, NULL, NULL, 0, NULL, user);
482: return(0);
483: }
485: PetscErrorCode SetupMaterial(DM dm, DM dmAux, AppCtx *user)
486: {
487: PetscErrorCode (*matFuncs[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx) = {elasticityMaterial, wallPressure};
488: Vec A;
489: void *ctxs[2];
493: ctxs[0] = user; ctxs[1] = user;
494: DMCreateLocalVector(dmAux, &A);
495: DMProjectFunctionLocal(dmAux, 0.0, matFuncs, ctxs, INSERT_ALL_VALUES, A);
496: PetscObjectCompose((PetscObject) dm, "A", (PetscObject) A);
497: VecDestroy(&A);
498: return(0);
499: }
501: PetscErrorCode SetupNearNullSpace(DM dm, AppCtx *user)
502: {
503: /* Set up the near null space (a.k.a. rigid body modes) that will be used by the multigrid preconditioner */
504: DM subdm;
505: MatNullSpace nearNullSpace;
506: PetscInt fields = 0;
507: PetscObject deformation;
511: DMCreateSubDM(dm, 1, &fields, NULL, &subdm);
512: DMPlexCreateRigidBody(subdm, 0, &nearNullSpace);
513: DMGetField(dm, 0, NULL, &deformation);
514: PetscObjectCompose(deformation, "nearnullspace", (PetscObject) nearNullSpace);
515: DMDestroy(&subdm);
516: MatNullSpaceDestroy(&nearNullSpace);
517: return(0);
518: }
520: static PetscErrorCode SetupAuxDM(DM dm, PetscInt NfAux, PetscFE feAux[], AppCtx *user)
521: {
522: DM dmAux, coordDM;
523: PetscInt f;
527: /* MUST call DMGetCoordinateDM() in order to get p4est setup if present */
528: DMGetCoordinateDM(dm, &coordDM);
529: if (!feAux) return(0);
530: DMClone(dm, &dmAux);
531: PetscObjectCompose((PetscObject) dm, "dmAux", (PetscObject) dmAux);
532: DMSetCoordinateDM(dmAux, coordDM);
533: for (f = 0; f < NfAux; ++f) {DMSetField(dmAux, f, NULL, (PetscObject) feAux[f]);}
534: DMCreateDS(dmAux);
535: SetupMaterial(dm, dmAux, user);
536: DMDestroy(&dmAux);
537: return(0);
538: }
540: PetscErrorCode SetupDiscretization(DM dm, AppCtx *user)
541: {
542: DM cdm = dm;
543: const PetscInt dim = user->dim;
544: const PetscBool simplex = user->simplex;
545: PetscFE fe[2], feAux[2];
546: MPI_Comm comm;
547: PetscErrorCode ierr;
550: PetscObjectGetComm((PetscObject) dm, &comm);
551: /* Create finite element */
552: PetscFECreateDefault(comm, dim, dim, simplex, "def_", PETSC_DEFAULT, &fe[0]);
553: PetscObjectSetName((PetscObject) fe[0], "deformation");
554: PetscFECreateDefault(comm, dim, 1, simplex, "pres_", PETSC_DEFAULT, &fe[1]);
555: PetscFECopyQuadrature(fe[0], fe[1]);
557: PetscObjectSetName((PetscObject) fe[1], "pressure");
559: PetscFECreateDefault(comm, dim, 1, simplex, "elastMat_", PETSC_DEFAULT, &feAux[0]);
560: PetscObjectSetName((PetscObject) feAux[0], "elasticityMaterial");
561: PetscFECopyQuadrature(fe[0], feAux[0]);
562: /* It is not yet possible to define a field on a submesh (e.g. a boundary), so we will use a normal finite element */
563: PetscFECreateDefault(comm, dim, 1, simplex, "wall_pres_", PETSC_DEFAULT, &feAux[1]);
564: PetscObjectSetName((PetscObject) feAux[1], "wall_pressure");
565: PetscFECopyQuadrature(fe[0], feAux[1]);
567: /* Set discretization and boundary conditions for each mesh */
568: DMSetField(dm, 0, NULL, (PetscObject) fe[0]);
569: DMSetField(dm, 1, NULL, (PetscObject) fe[1]);
570: DMCreateDS(dm);
571: SetupProblem(dm, dim, user);
572: while (cdm) {
573: SetupAuxDM(cdm, 2, feAux, user);
574: DMCopyDisc(dm, cdm);
575: DMGetCoarseDM(cdm, &cdm);
576: }
577: PetscFEDestroy(&fe[0]);
578: PetscFEDestroy(&fe[1]);
579: PetscFEDestroy(&feAux[0]);
580: PetscFEDestroy(&feAux[1]);
581: return(0);
582: }
585: int main(int argc, char **argv)
586: {
587: SNES snes; /* nonlinear solver */
588: DM dm; /* problem definition */
589: Vec u,r; /* solution, residual vectors */
590: Mat A,J; /* Jacobian matrix */
591: AppCtx user; /* user-defined work context */
592: PetscInt its; /* iterations for convergence */
595: PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr;
596: ProcessOptions(PETSC_COMM_WORLD, &user);
597: SNESCreate(PETSC_COMM_WORLD, &snes);
598: CreateMesh(PETSC_COMM_WORLD, &user, &dm);
599: SNESSetDM(snes, dm);
600: DMSetApplicationContext(dm, &user);
602: SetupDiscretization(dm, &user);
603: DMPlexCreateClosureIndex(dm, NULL);
604: SetupNearNullSpace(dm, &user);
606: DMCreateGlobalVector(dm, &u);
607: VecDuplicate(u, &r);
609: DMSetMatType(dm,MATAIJ);
610: DMCreateMatrix(dm, &J);
611: A = J;
613: DMPlexSetSNESLocalFEM(dm,&user,&user,&user);
614: SNESSetJacobian(snes, A, J, NULL, NULL);
616: SNESSetFromOptions(snes);
618: {
619: PetscErrorCode (*initialGuess[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void* ctx);
620: initialGuess[0] = coordinates; initialGuess[1] = zero_scalar;
621: DMProjectFunction(dm, 0.0, initialGuess, NULL, INSERT_VALUES, u);
622: }
623: if (user.showInitial) {DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);}
625: if (user.runType == RUN_FULL) {
626: if (user.debug) {
627: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
628: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
629: }
630: SNESSolve(snes, NULL, u);
631: SNESGetIterationNumber(snes, &its);
632: PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);
633: if (user.showSolution) {
634: PetscPrintf(PETSC_COMM_WORLD, "Solution\n");
635: VecChop(u, 3.0e-9);
636: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
637: }
638: } else {
639: PetscReal res = 0.0;
641: /* Check initial guess */
642: PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");
643: VecView(u, PETSC_VIEWER_STDOUT_WORLD);
644: /* Check residual */
645: SNESComputeFunction(snes, u, r);
646: PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");
647: VecChop(r, 1.0e-10);
648: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
649: VecNorm(r, NORM_2, &res);
650: PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", (double)res);
651: /* Check Jacobian */
652: {
653: Vec b;
655: SNESComputeJacobian(snes, u, A, A);
656: VecDuplicate(u, &b);
657: VecSet(r, 0.0);
658: SNESComputeFunction(snes, r, b);
659: MatMult(A, u, r);
660: VecAXPY(r, 1.0, b);
661: VecDestroy(&b);
662: PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");
663: VecChop(r, 1.0e-10);
664: VecView(r, PETSC_VIEWER_STDOUT_WORLD);
665: VecNorm(r, NORM_2, &res);
666: PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", (double)res);
667: }
668: }
669: VecViewFromOptions(u, NULL, "-sol_vec_view");
671: if (A != J) {MatDestroy(&A);}
672: MatDestroy(&J);
673: VecDestroy(&u);
674: VecDestroy(&r);
675: SNESDestroy(&snes);
676: DMDestroy(&dm);
677: PetscFinalize();
678: return ierr;
679: }
681: /*TEST
683: build:
684: requires: !complex
686: test:
687: suffix: 0
688: requires: ctetgen !single
689: args: -run_type full -dim 3 -dm_refine 2 -interpolate 1 -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0
691: test:
692: suffix: 1
693: requires: ctetgen superlu_dist
694: nsize: 2
695: args: -run_type full -dim 3 -dm_refine 0 -interpolate 1 -test_partition -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0
696: timeoutfactor: 2
698: test:
699: suffix: 2
700: requires: ctetgen !single
701: args: -run_type full -dim 3 -dm_refine 2 -interpolate 1 -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0
703: test:
704: requires: ctetgen superlu_dist
705: suffix: 4
706: nsize: 2
707: args: -run_type full -dim 3 -dm_refine 0 -interpolate 1 -test_partition -bc_fixed 1 -bc_pressure 2 -wall_pressure 0.4 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0
708: output_file: output/ex77_1.out
710: test:
711: requires: ctetgen !single
712: suffix: 3
713: args: -run_type full -dim 3 -dm_refine 2 -interpolate 1 -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0
714: output_file: output/ex77_2.out
716: #TODO: this example deadlocks for me when using ParMETIS
717: test:
718: requires: ctetgen superlu_dist !single
719: suffix: 2_par
720: nsize: 4
721: args: -run_type full -dim 3 -dm_refine 2 -interpolate 1 -bc_fixed 3,4,5,6 -bc_pressure 2 -wall_pressure 1.0 -def_petscspace_degree 2 -pres_petscspace_degree 1 -elastMat_petscspace_degree 0 -wall_pres_petscspace_degree 0 -snes_rtol 1e-05 -ksp_type fgmres -ksp_rtol 1e-10 -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi -snes_monitor_short -ksp_monitor_short -snes_converged_reason -ksp_converged_reason -show_solution 0 -petscpartitioner_type simple
722: output_file: output/ex77_2.out
724: TEST*/