xref: /petsc/src/snes/tutorials/ex17.c (revision f97672e55eacc8688507b9471cd7ec2664d7f203)
1 static char help[] = "Linear elasticity in 2d and 3d with finite elements.\n\
2 We solve the elasticity problem in a rectangular\n\
3 domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\
4 This example supports automatic convergence estimation\n\
5 and eventually adaptivity.\n\n\n";
6 
7 /*
8   https://en.wikipedia.org/wiki/Linear_elasticity
9 
10   Converting elastic constants:
11     lambda = E nu / ((1 + nu) (1 - 2 nu))
12     mu     = E / (2 (1 + nu))
13 */
14 
15 #include <petscdmplex.h>
16 #include <petscsnes.h>
17 #include <petscds.h>
18 #include <petscbag.h>
19 #include <petscconvest.h>
20 
21 typedef enum {SOL_VLAP_QUADRATIC, SOL_ELAS_QUADRATIC, SOL_VLAP_TRIG, SOL_ELAS_TRIG, SOL_ELAS_AXIAL_DISP, SOL_ELAS_UNIFORM_STRAIN, SOL_ELAS_GE, SOL_MASS_QUADRATIC, NUM_SOLUTION_TYPES} SolutionType;
22 const char *solutionTypes[NUM_SOLUTION_TYPES+1] = {"vlap_quad", "elas_quad", "vlap_trig", "elas_trig", "elas_axial_disp", "elas_uniform_strain", "elas_ge", "mass_quad", "unknown"};
23 
24 typedef enum {DEFORM_NONE, DEFORM_SHEAR, DEFORM_STEP, NUM_DEFORM_TYPES} DeformType;
25 const char *deformTypes[NUM_DEFORM_TYPES+1] = {"none", "shear", "step", "unknown"};
26 
27 typedef struct {
28   PetscScalar mu;     /* shear modulus */
29   PetscScalar lambda; /* Lame's first parameter */
30 } Parameter;
31 
32 typedef struct {
33   /* Domain and mesh definition */
34   char         dmType[256]; /* DM type for the solve */
35   DeformType   deform;      /* Domain deformation type */
36   /* Problem definition */
37   SolutionType solType;     /* Type of exact solution */
38   PetscBag     bag;         /* Problem parameters */
39   /* Solver definition */
40   PetscBool    useNearNullspace; /* Use the rigid body modes as a near nullspace for AMG */
41 } AppCtx;
42 
43 static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
44 {
45   PetscInt d;
46   for (d = 0; d < dim; ++d) u[d] = 0.0;
47   return 0;
48 }
49 
50 static PetscErrorCode ge_shift(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
51 {
52   PetscInt d;
53   u[0] = 0.1;
54   for (d = 1; d < dim; ++d) u[d] = 0.0;
55   return 0;
56 }
57 
58 static PetscErrorCode quadratic_2d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
59 {
60   u[0] = x[0]*x[0];
61   u[1] = x[1]*x[1] - 2.0*x[0]*x[1];
62   return 0;
63 }
64 
65 static PetscErrorCode quadratic_3d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
66 {
67   u[0] = x[0]*x[0];
68   u[1] = x[1]*x[1] - 2.0*x[0]*x[1];
69   u[2] = x[2]*x[2] - 2.0*x[1]*x[2];
70   return 0;
71 }
72 
73 /*
74   u = x^2
75   v = y^2 - 2xy
76   Delta <u,v> - f = <2, 2> - <2, 2>
77 
78   u = x^2
79   v = y^2 - 2xy
80   w = z^2 - 2yz
81   Delta <u,v,w> - f = <2, 2, 2> - <2, 2, 2>
82 */
83 static void f0_vlap_quadratic_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
84                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
85                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
86                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
87 {
88   PetscInt d;
89   for (d = 0; d < dim; ++d) f0[d] += 2.0;
90 }
91 
92 /*
93   u = x^2
94   v = y^2 - 2xy
95   \varepsilon = / 2x     -y    \
96                 \ -y   2y - 2x /
97   Tr(\varepsilon) = div u = 2y
98   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
99     = \lambda \partial_j (2y) + 2\mu < 2-1, 2 >
100     = \lambda < 0, 2 > + \mu < 2, 4 >
101 
102   u = x^2
103   v = y^2 - 2xy
104   w = z^2 - 2yz
105   \varepsilon = / 2x     -y       0   \
106                 | -y   2y - 2x   -z   |
107                 \  0     -z    2z - 2y/
108   Tr(\varepsilon) = div u = 2z
109   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
110     = \lambda \partial_j (2z) + 2\mu < 2-1, 2-1, 2 >
111     = \lambda < 0, 0, 2 > + \mu < 2, 2, 4 >
112 */
113 static void f0_elas_quadratic_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
114                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
115                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
116                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
117 {
118   const PetscReal mu     = 1.0;
119   const PetscReal lambda = 1.0;
120   PetscInt        d;
121 
122   for (d = 0; d < dim-1; ++d) f0[d] += 2.0*mu;
123   f0[dim-1] += 2.0*lambda + 4.0*mu;
124 }
125 
126 static void f0_mass_quadratic_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
127                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
128                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
129                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
130 {
131   if (dim == 2) {
132     f0[0] -= x[0]*x[0];
133     f0[1] -= x[1]*x[1] - 2.0*x[0]*x[1];
134   } else {
135     f0[0] -= x[0]*x[0];
136     f0[1] -= x[1]*x[1] - 2.0*x[0]*x[1];
137     f0[2] -= x[2]*x[2] - 2.0*x[1]*x[2];
138   }
139 }
140 
141 static PetscErrorCode trig_2d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
142 {
143   u[0] = PetscSinReal(2.0*PETSC_PI*x[0]);
144   u[1] = PetscSinReal(2.0*PETSC_PI*x[1]) - 2.0*x[0]*x[1];
145   return 0;
146 }
147 
148 static PetscErrorCode trig_3d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
149 {
150   u[0] = PetscSinReal(2.0*PETSC_PI*x[0]);
151   u[1] = PetscSinReal(2.0*PETSC_PI*x[1]) - 2.0*x[0]*x[1];
152   u[2] = PetscSinReal(2.0*PETSC_PI*x[2]) - 2.0*x[1]*x[2];
153   return 0;
154 }
155 
156 /*
157   u = sin(2 pi x)
158   v = sin(2 pi y) - 2xy
159   Delta <u,v> - f = <-4 pi^2 u, -4 pi^2 v> - <-4 pi^2 sin(2 pi x), -4 pi^2 sin(2 pi y)>
160 
161   u = sin(2 pi x)
162   v = sin(2 pi y) - 2xy
163   w = sin(2 pi z) - 2yz
164   Delta <u,v,2> - f = <-4 pi^2 u, -4 pi^2 v, -4 pi^2 w> - <-4 pi^2 sin(2 pi x), -4 pi^2 sin(2 pi y), -4 pi^2 sin(2 pi z)>
165 */
166 static void f0_vlap_trig_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
167                            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
168                            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
169                            PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
170 {
171   PetscInt d;
172   for (d = 0; d < dim; ++d) f0[d] += -4.0*PetscSqr(PETSC_PI)*PetscSinReal(2.0*PETSC_PI*x[d]);
173 }
174 
175 /*
176   u = sin(2 pi x)
177   v = sin(2 pi y) - 2xy
178   \varepsilon = / 2 pi cos(2 pi x)             -y        \
179                 \      -y          2 pi cos(2 pi y) - 2x /
180   Tr(\varepsilon) = div u = 2 pi (cos(2 pi x) + cos(2 pi y)) - 2 x
181   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
182     = \lambda \partial_j 2 pi (cos(2 pi x) + cos(2 pi y)) + 2\mu < -4 pi^2 sin(2 pi x) - 1, -4 pi^2 sin(2 pi y) >
183     = \lambda < -4 pi^2 sin(2 pi x) - 2, -4 pi^2 sin(2 pi y) > + \mu < -8 pi^2 sin(2 pi x) - 2, -8 pi^2 sin(2 pi y) >
184 
185   u = sin(2 pi x)
186   v = sin(2 pi y) - 2xy
187   w = sin(2 pi z) - 2yz
188   \varepsilon = / 2 pi cos(2 pi x)            -y                     0         \
189                 |         -y       2 pi cos(2 pi y) - 2x            -z         |
190                 \          0                  -z         2 pi cos(2 pi z) - 2y /
191   Tr(\varepsilon) = div u = 2 pi (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) - 2 x - 2 y
192   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
193     = \lambda \partial_j (2 pi (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) - 2 x - 2 y) + 2\mu < -4 pi^2 sin(2 pi x) - 1, -4 pi^2 sin(2 pi y) - 1, -4 pi^2 sin(2 pi z) >
194     = \lambda < -4 pi^2 sin(2 pi x) - 2, -4 pi^2 sin(2 pi y) - 2, -4 pi^2 sin(2 pi z) > + 2\mu < -4 pi^2 sin(2 pi x) - 1, -4 pi^2 sin(2 pi y) - 1, -4 pi^2 sin(2 pi z) >
195 */
196 static void f0_elas_trig_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
197                            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
198                            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
199                            PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
200 {
201   const PetscReal mu     = 1.0;
202   const PetscReal lambda = 1.0;
203   const PetscReal fact   = 4.0*PetscSqr(PETSC_PI);
204   PetscInt        d;
205 
206   for (d = 0; d < dim; ++d) f0[d] += -(2.0*mu + lambda) * fact*PetscSinReal(2.0*PETSC_PI*x[d]) - (d < dim-1 ? 2.0*(mu + lambda) : 0.0);
207 }
208 
209 static PetscErrorCode axial_disp_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
210 {
211   const PetscReal mu     = 1.0;
212   const PetscReal lambda = 1.0;
213   const PetscReal N      = 1.0;
214   PetscInt d;
215 
216   u[0] = (3.*lambda*lambda + 8.*lambda*mu + 4*mu*mu)/(4*mu*(3*lambda*lambda + 5.*lambda*mu + 2*mu*mu))*N*x[0];
217   u[1] = -0.25*lambda/mu/(lambda+mu)*N*x[1];
218   for (d = 2; d < dim; ++d) u[d] = 0.0;
219   return 0;
220 }
221 
222 /*
223   We will pull/push on the right side of a block of linearly elastic material. The uniform traction conditions on the
224   right side of the box will result in a uniform strain along x and y. The Neumann BC is given by
225 
226      n_i \sigma_{ij} = t_i
227 
228   u = (1/(2\mu) - 1) x
229   v = -y
230   f = 0
231   t = <4\mu/\lambda (\lambda + \mu), 0>
232   \varepsilon = / 1/(2\mu) - 1   0 \
233                 \ 0             -1 /
234   Tr(\varepsilon) = div u = 1/(2\mu) - 2
235   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
236     = \lambda \partial_j (1/(2\mu) - 2) + 2\mu < 0, 0 >
237     = \lambda < 0, 0 > + \mu < 0, 0 > = 0
238   NBC =  <1,0> . <4\mu/\lambda (\lambda + \mu), 0> = 4\mu/\lambda (\lambda + \mu)
239 
240   u = x - 1/2
241   v = 0
242   w = 0
243   \varepsilon = / x  0  0 \
244                 | 0  0  0 |
245                 \ 0  0  0 /
246   Tr(\varepsilon) = div u = x
247   div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
248     = \lambda \partial_j x + 2\mu < 1, 0, 0 >
249     = \lambda < 1, 0, 0 > + \mu < 2, 0, 0 >
250 */
251 static void f0_elas_axial_disp_bd_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
252                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
253                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
254                                     PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
255 {
256   const PetscReal N = -1.0;
257 
258   f0[0] = N;
259 }
260 
261 static PetscErrorCode uniform_strain_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
262 {
263   const PetscReal eps_xx = 0.1;
264   const PetscReal eps_xy = 0.3;
265   const PetscReal eps_yy = 0.25;
266   PetscInt d;
267 
268   u[0] = eps_xx*x[0] + eps_xy*x[1];
269   u[1] = eps_xy*x[0] + eps_yy*x[1];
270   for (d = 2; d < dim; ++d) u[d] = 0.0;
271   return 0;
272 }
273 
274 static void f0_mass_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
275                       const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
276                       const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
277                       PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
278 {
279   const PetscInt Nc = dim;
280   PetscInt       c;
281 
282   for (c = 0; c < Nc; ++c) f0[c] = u[c];
283 }
284 
285 static void f1_vlap_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
286                       const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
287                       const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
288                       PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
289 {
290   const PetscInt Nc = dim;
291   PetscInt       c, d;
292 
293   for (c = 0; c < Nc; ++c) for (d = 0; d < dim; ++d) f1[c*dim+d] += u_x[c*dim+d];
294 }
295 
296 static void f1_elas_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
297                       const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
298                       const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
299                       PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
300 {
301   const PetscInt  Nc     = dim;
302   const PetscReal mu     = 1.0;
303   const PetscReal lambda = 1.0;
304   PetscInt        c, d;
305 
306   for (c = 0; c < Nc; ++c) {
307     for (d = 0; d < dim; ++d) {
308       f1[c*dim+d] += mu*(u_x[c*dim+d] + u_x[d*dim+c]);
309       f1[c*dim+c] += lambda*u_x[d*dim+d];
310     }
311   }
312 }
313 
314 static void g0_mass_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
315                        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
316                        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
317                        PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
318 {
319   const PetscInt Nc = dim;
320   PetscInt       c;
321 
322   for (c = 0; c < Nc; ++c) g0[c*Nc + c] = 1.0;
323 }
324 
325 static void g3_vlap_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
326                        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
327                        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
328                        PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
329 {
330   const PetscInt Nc = dim;
331   PetscInt       c, d;
332 
333   for (c = 0; c < Nc; ++c) {
334     for (d = 0; d < dim; ++d) {
335       g3[((c*Nc + c)*dim + d)*dim + d] = 1.0;
336     }
337   }
338 }
339 
340 /*
341   \partial_df \phi_fc g_{fc,gc,df,dg} \partial_dg \phi_gc
342 
343   \partial_df \phi_fc \lambda \delta_{fc,df} \sum_gc \partial_dg \phi_gc \delta_{gc,dg}
344   = \partial_fc \phi_fc \sum_gc \partial_gc \phi_gc
345 */
346 static void g3_elas_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
347                        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
348                        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
349                        PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
350 {
351   const PetscInt  Nc     = dim;
352   const PetscReal mu     = 1.0;
353   const PetscReal lambda = 1.0;
354   PetscInt        c, d;
355 
356   for (c = 0; c < Nc; ++c) {
357     for (d = 0; d < dim; ++d) {
358       g3[((c*Nc + c)*dim + d)*dim + d] += mu;
359       g3[((c*Nc + d)*dim + d)*dim + c] += mu;
360       g3[((c*Nc + d)*dim + c)*dim + d] += lambda;
361     }
362   }
363 }
364 
365 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
366 {
367   PetscInt       sol = 0, def = 0;
368 
369   PetscFunctionBeginUser;
370   options->deform           = DEFORM_NONE;
371   options->solType          = SOL_VLAP_QUADRATIC;
372   options->useNearNullspace = PETSC_TRUE;
373   PetscCall(PetscStrncpy(options->dmType, DMPLEX, 256));
374 
375   PetscOptionsBegin(comm, "", "Linear Elasticity Problem Options", "DMPLEX");
376   PetscCall(PetscOptionsEList("-deform_type", "Type of domain deformation", "ex17.c", deformTypes, NUM_DEFORM_TYPES, deformTypes[options->deform], &def, NULL));
377   options->deform = (DeformType) def;
378   PetscCall(PetscOptionsEList("-sol_type", "Type of exact solution", "ex17.c", solutionTypes, NUM_SOLUTION_TYPES, solutionTypes[options->solType], &sol, NULL));
379   options->solType = (SolutionType) sol;
380   PetscCall(PetscOptionsBool("-near_nullspace", "Use the rigid body modes as an AMG near nullspace", "ex17.c", options->useNearNullspace, &options->useNearNullspace, NULL));
381   PetscCall(PetscOptionsFList("-dm_type", "Convert DMPlex to another format", "ex17.c", DMList, options->dmType, options->dmType, 256, NULL));
382   PetscOptionsEnd();
383   PetscFunctionReturn(0);
384 }
385 
386 static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
387 {
388   PetscBag       bag;
389   Parameter     *p;
390 
391   PetscFunctionBeginUser;
392   /* setup PETSc parameter bag */
393   PetscCall(PetscBagGetData(ctx->bag,(void**)&p));
394   PetscCall(PetscBagSetName(ctx->bag,"par","Elastic Parameters"));
395   bag  = ctx->bag;
396   PetscCall(PetscBagRegisterScalar(bag, &p->mu,     1.0, "mu",     "Shear Modulus, Pa"));
397   PetscCall(PetscBagRegisterScalar(bag, &p->lambda, 1.0, "lambda", "Lame's first parameter, Pa"));
398   PetscCall(PetscBagSetFromOptions(bag));
399   {
400     PetscViewer       viewer;
401     PetscViewerFormat format;
402     PetscBool         flg;
403 
404     PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg));
405     if (flg) {
406       PetscCall(PetscViewerPushFormat(viewer, format));
407       PetscCall(PetscBagView(bag, viewer));
408       PetscCall(PetscViewerFlush(viewer));
409       PetscCall(PetscViewerPopFormat(viewer));
410       PetscCall(PetscViewerDestroy(&viewer));
411     }
412   }
413   PetscFunctionReturn(0);
414 }
415 
416 static PetscErrorCode DMPlexDistortGeometry(DM dm)
417 {
418   DM             cdm;
419   DMLabel        label;
420   Vec            coordinates;
421   PetscScalar   *coords;
422   PetscReal      mid = 0.5;
423   PetscInt       cdim, d, vStart, vEnd, v;
424 
425   PetscFunctionBeginUser;
426   PetscCall(DMGetCoordinateDM(dm, &cdm));
427   PetscCall(DMGetCoordinateDim(dm, &cdim));
428   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
429   PetscCall(DMGetLabel(dm, "marker", &label));
430   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
431   PetscCall(VecGetArrayWrite(coordinates, &coords));
432   for (v = vStart; v < vEnd; ++v) {
433     PetscScalar *pcoords, shift;
434     PetscInt     val;
435 
436     PetscCall(DMLabelGetValue(label, v, &val));
437     if (val >= 0) continue;
438     PetscCall(DMPlexPointLocalRef(cdm, v, coords, &pcoords));
439     shift = 0.2 * PetscAbsScalar(pcoords[0] - mid);
440     shift = PetscRealPart(pcoords[0]) > mid ? shift : -shift;
441     for (d = 1; d < cdim; ++d) pcoords[d] += shift;
442   }
443   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
444   PetscFunctionReturn(0);
445 }
446 
447 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
448 {
449   PetscFunctionBeginUser;
450   PetscCall(DMCreate(comm, dm));
451   PetscCall(DMSetType(*dm, DMPLEX));
452   PetscCall(DMSetFromOptions(*dm));
453   switch (user->deform) {
454     case DEFORM_NONE:  break;
455     case DEFORM_SHEAR: PetscCall(DMPlexShearGeometry(*dm, DM_X, NULL));break;
456     case DEFORM_STEP:  PetscCall(DMPlexDistortGeometry(*dm));break;
457     default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid deformation type: %s (%d)", deformTypes[PetscMin(user->deform, NUM_DEFORM_TYPES)], user->deform);
458   }
459   PetscCall(DMSetApplicationContext(*dm, user));
460   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
461   PetscFunctionReturn(0);
462 }
463 
464 static PetscErrorCode SetupPrimalProblem(DM dm, AppCtx *user)
465 {
466   PetscErrorCode (*exact)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *);
467   Parameter       *param;
468   PetscDS          ds;
469   PetscWeakForm    wf;
470   DMLabel          label;
471   PetscInt         id, bd;
472   PetscInt         dim;
473 
474   PetscFunctionBeginUser;
475   PetscCall(DMGetDS(dm, &ds));
476   PetscCall(PetscDSGetWeakForm(ds, &wf));
477   PetscCall(PetscDSGetSpatialDimension(ds, &dim));
478   PetscCall(PetscBagGetData(user->bag, (void **) &param));
479   switch (user->solType) {
480   case SOL_MASS_QUADRATIC:
481     PetscCall(PetscDSSetResidual(ds, 0, f0_mass_u, NULL));
482     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_mass_uu, NULL, NULL, NULL));
483     PetscCall(PetscWeakFormSetIndexResidual(wf, NULL, 0, 0,  0, 1, f0_mass_quadratic_u, 0, NULL));
484     switch (dim) {
485     case 2: exact = quadratic_2d_u;break;
486     case 3: exact = quadratic_3d_u;break;
487     default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid dimension: %" PetscInt_FMT, dim);
488     }
489     break;
490   case SOL_VLAP_QUADRATIC:
491     PetscCall(PetscDSSetResidual(ds, 0, f0_vlap_quadratic_u, f1_vlap_u));
492     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_vlap_uu));
493     switch (dim) {
494     case 2: exact = quadratic_2d_u;break;
495     case 3: exact = quadratic_3d_u;break;
496     default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid dimension: %" PetscInt_FMT, dim);
497     }
498     break;
499   case SOL_ELAS_QUADRATIC:
500     PetscCall(PetscDSSetResidual(ds, 0, f0_elas_quadratic_u, f1_elas_u));
501     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_elas_uu));
502     switch (dim) {
503     case 2: exact = quadratic_2d_u;break;
504     case 3: exact = quadratic_3d_u;break;
505     default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid dimension: %" PetscInt_FMT, dim);
506     }
507     break;
508   case SOL_VLAP_TRIG:
509     PetscCall(PetscDSSetResidual(ds, 0, f0_vlap_trig_u, f1_vlap_u));
510     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_vlap_uu));
511     switch (dim) {
512     case 2: exact = trig_2d_u;break;
513     case 3: exact = trig_3d_u;break;
514     default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid dimension: %" PetscInt_FMT, dim);
515     }
516     break;
517   case SOL_ELAS_TRIG:
518     PetscCall(PetscDSSetResidual(ds, 0, f0_elas_trig_u, f1_elas_u));
519     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_elas_uu));
520     switch (dim) {
521     case 2: exact = trig_2d_u;break;
522     case 3: exact = trig_3d_u;break;
523     default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid dimension: %" PetscInt_FMT, dim);
524     }
525     break;
526   case SOL_ELAS_AXIAL_DISP:
527     PetscCall(PetscDSSetResidual(ds, 0, NULL, f1_elas_u));
528     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_elas_uu));
529     id   = dim == 3 ? 5 : 2;
530     PetscCall(DMGetLabel(dm, "marker", &label));
531     PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "right", label, 1, &id, 0, 0, NULL, (void (*)(void)) NULL, NULL, user, &bd));
532     PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
533     PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_elas_axial_disp_bd_u, 0, NULL));
534     exact = axial_disp_u;
535     break;
536   case SOL_ELAS_UNIFORM_STRAIN:
537     PetscCall(PetscDSSetResidual(ds, 0, NULL, f1_elas_u));
538     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_elas_uu));
539     exact = uniform_strain_u;
540     break;
541   case SOL_ELAS_GE:
542     PetscCall(PetscDSSetResidual(ds, 0, NULL, f1_elas_u));
543     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_elas_uu));
544     exact = zero; /* No exact solution available */
545     break;
546   default: SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Invalid solution type: %s (%d)", solutionTypes[PetscMin(user->solType, NUM_SOLUTION_TYPES)], user->solType);
547   }
548   PetscCall(PetscDSSetExactSolution(ds, 0, exact, user));
549   PetscCall(DMGetLabel(dm, "marker", &label));
550   if (user->solType == SOL_ELAS_AXIAL_DISP) {
551     PetscInt cmp;
552 
553     id   = dim == 3 ? 6 : 4;
554     cmp  = 0;
555     PetscCall(DMAddBoundary(dm,   DM_BC_ESSENTIAL, "left",   label, 1, &id, 0, 1, &cmp, (void (*)(void)) zero, NULL, user, NULL));
556     cmp  = dim == 3 ? 2 : 1;
557     id   = dim == 3 ? 1 : 1;
558     PetscCall(DMAddBoundary(dm,   DM_BC_ESSENTIAL, "bottom", label, 1, &id, 0, 1, &cmp, (void (*)(void)) zero, NULL, user, NULL));
559     if (dim == 3) {
560       cmp  = 1;
561       id   = 3;
562       PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "front",  label, 1, &id, 0, 1, &cmp, (void (*)(void)) zero, NULL, user, NULL));
563     }
564   } else if (user->solType == SOL_ELAS_GE) {
565     PetscInt cmp;
566 
567     id   = dim == 3 ? 6 : 4;
568     PetscCall(DMAddBoundary(dm,   DM_BC_ESSENTIAL, "left",   label, 1, &id, 0, 0, NULL, (void (*)(void)) zero, NULL, user, NULL));
569     id   = dim == 3 ? 5 : 2;
570     cmp  = 0;
571     PetscCall(DMAddBoundary(dm,   DM_BC_ESSENTIAL, "right",  label, 1, &id, 0, 1, &cmp, (void (*)(void)) ge_shift, NULL, user, NULL));
572   } else {
573     id = 1;
574     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void)) exact, NULL, user, NULL));
575   }
576   /* Setup constants */
577   {
578     PetscScalar constants[2];
579 
580     constants[0] = param->mu;     /* shear modulus, Pa */
581     constants[1] = param->lambda; /* Lame's first parameter, Pa */
582     PetscCall(PetscDSSetConstants(ds, 2, constants));
583   }
584   PetscFunctionReturn(0);
585 }
586 
587 static PetscErrorCode CreateElasticityNullSpace(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullspace)
588 {
589   PetscFunctionBegin;
590   PetscCall(DMPlexCreateRigidBody(dm, origField, nullspace));
591   PetscFunctionReturn(0);
592 }
593 
594 PetscErrorCode SetupFE(DM dm, const char name[], PetscErrorCode (*setup)(DM, AppCtx *), void *ctx)
595 {
596   AppCtx        *user = (AppCtx *) ctx;
597   DM             cdm  = dm;
598   PetscFE        fe;
599   char           prefix[PETSC_MAX_PATH_LEN];
600   DMPolytopeType ct;
601   PetscBool      simplex;
602   PetscInt       dim, cStart;
603 
604   PetscFunctionBegin;
605   /* Create finite element */
606   PetscCall(DMGetDimension(dm, &dim));
607   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
608   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
609   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
610   PetscCall(PetscSNPrintf(prefix, PETSC_MAX_PATH_LEN, "%s_", name));
611   PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) dm), dim, dim, simplex, name ? prefix : NULL, -1, &fe));
612   PetscCall(PetscObjectSetName((PetscObject) fe, name));
613   /* Set discretization and boundary conditions for each mesh */
614   PetscCall(DMSetField(dm, 0, NULL, (PetscObject) fe));
615   PetscCall(DMCreateDS(dm));
616   PetscCall((*setup)(dm, user));
617   while (cdm) {
618     PetscCall(DMCopyDisc(dm, cdm));
619     if (user->useNearNullspace) PetscCall(DMSetNearNullSpaceConstructor(cdm, 0, CreateElasticityNullSpace));
620     /* TODO: Check whether the boundary of coarse meshes is marked */
621     PetscCall(DMGetCoarseDM(cdm, &cdm));
622   }
623   PetscCall(PetscFEDestroy(&fe));
624   PetscFunctionReturn(0);
625 }
626 
627 int main(int argc, char **argv)
628 {
629   DM             dm;   /* Problem specification */
630   SNES           snes; /* Nonlinear solver */
631   Vec            u;    /* Solutions */
632   AppCtx         user; /* User-defined work context */
633 
634   PetscCall(PetscInitialize(&argc, &argv, NULL,help));
635   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
636   PetscCall(PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &user.bag));
637   PetscCall(SetupParameters(PETSC_COMM_WORLD, &user));
638   /* Primal system */
639   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
640   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
641   PetscCall(SNESSetDM(snes, dm));
642   PetscCall(SetupFE(dm, "displacement", SetupPrimalProblem, &user));
643   PetscCall(DMCreateGlobalVector(dm, &u));
644   PetscCall(VecSet(u, 0.0));
645   PetscCall(PetscObjectSetName((PetscObject) u, "displacement"));
646   PetscCall(DMPlexSetSNESLocalFEM(dm, &user, &user, &user));
647   PetscCall(SNESSetFromOptions(snes));
648   PetscCall(DMSNESCheckFromOptions(snes, u));
649   PetscCall(SNESSolve(snes, NULL, u));
650   PetscCall(SNESGetSolution(snes, &u));
651   PetscCall(VecViewFromOptions(u, NULL, "-displacement_view"));
652   /* Cleanup */
653   PetscCall(VecDestroy(&u));
654   PetscCall(SNESDestroy(&snes));
655   PetscCall(DMDestroy(&dm));
656   PetscCall(PetscBagDestroy(&user.bag));
657   PetscCall(PetscFinalize());
658   return 0;
659 }
660 
661 /*TEST
662 
663   testset:
664     args: -dm_plex_box_faces 1,1,1
665 
666     test:
667       suffix: 2d_p1_quad_vlap
668       requires: triangle
669       args: -displacement_petscspace_degree 1 -dm_refine 2 -convest_num_refine 3 -snes_convergence_estimate
670     test:
671       suffix: 2d_p2_quad_vlap
672       requires: triangle
673       args: -displacement_petscspace_degree 2 -dm_refine 2 -dmsnes_check .0001
674     test:
675       suffix: 2d_p3_quad_vlap
676       requires: triangle
677       args: -displacement_petscspace_degree 3 -dm_refine 2 -dmsnes_check .0001
678     test:
679       suffix: 2d_q1_quad_vlap
680       args: -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_refine 2 -convest_num_refine 3 -snes_convergence_estimate
681     test:
682       suffix: 2d_q2_quad_vlap
683       args: -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 2 -dmsnes_check .0001
684     test:
685       suffix: 2d_q3_quad_vlap
686       requires: !single
687       args: -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 2 -dmsnes_check .0001
688     test:
689       suffix: 2d_p1_quad_elas
690       requires: triangle
691       args: -sol_type elas_quad -displacement_petscspace_degree 1 -dm_refine 2 -convest_num_refine 3 -snes_convergence_estimate
692     test:
693       suffix: 2d_p2_quad_elas
694       requires: triangle
695       args: -sol_type elas_quad -displacement_petscspace_degree 2 -dmsnes_check .0001
696     test:
697       suffix: 2d_p3_quad_elas
698       requires: triangle
699       args: -sol_type elas_quad -displacement_petscspace_degree 3 -dmsnes_check .0001
700     test:
701       suffix: 2d_q1_quad_elas
702       args: -sol_type elas_quad -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
703     test:
704       suffix: 2d_q1_quad_elas_shear
705       args: -sol_type elas_quad -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
706     test:
707       suffix: 2d_q2_quad_elas
708       args: -sol_type elas_quad -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dmsnes_check .0001
709     test:
710       suffix: 2d_q2_quad_elas_shear
711       args: -sol_type elas_quad -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 2 -dmsnes_check
712     test:
713       suffix: 2d_q3_quad_elas
714       args: -sol_type elas_quad -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dmsnes_check .0001
715     test:
716       suffix: 2d_q3_quad_elas_shear
717       requires: !single
718       args: -sol_type elas_quad -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 3 -dmsnes_check
719 
720     test:
721       suffix: 3d_p1_quad_vlap
722       requires: ctetgen
723       args: -dm_plex_dim 3 -dm_refine 1 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
724     test:
725       suffix: 3d_p2_quad_vlap
726       requires: ctetgen
727       args: -dm_plex_dim 3 -displacement_petscspace_degree 2 -dm_refine 1 -dmsnes_check .0001
728     test:
729       suffix: 3d_p3_quad_vlap
730       requires: ctetgen
731       args: -dm_plex_dim 3 -displacement_petscspace_degree 3 -dm_refine 0 -dmsnes_check .0001
732     test:
733       suffix: 3d_q1_quad_vlap
734       args: -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_simplex 0 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
735     test:
736       suffix: 3d_q2_quad_vlap
737       args: -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 1 -dmsnes_check .0001
738     test:
739       suffix: 3d_q3_quad_vlap
740       args: -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 0 -dmsnes_check .0001
741     test:
742       suffix: 3d_p1_quad_elas
743       requires: ctetgen
744       args: -sol_type elas_quad -dm_plex_dim 3 -dm_refine 1 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
745     test:
746       suffix: 3d_p2_quad_elas
747       requires: ctetgen
748       args: -sol_type elas_quad -dm_plex_dim 3 -displacement_petscspace_degree 2 -dm_refine 1 -dmsnes_check .0001
749     test:
750       suffix: 3d_p3_quad_elas
751       requires: ctetgen
752       args: -sol_type elas_quad -dm_plex_dim 3 -displacement_petscspace_degree 3 -dm_refine 0 -dmsnes_check .0001
753     test:
754       suffix: 3d_q1_quad_elas
755       args: -sol_type elas_quad -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_simplex 0 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
756     test:
757       suffix: 3d_q2_quad_elas
758       args: -sol_type elas_quad -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 1 -dmsnes_check .0001
759     test:
760       suffix: 3d_q3_quad_elas
761       requires: !single
762       args: -sol_type elas_quad -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 0 -dmsnes_check .0001
763 
764     test:
765       suffix: 2d_p1_trig_vlap
766       requires: triangle
767       args: -sol_type vlap_trig -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
768     test:
769       suffix: 2d_p2_trig_vlap
770       requires: triangle
771       args: -sol_type vlap_trig -displacement_petscspace_degree 2 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
772     test:
773       suffix: 2d_p3_trig_vlap
774       requires: triangle
775       args: -sol_type vlap_trig -displacement_petscspace_degree 3 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
776     test:
777       suffix: 2d_q1_trig_vlap
778       args: -sol_type vlap_trig -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
779     test:
780       suffix: 2d_q2_trig_vlap
781       args: -sol_type vlap_trig -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
782     test:
783       suffix: 2d_q3_trig_vlap
784       args: -sol_type vlap_trig -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
785     test:
786       suffix: 2d_p1_trig_elas
787       requires: triangle
788       args: -sol_type elas_trig -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
789     test:
790       suffix: 2d_p2_trig_elas
791       requires: triangle
792       args: -sol_type elas_trig -displacement_petscspace_degree 2 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
793     test:
794       suffix: 2d_p3_trig_elas
795       requires: triangle
796       args: -sol_type elas_trig -displacement_petscspace_degree 3 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
797     test:
798       suffix: 2d_q1_trig_elas
799       args: -sol_type elas_trig -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
800     test:
801       suffix: 2d_q1_trig_elas_shear
802       args: -sol_type elas_trig -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 1 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
803     test:
804       suffix: 2d_q2_trig_elas
805       args: -sol_type elas_trig -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
806     test:
807       suffix: 2d_q2_trig_elas_shear
808       args: -sol_type elas_trig -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 2 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
809     test:
810       suffix: 2d_q3_trig_elas
811       args: -sol_type elas_trig -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
812     test:
813       suffix: 2d_q3_trig_elas_shear
814       args: -sol_type elas_trig -dm_plex_simplex 0 -deform_type shear -displacement_petscspace_degree 3 -dm_refine 1 -convest_num_refine 3 -snes_convergence_estimate
815 
816     test:
817       suffix: 3d_p1_trig_vlap
818       requires: ctetgen
819       args: -sol_type vlap_trig -dm_plex_dim 3 -dm_refine 1 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
820     test:
821       suffix: 3d_p2_trig_vlap
822       requires: ctetgen
823       args: -sol_type vlap_trig -dm_plex_dim 3 -displacement_petscspace_degree 2 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
824     test:
825       suffix: 3d_p3_trig_vlap
826       requires: ctetgen
827       args: -sol_type vlap_trig -dm_plex_dim 3 -displacement_petscspace_degree 3 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
828     test:
829       suffix: 3d_q1_trig_vlap
830       args: -sol_type vlap_trig -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_simplex 0 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
831     test:
832       suffix: 3d_q2_trig_vlap
833       args: -sol_type vlap_trig -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
834     test:
835       suffix: 3d_q3_trig_vlap
836       requires: !__float128
837       args: -sol_type vlap_trig -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
838     test:
839       suffix: 3d_p1_trig_elas
840       requires: ctetgen
841       args: -sol_type elas_trig -dm_plex_dim 3 -dm_refine 1 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
842     test:
843       suffix: 3d_p2_trig_elas
844       requires: ctetgen
845       args: -sol_type elas_trig -dm_plex_dim 3 -displacement_petscspace_degree 2 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
846     test:
847       suffix: 3d_p3_trig_elas
848       requires: ctetgen
849       args: -sol_type elas_trig -dm_plex_dim 3 -displacement_petscspace_degree 3 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
850     test:
851       suffix: 3d_q1_trig_elas
852       args: -sol_type elas_trig -dm_plex_dim 3 -dm_plex_box_faces 2,2,2 -dm_plex_simplex 0 -displacement_petscspace_degree 1 -convest_num_refine 2 -snes_convergence_estimate
853     test:
854       suffix: 3d_q2_trig_elas
855       args: -sol_type elas_trig -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
856     test:
857       suffix: 3d_q3_trig_elas
858       requires: !__float128
859       args: -sol_type elas_trig -dm_plex_dim 3 -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 0 -convest_num_refine 1 -snes_convergence_estimate
860 
861     test:
862       suffix: 2d_p1_axial_elas
863       requires: triangle
864       args: -sol_type elas_axial_disp -displacement_petscspace_degree 1 -dm_plex_separate_marker -dm_refine 2 -dmsnes_check .0001 -pc_type lu
865     test:
866       suffix: 2d_p2_axial_elas
867       requires: triangle
868       args: -sol_type elas_axial_disp -displacement_petscspace_degree 2 -dm_plex_separate_marker -dmsnes_check .0001 -pc_type lu
869     test:
870       suffix: 2d_p3_axial_elas
871       requires: triangle
872       args: -sol_type elas_axial_disp -displacement_petscspace_degree 3 -dm_plex_separate_marker -dmsnes_check .0001 -pc_type lu
873     test:
874       suffix: 2d_q1_axial_elas
875       args: -sol_type elas_axial_disp -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_plex_separate_marker -dm_refine 1 -dmsnes_check   .0001 -pc_type lu
876     test:
877       suffix: 2d_q2_axial_elas
878       args: -sol_type elas_axial_disp -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_plex_separate_marker -dmsnes_check .0001 -pc_type   lu
879     test:
880       suffix: 2d_q3_axial_elas
881       args: -sol_type elas_axial_disp -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_plex_separate_marker -dmsnes_check .0001 -pc_type   lu
882 
883     test:
884       suffix: 2d_p1_uniform_elas
885       requires: triangle
886       args: -sol_type elas_uniform_strain -displacement_petscspace_degree 1 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
887     test:
888       suffix: 2d_p2_uniform_elas
889       requires: triangle
890       args: -sol_type elas_uniform_strain -displacement_petscspace_degree 2 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
891     test:
892       suffix: 2d_p3_uniform_elas
893       requires: triangle
894       args: -sol_type elas_uniform_strain -displacement_petscspace_degree 3 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
895     test:
896       suffix: 2d_q1_uniform_elas
897       args: -sol_type elas_uniform_strain -dm_plex_simplex 0 -displacement_petscspace_degree 1 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
898     test:
899       suffix: 2d_q2_uniform_elas
900       requires: !single
901       args: -sol_type elas_uniform_strain -dm_plex_simplex 0 -displacement_petscspace_degree 2 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
902     test:
903       suffix: 2d_q3_uniform_elas
904       requires: !single
905       args: -sol_type elas_uniform_strain -dm_plex_simplex 0 -displacement_petscspace_degree 3 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
906     test:
907       suffix: 2d_p1_uniform_elas_step
908       requires: triangle
909       args: -sol_type elas_uniform_strain -deform_type step -displacement_petscspace_degree 1 -dm_refine 2 -dmsnes_check .0001 -pc_type lu
910 
911   testset:
912     args: -dm_plex_simplex 0 -dm_plex_box_faces 3,3 -deform_type step -displacement_petscspace_degree 1 -dmsnes_check .0001 -pc_type lu
913 
914     test:
915       suffix: 2d_q1_uniform_elas_step
916       args: -sol_type elas_uniform_strain -dm_refine 2
917     test:
918       suffix: 2d_q1_quad_vlap_step
919       args:
920     test:
921       suffix: 2d_q2_quad_vlap_step
922       args: -displacement_petscspace_degree 2
923     test:
924       suffix: 2d_q1_quad_mass_step
925       args: -sol_type mass_quad
926 
927   testset:
928     args: -dm_plex_dim 3 -dm_plex_simplex 0 -dm_plex_box_lower -5,-5,-0.25 -dm_plex_box_upper 5,5,0.25 \
929           -dm_plex_box_faces 5,5,2 -dm_plex_separate_marker -dm_refine 0 -petscpartitioner_type simple \
930           -sol_type elas_ge \
931           -snes_max_it 2 -snes_rtol 1.e-10 \
932           -ksp_type cg -ksp_rtol 1.e-10 -ksp_max_it 100 -ksp_norm_type unpreconditioned \
933           -pc_type gamg -pc_gamg_type agg -pc_gamg_agg_nsmooths 1 \
934             -pc_gamg_coarse_eq_limit 10 -pc_gamg_reuse_interpolation true \
935             -pc_gamg_square_graph 1 -pc_gamg_threshold 0.05 -pc_gamg_threshold_scale .0 \
936             -mg_levels_ksp_max_it 2 -mg_levels_ksp_type chebyshev -mg_levels_ksp_chebyshev_esteig 0,0.05,0,1.1 -mg_levels_pc_type jacobi \
937             -matptap_via scalable
938     test:
939       suffix: ge_q1_0
940       args: -displacement_petscspace_degree 1
941 
942 TEST*/
943