xref: /petsc/src/ts/tutorials/ex53.c (revision f4259b3095b7e7c300c2b3c3729548b071684bd7)
1 static char help[] = "Time dependent Biot Poroelasticity problem with finite elements.\n\
2 We solve three field, quasi-static poroelasticity in a rectangular\n\
3 domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\
4 Contributed by: Robert Walker <rwalker6@buffalo.edu>\n\n\n";
5 
6 #include <petscdmplex.h>
7 #include <petscsnes.h>
8 #include <petscts.h>
9 #include <petscds.h>
10 #include <petscbag.h>
11 
12 #include <petsc/private/tsimpl.h>
13 
14 /* This presentation of poroelasticity is taken from
15 
16 @book{Cheng2016,
17   title={Poroelasticity},
18   author={Cheng, Alexander H-D},
19   volume={27},
20   year={2016},
21   publisher={Springer}
22 }
23 
24 For visualization, use
25 
26   -dm_view hdf5:${PETSC_DIR}/sol.h5 -monitor_solution hdf5:${PETSC_DIR}/sol.h5::append
27 
28 The weak form would then be, using test function $(v, q, \tau)$,
29 
30             (q, \frac{1}{M} \frac{dp}{dt}) + (q, \alpha \frac{d\varepsilon}{dt}) + (\nabla q, \kappa \nabla p) = (q, g)
31  -(\nabla v, 2 G \epsilon) - (\nabla\cdot v, \frac{2 G \nu}{1 - 2\nu} \varepsilon) + \alpha (\nabla\cdot v, p) = (v, f)
32                                                                           (\tau, \nabla \cdot u - \varepsilon) = 0
33 */
34 
35 typedef enum {SOL_QUADRATIC_LINEAR, SOL_QUADRATIC_TRIG, SOL_TRIG_LINEAR, SOL_TERZAGHI, SOL_MANDEL, SOL_CRYER, NUM_SOLUTION_TYPES} SolutionType;
36 const char *solutionTypes[NUM_SOLUTION_TYPES+1] = {"quadratic_linear", "quadratic_trig", "trig_linear", "terzaghi", "mandel", "cryer", "unknown"};
37 
38 typedef struct {
39   PetscScalar mu;    /* shear modulus */
40   PetscScalar K_u;   /* undrained bulk modulus */
41   PetscScalar alpha; /* Biot effective stress coefficient */
42   PetscScalar M;     /* Biot modulus */
43   PetscScalar k;     /* (isotropic) permeability */
44   PetscScalar mu_f;  /* fluid dynamic viscosity */
45   PetscReal   zmax;  /* depth maximum extent */
46   PetscReal   zmin;  /* depth minimum extent */
47   PetscReal   ymax;  /* vertical maximum extent */
48   PetscReal   ymin;  /* vertical minimum extent */
49   PetscReal   xmax;  /* horizontal maximum extent */
50   PetscReal   xmin;  /* horizontal minimum extent */
51   PetscScalar P_0;   /* magnitude of vertical stress */
52 } Parameter;
53 
54 typedef struct {
55   /* Domain and mesh definition */
56   char         dmType[256]; /* DM type for the solve */
57   PetscInt     dim;         /* The topological mesh dimension */
58   PetscBool    simplex;     /* Simplicial mesh */
59   PetscReal    refLimit;    /* Refine mesh with generator */
60   /* Problem definition */
61   SolutionType solType;     /* Type of exact solution */
62   PetscBag     bag;         /* Problem parameters */
63   PetscReal    t_r;         /* Relaxation time: 4 L^2 / c */
64   /* Exact solution terms */
65   PetscInt    niter; /* Number of series term iterations in exact solutions */
66   PetscReal   eps;   /* Precision value for root finding */
67   PetscReal  *zeroArray; /* Array of root locations */
68 } AppCtx;
69 
70 static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
71 {
72   PetscInt c;
73   for (c = 0; c < Nc; ++c) u[c] = 0.0;
74   return 0;
75 }
76 
77 /* Quadratic space and linear time solution
78 
79   2D:
80   u = x^2
81   v = y^2 - 2xy
82   p = (x + y) t
83   e = 2y
84   f = <2 G, 4 G + 2 \lambda > - <alpha t, alpha t>
85   g = 0
86   \epsilon = / 2x     -y    \
87              \ -y   2y - 2x /
88   Tr(\epsilon) = e = div u = 2y
89   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
90     = 2 G < 2-1, 2 > + \lambda <0, 2> - alpha <t, t>
91     = <2 G, 4 G + 2 \lambda> - <alpha t, alpha t>
92   \frac{1}{M} \frac{dp}{dt} + \alpha \frac{d\varepsilon}{dt} - \nabla \cdot \kappa \nabla p
93     = \frac{1}{M} \frac{dp}{dt} + \kappa \Delta p
94     = (x + y)/M
95 
96   3D:
97   u = x^2
98   v = y^2 - 2xy
99   w = z^2 - 2yz
100   p = (x + y + z) t
101   e = 2z
102   f = <2 G, 4 G + 2 \lambda > - <alpha t, alpha t, alpha t>
103   g = 0
104   \varepsilon = / 2x     -y       0   \
105                 | -y   2y - 2x   -z   |
106                 \  0     -z    2z - 2y/
107   Tr(\varepsilon) = div u = 2z
108   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
109     = 2 G < 2-1, 2-1, 2 > + \lambda <0, 0, 2> - alpha <t, t, t>
110     = <2 G, 2G, 4 G + 2 \lambda> - <alpha t, alpha t, alpha t>
111 */
112 static PetscErrorCode quadratic_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
113 {
114   PetscInt d;
115 
116   for (d = 0; d < dim; ++d) {
117     u[d] = PetscSqr(x[d]) - (d > 0 ? 2.0 * x[d-1] * x[d] : 0.0);
118   }
119   return 0;
120 }
121 
122 static PetscErrorCode linear_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
123 {
124   u[0] = 2.0*x[dim-1];
125   return 0;
126 }
127 
128 static PetscErrorCode linear_linear_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
129 {
130   PetscReal sum = 0.0;
131   PetscInt  d;
132 
133   for (d = 0; d < dim; ++d) sum += x[d];
134   u[0] = sum*time;
135   return 0;
136 }
137 
138 static PetscErrorCode linear_linear_p_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
139 {
140   PetscReal sum = 0.0;
141   PetscInt  d;
142 
143   for (d = 0; d < dim; ++d) sum += x[d];
144   u[0] = sum;
145   return 0;
146 }
147 
148 static void f0_quadratic_linear_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
149                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
150                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
151                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
152 {
153   const PetscReal G      = PetscRealPart(constants[0]);
154   const PetscReal K_u    = PetscRealPart(constants[1]);
155   const PetscReal alpha  = PetscRealPart(constants[2]);
156   const PetscReal M      = PetscRealPart(constants[3]);
157   const PetscReal K_d    = K_u - alpha*alpha*M;
158   const PetscReal lambda = K_d - (2.0 * G) / 3.0;
159   PetscInt        d;
160 
161   for (d = 0; d < dim-1; ++d) {
162     f0[d] -= 2.0*G - alpha*t;
163   }
164   f0[dim-1] -= 2.0*lambda + 4.0*G - alpha*t;
165 }
166 
167 static void f0_quadratic_linear_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
168                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
169                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
170                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
171 {
172   const PetscReal alpha  = PetscRealPart(constants[2]);
173   const PetscReal M      = PetscRealPart(constants[3]);
174   PetscReal       sum    = 0.0;
175   PetscInt        d;
176 
177   for (d = 0; d < dim; ++d) sum += x[d];
178   f0[0] += u_t ? alpha*u_t[uOff[1]] : 0.0;
179   f0[0] += u_t ? u_t[uOff[2]]/M     : 0.0;
180   f0[0] -= sum/M;
181 }
182 
183 /* Quadratic space and trigonometric time solution
184 
185   2D:
186   u = x^2
187   v = y^2 - 2xy
188   p = (x + y) cos(t)
189   e = 2y
190   f = <2 G, 4 G + 2 \lambda > - <alpha cos(t), alpha cos(t)>
191   g = 0
192   \epsilon = / 2x     -y    \
193              \ -y   2y - 2x /
194   Tr(\epsilon) = e = div u = 2y
195   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
196     = 2 G < 2-1, 2 > + \lambda <0, 2> - alpha <cos(t), cos(t)>
197     = <2 G, 4 G + 2 \lambda> - <alpha cos(t), alpha cos(t)>
198   \frac{1}{M} \frac{dp}{dt} + \alpha \frac{d\varepsilon}{dt} - \nabla \cdot \kappa \nabla p
199     = \frac{1}{M} \frac{dp}{dt} + \kappa \Delta p
200     = -(x + y)/M sin(t)
201 
202   3D:
203   u = x^2
204   v = y^2 - 2xy
205   w = z^2 - 2yz
206   p = (x + y + z) cos(t)
207   e = 2z
208   f = <2 G, 4 G + 2 \lambda > - <alpha cos(t), alpha cos(t), alpha cos(t)>
209   g = 0
210   \varepsilon = / 2x     -y       0   \
211                 | -y   2y - 2x   -z   |
212                 \  0     -z    2z - 2y/
213   Tr(\varepsilon) = div u = 2z
214   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
215     = 2 G < 2-1, 2-1, 2 > + \lambda <0, 0, 2> - alpha <cos(t), cos(t), cos(t)>
216     = <2 G, 2G, 4 G + 2 \lambda> - <alpha cos(t), alpha cos(t), alpha cos(t)>
217 */
218 static PetscErrorCode linear_trig_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
219 {
220   PetscReal sum = 0.0;
221   PetscInt  d;
222 
223   for (d = 0; d < dim; ++d) sum += x[d];
224   u[0] = sum*PetscCosReal(time);
225   return 0;
226 }
227 
228 static PetscErrorCode linear_trig_p_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
229 {
230   PetscReal sum = 0.0;
231   PetscInt  d;
232 
233   for (d = 0; d < dim; ++d) sum += x[d];
234   u[0] = -sum*PetscSinReal(time);
235   return 0;
236 }
237 
238 static void f0_quadratic_trig_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
239                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
240                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
241                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
242 {
243   const PetscReal G      = PetscRealPart(constants[0]);
244   const PetscReal K_u    = PetscRealPart(constants[1]);
245   const PetscReal alpha  = PetscRealPart(constants[2]);
246   const PetscReal M      = PetscRealPart(constants[3]);
247   const PetscReal K_d    = K_u - alpha*alpha*M;
248   const PetscReal lambda = K_d - (2.0 * G) / 3.0;
249   PetscInt        d;
250 
251   for (d = 0; d < dim-1; ++d) {
252     f0[d] -= 2.0*G - alpha*PetscCosReal(t);
253   }
254   f0[dim-1] -= 2.0*lambda + 4.0*G - alpha*PetscCosReal(t);
255 }
256 
257 static void f0_quadratic_trig_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
258                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
259                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
260                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
261 {
262   const PetscReal alpha  = PetscRealPart(constants[2]);
263   const PetscReal M      = PetscRealPart(constants[3]);
264   PetscReal       sum    = 0.0;
265   PetscInt        d;
266 
267   for (d = 0; d < dim; ++d) sum += x[d];
268 
269   f0[0] += u_t ? alpha*u_t[uOff[1]] : 0.0;
270   f0[0] += u_t ? u_t[uOff[2]]/M     : 0.0;
271   f0[0] += PetscSinReal(t)*sum/M;
272 }
273 
274 /* Trigonometric space and linear time solution
275 
276 u = sin(2 pi x)
277 v = sin(2 pi y) - 2xy
278 \varepsilon = / 2 pi cos(2 pi x)             -y        \
279               \      -y          2 pi cos(2 pi y) - 2x /
280 Tr(\varepsilon) = div u = 2 pi (cos(2 pi x) + cos(2 pi y)) - 2 x
281 div \sigma = \partial_i \lambda \delta_{ij} \varepsilon_{kk} + \partial_i 2\mu\varepsilon_{ij}
282   = \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) >
283   = \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) >
284 
285   2D:
286   u = sin(2 pi x)
287   v = sin(2 pi y) - 2xy
288   p = (cos(2 pi x) + cos(2 pi y)) t
289   e = 2 pi (cos(2 pi x) + cos(2 pi y)) - 2 x
290   f = < -4 pi^2 sin(2 pi x) (2 G + lambda) - (2 G - 2 lambda), -4 pi^2 sin(2 pi y) (2G + lambda) > + 2 pi alpha t <sin(2 pi x), sin(2 pi y)>
291   g = 0
292   \varepsilon = / 2 pi cos(2 pi x)             -y        \
293                 \      -y          2 pi cos(2 pi y) - 2x /
294   Tr(\varepsilon) = div u = 2 pi (cos(2 pi x) + cos(2 pi y)) - 2 x
295   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
296     = 2 G < -4 pi^2 sin(2 pi x) - 1, -4 pi^2 sin(2 pi y) > + \lambda <-4 pi^2 sin(2 pi x) - 2, -4 pi^2 sin(2 pi y)> - alpha <-2 pi sin(2 pi x) t, -2 pi sin(2 pi y) t>
297     = < -4 pi^2 sin(2 pi x) (2 G + lambda) - (2 G + 2 lambda), -4 pi^2 sin(2 pi y) (2G + lambda) > + 2 pi alpha t <sin(2 pi x), sin(2 pi y)>
298   \frac{1}{M} \frac{dp}{dt} + \alpha \frac{d\varepsilon}{dt} - \nabla \cdot \kappa \nabla p
299     = \frac{1}{M} \frac{dp}{dt} + \kappa \Delta p
300     = (cos(2 pi x) + cos(2 pi y))/M - 4 pi^2 \kappa (cos(2 pi x) + cos(2 pi y)) t
301 
302   3D:
303   u = sin(2 pi x)
304   v = sin(2 pi y) - 2xy
305   v = sin(2 pi y) - 2yz
306   p = (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) t
307   e = 2 pi (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) - 2 x - 2y
308   f = < -4 pi^2 sin(2 pi x) (2 G + lambda) - (2 G + 2 lambda),  -4 pi^2 sin(2 pi y) (2 G + lambda) - (2 G + 2 lambda), -4 pi^2 sin(2 pi z) (2G + lambda) > + 2 pi alpha t <sin(2 pi x), sin(2 pi y), , sin(2 pi z)>
309   g = 0
310   \varepsilon = / 2 pi cos(2 pi x)            -y                     0         \
311                 |         -y       2 pi cos(2 pi y) - 2x            -z         |
312                 \          0                  -z         2 pi cos(2 pi z) - 2y /
313   Tr(\varepsilon) = div u = 2 pi (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) - 2 x - 2 y
314   div \sigma = \partial_i 2 G \epsilon_{ij} + \partial_i \lambda \varepsilon \delta_{ij} - \partial_i \alpha p \delta_{ij}
315     = 2 G < -4 pi^2 sin(2 pi x) - 1, -4 pi^2 sin(2 pi y) - 1, -4 pi^2 sin(2 pi z) > + \lambda <-4 pi^2 sin(2 pi x) - 2, 4 pi^2 sin(2 pi y) - 2, -4 pi^2 sin(2 pi y)> - alpha <-2 pi sin(2 pi x) t, -2 pi sin(2 pi y) t, -2 pi sin(2 pi z) t>
316     = < -4 pi^2 sin(2 pi x) (2 G + lambda) - (2 G + 2 lambda),  -4 pi^2 sin(2 pi y) (2 G + lambda) - (2 G + 2 lambda), -4 pi^2 sin(2 pi z) (2G + lambda) > + 2 pi alpha t <sin(2 pi x), sin(2 pi y), , sin(2 pi z)>
317   \frac{1}{M} \frac{dp}{dt} + \alpha \frac{d\varepsilon}{dt} - \nabla \cdot \kappa \nabla p
318     = \frac{1}{M} \frac{dp}{dt} + \kappa \Delta p
319     = (cos(2 pi x) + cos(2 pi y) + cos(2 pi z))/M - 4 pi^2 \kappa (cos(2 pi x) + cos(2 pi y) + cos(2 pi z)) t
320 */
321 static PetscErrorCode trig_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
322 {
323   PetscInt d;
324 
325   for (d = 0; d < dim; ++d) {
326     u[d] = PetscSinReal(2.*PETSC_PI*x[d]) - (d > 0 ? 2.0 * x[d-1] * x[d] : 0.0);
327   }
328   return 0;
329 }
330 
331 static PetscErrorCode trig_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
332 {
333   PetscReal sum = 0.0;
334   PetscInt  d;
335 
336   for (d = 0; d < dim; ++d) sum += 2.*PETSC_PI*PetscCosReal(2.*PETSC_PI*x[d]) - (d < dim-1 ? 2.*x[d] : 0.0);
337   u[0] = sum;
338   return 0;
339 }
340 
341 static PetscErrorCode trig_linear_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
342 {
343   PetscReal sum = 0.0;
344   PetscInt  d;
345 
346   for (d = 0; d < dim; ++d) sum += PetscCosReal(2.*PETSC_PI*x[d]);
347   u[0] = sum*time;
348   return 0;
349 }
350 
351 static PetscErrorCode trig_linear_p_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
352 {
353   PetscReal sum = 0.0;
354   PetscInt  d;
355 
356   for (d = 0; d < dim; ++d) sum += PetscCosReal(2.*PETSC_PI*x[d]);
357   u[0] = sum;
358   return 0;
359 }
360 
361 static void f0_trig_linear_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
362                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
363                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
364                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
365 {
366   const PetscReal G      = PetscRealPart(constants[0]);
367   const PetscReal K_u    = PetscRealPart(constants[1]);
368   const PetscReal alpha  = PetscRealPart(constants[2]);
369   const PetscReal M      = PetscRealPart(constants[3]);
370   const PetscReal K_d    = K_u - alpha*alpha*M;
371   const PetscReal lambda = K_d - (2.0 * G) / 3.0;
372   PetscInt        d;
373 
374   for (d = 0; d < dim-1; ++d) {
375     f0[d] += PetscSqr(2.*PETSC_PI)*PetscSinReal(2.*PETSC_PI*x[d])*(2.*G + lambda) + 2.0*(G + lambda) - 2.*PETSC_PI*alpha*PetscSinReal(2.*PETSC_PI*x[d])*t;
376   }
377   f0[dim-1] += PetscSqr(2.*PETSC_PI)*PetscSinReal(2.*PETSC_PI*x[dim-1])*(2.*G + lambda) - 2.*PETSC_PI*alpha*PetscSinReal(2.*PETSC_PI*x[dim-1])*t;
378 }
379 
380 static void f0_trig_linear_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
381                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
382                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
383                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
384 {
385   const PetscReal alpha  = PetscRealPart(constants[2]);
386   const PetscReal M      = PetscRealPart(constants[3]);
387   const PetscReal kappa  = PetscRealPart(constants[4]);
388   PetscReal       sum    = 0.0;
389   PetscInt        d;
390 
391   for (d = 0; d < dim; ++d) sum += PetscCosReal(2.*PETSC_PI*x[d]);
392   f0[0] += u_t ? alpha*u_t[uOff[1]] : 0.0;
393   f0[0] += u_t ? u_t[uOff[2]]/M     : 0.0;
394   f0[0] -= sum/M - 4*PetscSqr(PETSC_PI)*kappa*sum*t;
395 }
396 
397 /* Terzaghi Solutions */
398 /* The analytical solutions given here are drawn from chapter 7, section 3, */
399 /* "One-Dimensional Consolidation Problem," from Poroelasticity, by Cheng.  */
400 static PetscErrorCode terzaghi_drainage_pressure(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
401 {
402   AppCtx        *user = (AppCtx *) ctx;
403   Parameter     *param;
404   PetscErrorCode ierr;
405 
406   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
407   if (time <= 0.0) {
408     PetscScalar alpha = param->alpha; /* -  */
409     PetscScalar K_u   = param->K_u;   /* Pa */
410     PetscScalar M     = param->M;     /* Pa */
411     PetscScalar G     = param->mu;    /* Pa */
412     PetscScalar P_0   = param->P_0;   /* Pa */
413     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
414     PetscScalar eta   = (3.0*alpha*G) / (3.0*K_d + 4.0*G);         /* -,       Cheng (B.11) */
415     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
416 
417     u[0] = ((P_0*eta) / (G*S));
418   } else {
419     u[0] = 0.0;
420   }
421   return 0;
422 }
423 
424 static PetscErrorCode terzaghi_initial_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
425 {
426   AppCtx        *user = (AppCtx *) ctx;
427   Parameter     *param;
428   PetscErrorCode ierr;
429 
430   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
431   {
432     PetscScalar K_u   = param->K_u;   /* Pa */
433     PetscScalar G     = param->mu;    /* Pa */
434     PetscScalar P_0   = param->P_0;   /* Pa */
435     PetscReal   L     = param->ymax - param->ymin; /* m */
436     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G)); /* -,       Cheng (B.9)  */
437     PetscReal   zstar = x[1] / L;                                /* - */
438 
439     u[0] = 0.0;
440     u[1] = ((P_0*L*(1.0 - 2.0*nu_u)) / (2.0*G*(1.0 - nu_u))) * (1.0 - zstar);
441   }
442   return 0;
443 }
444 
445 static PetscErrorCode terzaghi_initial_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
446 {
447   AppCtx        *user = (AppCtx *) ctx;
448   Parameter     *param;
449   PetscErrorCode ierr;
450 
451   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
452   {
453     PetscScalar K_u   = param->K_u;   /* Pa */
454     PetscScalar G     = param->mu;    /* Pa */
455     PetscScalar P_0   = param->P_0;   /* Pa */
456     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
457 
458     u[0] = -(P_0*(1.0 - 2.0*nu_u)) / (2.0*G*(1.0 - nu_u));
459   }
460   return 0;
461 }
462 
463 static PetscErrorCode terzaghi_2d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
464 {
465   AppCtx        *user = (AppCtx *) ctx;
466   Parameter     *param;
467   PetscErrorCode ierr;
468 
469   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
470   if (time < 0.0) {
471     ierr = terzaghi_initial_u(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
472   } else {
473     PetscScalar alpha = param->alpha; /* -  */
474     PetscScalar K_u   = param->K_u;   /* Pa */
475     PetscScalar M     = param->M;     /* Pa */
476     PetscScalar G     = param->mu;    /* Pa */
477     PetscScalar P_0   = param->P_0;   /* Pa */
478     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
479     PetscReal   L     = param->ymax - param->ymin; /* m */
480     PetscInt    N     = user->niter, m;
481 
482     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
483     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
484     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
485     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
486     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
487 
488     PetscReal   zstar = x[1] / L;                                  /* - */
489     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
490     PetscScalar F2    = 0.0;
491 
492     for (m = 1; m < 2*N+1; ++m) {
493       if (m%2 == 1) {
494         F2 += (8.0 / PetscSqr(m*PETSC_PI)) * PetscCosReal(0.5*m*PETSC_PI*zstar) * (1.0 - PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar));
495       }
496     }
497     u[0] = 0.0;
498     u[1] = ((P_0*L*(1.0 - 2.0*nu_u)) / (2.0*G*(1.0 - nu_u))) * (1.0 - zstar) + ((P_0*L*(nu_u - nu)) / (2.0*G*(1.0 - nu_u)*(1.0 - nu)))*F2; /* m */
499   }
500   return 0;
501 }
502 
503 static PetscErrorCode terzaghi_2d_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
504 {
505   AppCtx        *user = (AppCtx *) ctx;
506   Parameter     *param;
507   PetscErrorCode ierr;
508 
509   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
510   if (time < 0.0) {
511     ierr = terzaghi_initial_eps(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
512   } else {
513     PetscScalar alpha = param->alpha; /* -  */
514     PetscScalar K_u   = param->K_u;   /* Pa */
515     PetscScalar M     = param->M;     /* Pa */
516     PetscScalar G     = param->mu;    /* Pa */
517     PetscScalar P_0   = param->P_0;   /* Pa */
518     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
519     PetscReal   L     = param->ymax - param->ymin; /* m */
520     PetscInt    N     = user->niter, m;
521 
522     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
523     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
524     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
525     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
526     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
527 
528     PetscReal   zstar = x[1] / L;                                  /* - */
529     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
530     PetscScalar F2_z  = 0.0;
531 
532     for (m = 1; m < 2*N+1; ++m) {
533       if (m%2 == 1) {
534         F2_z += (-4.0 / (m*PETSC_PI*L)) * PetscSinReal(0.5*m*PETSC_PI*zstar) * (1.0 - PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar));
535       }
536     }
537     u[0] = -((P_0*L*(1.0 - 2.0*nu_u)) / (2.0*G*(1.0 - nu_u)*L)) + ((P_0*L*(nu_u - nu)) / (2.0*G*(1.0 - nu_u)*(1.0 - nu)))*F2_z; /* - */
538   }
539   return 0;
540 }
541 
542 // Pressure
543 static PetscErrorCode terzaghi_2d_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
544 {
545   AppCtx        *user = (AppCtx *) ctx;
546   Parameter     *param;
547   PetscErrorCode ierr;
548 
549   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
550   if (time <= 0.0) {
551     ierr = terzaghi_drainage_pressure(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
552   } else {
553     PetscScalar alpha = param->alpha; /* -  */
554     PetscScalar K_u   = param->K_u;   /* Pa */
555     PetscScalar M     = param->M;     /* Pa */
556     PetscScalar G     = param->mu;    /* Pa */
557     PetscScalar P_0   = param->P_0;   /* Pa */
558     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
559     PetscReal   L     = param->ymax - param->ymin; /* m */
560     PetscInt    N     = user->niter, m;
561 
562     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
563     PetscScalar eta   = (3.0*alpha*G) / (3.0*K_d + 4.0*G);         /* -,       Cheng (B.11) */
564     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
565     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
566 
567     PetscReal   zstar = x[1] / L;                                  /* - */
568     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
569     PetscScalar F1    = 0.0;
570 
571     if (PetscAbsScalar((1/M + (alpha*eta)/G) - S) > 1.0e-10) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "S %g != check %g", S, (1/M + (alpha*eta)/G));
572 
573     for (m = 1; m < 2*N+1; ++m) {
574       if (m%2 == 1) {
575         F1 += (4.0 / (m*PETSC_PI)) * PetscSinReal(0.5*m*PETSC_PI*zstar) * PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar);
576       }
577     }
578     u[0] = ((P_0*eta) / (G*S)) * F1; /* Pa */
579   }
580   return 0;
581 }
582 
583 static PetscErrorCode terzaghi_2d_u_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
584 {
585   AppCtx        *user = (AppCtx *) ctx;
586   Parameter     *param;
587   PetscErrorCode ierr;
588 
589   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
590   if (time <= 0.0) {
591     u[0] = 0.0;
592     u[1] = 0.0;
593   } else {
594     PetscScalar alpha = param->alpha; /* -  */
595     PetscScalar K_u   = param->K_u;   /* Pa */
596     PetscScalar M     = param->M;     /* Pa */
597     PetscScalar G     = param->mu;    /* Pa */
598     PetscScalar P_0   = param->P_0;   /* Pa */
599     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
600     PetscReal   L     = param->ymax - param->ymin; /* m */
601     PetscInt    N     = user->niter, m;
602 
603     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
604     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
605     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
606     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
607     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
608 
609     PetscReal   zstar = x[1] / L;                                  /* - */
610     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
611     PetscScalar F2_t  = 0.0;
612 
613     for (m = 1; m < 2*N+1; ++m) {
614       if (m%2 == 1) {
615         F2_t += (2.0*c / PetscSqr(L)) * PetscCosReal(0.5*m*PETSC_PI*zstar) * PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar);
616       }
617     }
618     u[0] = 0.0;
619     u[1] = ((P_0*L*(nu_u - nu)) / (2.0*G*(1.0 - nu_u)*(1.0 - nu)))*F2_t; /* m / s */
620   }
621   return 0;
622 }
623 
624 static PetscErrorCode terzaghi_2d_eps_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
625 {
626   AppCtx        *user = (AppCtx *) ctx;
627   Parameter     *param;
628   PetscErrorCode ierr;
629 
630   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
631   if (time <= 0.0) {
632     u[0] = 0.0;
633   } else {
634     PetscScalar alpha = param->alpha; /* -  */
635     PetscScalar K_u   = param->K_u;   /* Pa */
636     PetscScalar M     = param->M;     /* Pa */
637     PetscScalar G     = param->mu;    /* Pa */
638     PetscScalar P_0   = param->P_0;   /* Pa */
639     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
640     PetscReal   L     = param->ymax - param->ymin; /* m */
641     PetscInt    N     = user->niter, m;
642 
643     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
644     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
645     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
646     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
647     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
648 
649     PetscReal   zstar = x[1] / L;                                  /* - */
650     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
651     PetscScalar F2_zt = 0.0;
652 
653     for (m = 1; m < 2*N+1; ++m) {
654       if (m%2 == 1) {
655         F2_zt += ((-m*PETSC_PI*c) / (L*L*L)) * PetscSinReal(0.5*m*PETSC_PI*zstar) * PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar);
656       }
657     }
658     u[0] = ((P_0*L*(nu_u - nu)) / (2.0*G*(1.0 - nu_u)*(1.0 - nu)))*F2_zt; /* 1 / s */
659   }
660   return 0;
661 }
662 
663 static PetscErrorCode terzaghi_2d_p_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
664 {
665 
666   AppCtx        *user = (AppCtx *) ctx;
667   Parameter     *param;
668   PetscErrorCode ierr;
669 
670   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
671   if (time <= 0.0) {
672     PetscScalar alpha = param->alpha; /* -  */
673     PetscScalar K_u   = param->K_u;   /* Pa */
674     PetscScalar M     = param->M;     /* Pa */
675     PetscScalar G     = param->mu;    /* Pa */
676     PetscScalar P_0   = param->P_0;   /* Pa */
677     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
678     PetscReal   L     = param->ymax - param->ymin; /* m */
679 
680     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
681     PetscScalar eta   = (3.0*alpha*G) / (3.0*K_d + 4.0*G);         /* -,       Cheng (B.11) */
682     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
683     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
684 
685     u[0] = -((P_0*eta) / (G*S)) * PetscSqr(0*PETSC_PI)*c / PetscSqr(2.0*L); /* Pa / s */
686   } else {
687     PetscScalar alpha = param->alpha; /* -  */
688     PetscScalar K_u   = param->K_u;   /* Pa */
689     PetscScalar M     = param->M;     /* Pa */
690     PetscScalar G     = param->mu;    /* Pa */
691     PetscScalar P_0   = param->P_0;   /* Pa */
692     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
693     PetscReal   L     = param->ymax - param->ymin; /* m */
694     PetscInt    N     = user->niter, m;
695 
696     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
697     PetscScalar eta   = (3.0*alpha*G) / (3.0*K_d + 4.0*G);         /* -,       Cheng (B.11) */
698     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
699     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
700 
701     PetscReal   zstar = x[1] / L;                                  /* - */
702     PetscReal   tstar = PetscRealPart(c*time) / PetscSqr(2.0*L);   /* - */
703     PetscScalar F1_t  = 0.0;
704     PetscScalar F1_zz = 0.0;
705 
706     if (PetscAbsScalar((1/M + (alpha*eta)/G) - S) > 1.0e-10) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "S %g != check %g", S, (1/M + (alpha*eta)/G));
707 
708     for (m = 1; m < 2*N+1; ++m) {
709       if (m%2 == 1) {
710         F1_t += ((-m*PETSC_PI*c) / PetscSqr(L)) * PetscSinReal(0.5*m*PETSC_PI*zstar) * PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar);
711         F1_zz += (-m*PETSC_PI / PetscSqr(L)) * PetscSinReal(0.5*m*PETSC_PI*zstar) * PetscExpReal(-PetscSqr(m*PETSC_PI)*tstar);
712       }
713     }
714     u[0] = ((P_0*eta) / (G*S)) * F1_t; /* Pa / s */
715   }
716   return 0;
717 }
718 
719 /* Mandel Solutions */
720 static PetscErrorCode mandel_drainage_pressure(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
721 {
722   AppCtx        *user = (AppCtx *) ctx;
723   Parameter     *param;
724   PetscErrorCode ierr;
725 
726   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
727   if (time <= 0.0) {
728     PetscScalar alpha = param->alpha; /* -  */
729     PetscScalar K_u   = param->K_u;   /* Pa */
730     PetscScalar M     = param->M;     /* Pa */
731     PetscScalar G     = param->mu;    /* Pa */
732     PetscScalar P_0   = param->P_0;   /* Pa */
733     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
734     PetscReal   a     = 0.5*(param->xmax - param->xmin); /* m */
735     PetscInt    N     = user->niter, n;
736 
737     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
738     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
739     PetscScalar B     = alpha*M / K_u;                             /* -,       Cheng (B.12) */
740     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
741     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
742 
743     PetscScalar A1    = 3.0 / (B * (1.0 + nu_u));
744     PetscReal   aa    = 0.0;
745     PetscReal   p     = 0.0;
746     PetscReal   time  = 0.0;
747 
748     for (n = 1; n < N+1; ++n) {
749       aa = user->zeroArray[n-1];
750       p += (PetscSinReal(aa) / (aa - PetscSinReal(aa)*PetscCosReal(aa))) * (PetscCosReal( (aa*x[0]) / a) - PetscCosReal(aa)) * PetscExpReal(-1.0*(aa*aa * PetscRealPart(c) * time)/(a*a));
751     }
752     u[0] = ((2.0 * P_0) / (a*A1)) * p;
753   } else {
754     u[0] = 0.0;
755   }
756   return 0;
757 }
758 
759 static PetscErrorCode mandel_initial_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
760 {
761   AppCtx        *user = (AppCtx *) ctx;
762   Parameter     *param;
763   PetscErrorCode ierr;
764 
765   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
766   {
767     PetscScalar alpha = param->alpha; /* -  */
768     PetscScalar K_u   = param->K_u;   /* Pa */
769     PetscScalar M     = param->M;     /* Pa */
770     PetscScalar G     = param->mu;    /* Pa */
771     PetscScalar P_0   = param->P_0;   /* Pa */
772     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
773     PetscScalar a     = 0.5*(param->xmax - param->xmin); /* m */
774     PetscInt    N     = user->niter, n;
775 
776     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
777     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
778     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
779     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
780     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
781 
782     PetscScalar A_s   = 0.0;
783     PetscScalar B_s   = 0.0;
784     PetscScalar time  = 0.0;
785     PetscScalar alpha_n = 0.0;
786 
787     for (n = 1; n < N+1; ++n) {
788       alpha_n = user->zeroArray[n-1];
789       A_s += ((PetscSinReal(alpha_n) * PetscCosReal(alpha_n)) / (alpha_n - PetscSinReal(alpha_n) * PetscCosReal(alpha_n)) ) * PetscExpReal(-1*(alpha_n*alpha_n*c*time)/(a*a));
790       B_s += (PetscCosReal(alpha_n) / (alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n))) * PetscSinReal( (alpha_n * x[0])/a ) * PetscExpReal(-1*(alpha_n*alpha_n*c*time)/(a*a));
791     }
792     u[0] = ((P_0*nu)/(2.0*G*a) - (P_0*nu_u)/(G*a) * A_s)* x[0] + P_0/G * B_s;
793     u[1] = (-1*(P_0*(1.0-nu))/(2*G*a) + (P_0*(1-nu_u))/(G*a) * A_s )*x[1];
794   }
795   return 0;
796 }
797 
798 static PetscErrorCode mandel_initial_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
799 {
800   AppCtx        *user = (AppCtx *) ctx;
801   Parameter     *param;
802   PetscErrorCode ierr;
803 
804   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
805   {
806     PetscScalar alpha = param->alpha; /* -  */
807     PetscScalar K_u   = param->K_u;   /* Pa */
808     PetscScalar M     = param->M;     /* Pa */
809     PetscScalar G     = param->mu;    /* Pa */
810     PetscScalar P_0   = param->P_0;   /* Pa */
811     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
812     PetscReal   a     = 0.5*(param->xmax - param->xmin); /* m */
813     PetscInt    N     = user->niter, n;
814 
815     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
816     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
817     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
818     PetscReal   c     = PetscRealPart(kappa / S);                  /* m^2 / s, Cheng (B.16) */
819 
820     PetscReal   aa    = 0.0;
821     PetscReal   eps_A = 0.0;
822     PetscReal   eps_B = 0.0;
823     PetscReal   eps_C = 0.0;
824     PetscReal   time  = 0.0;
825 
826     for (n = 1; n < N+1; ++n) {
827       aa     = user->zeroArray[n-1];
828       eps_A += (aa * PetscExpReal( (-1.0*aa*aa*c*time)/(a*a) )*PetscCosReal(aa)*PetscCosReal( (aa*x[0])/a )) / (a * (aa - PetscSinReal(aa)*PetscCosReal(aa)));
829       eps_B += ( PetscExpReal( (-1.0*aa*aa*c*time)/(a*a) )*PetscSinReal(aa)*PetscCosReal(aa) ) / (aa - PetscSinReal(aa)*PetscCosReal(aa));
830       eps_C += ( PetscExpReal( (-1.0*aa*aa*c*time)/(aa*aa) )*PetscSinReal(aa)*PetscCosReal(aa) ) / (aa - PetscSinReal(aa)*PetscCosReal(aa));
831     }
832     u[0] = (P_0/G)*eps_A + ( (P_0*nu)/(2.0*G*a) ) - eps_B/(G*a) - (P_0*(1-nu))/(2*G*a) + eps_C/(G*a);
833   }
834   return 0;
835 }
836 
837 // Displacement
838 static PetscErrorCode mandel_2d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
839 {
840 
841   Parameter  *param;
842   PetscErrorCode ierr;
843 
844   AppCtx *user = (AppCtx *) ctx;
845 
846   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
847   if (time <= 0.0) {
848     ierr = mandel_initial_u(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
849   } else {
850     PetscInt NITER = user->niter;
851     PetscScalar alpha = param->alpha;
852     PetscScalar K_u = param->K_u;
853     PetscScalar M = param->M;
854     PetscScalar G = param->mu;
855     PetscScalar k = param->k;
856     PetscScalar mu_f = param->mu_f;
857     PetscScalar F = param->P_0;
858 
859     PetscScalar K_d = K_u - alpha*alpha*M;
860     PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
861     PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
862     PetscScalar kappa = k / mu_f;
863     PetscReal   a = (param->xmax - param->xmin) / 2.0;
864     PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu) ) / ( alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
865 
866     // Series term
867     PetscScalar A_x = 0.0;
868     PetscScalar B_x = 0.0;
869 
870     for (PetscInt n=1; n < NITER+1; n++) {
871       PetscReal alpha_n = user->zeroArray[n-1];
872 
873       A_x += ( (PetscSinReal(alpha_n) * PetscCosReal(alpha_n)) / (alpha_n - PetscSinReal(alpha_n) * PetscCosReal(alpha_n)) ) * PetscExpReal( -1*(alpha_n*alpha_n*c*time)/(a*a) );
874       B_x += ( PetscCosReal(alpha_n) / (alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) ) * PetscSinReal( (alpha_n * x[0])/a ) * PetscExpReal( -1*(alpha_n*alpha_n*c*time)/(a*a) );
875     }
876     u[0] = ((F*nu)/(2.0*G*a) - (F*nu_u)/(G*a) * A_x)* x[0] + F/G * B_x;
877     u[1] = (-1*(F*(1.0-nu))/(2*G*a) + (F*(1-nu_u))/(G*a) * A_x )*x[1];
878   }
879   return 0;
880 }
881 
882 // Trace strain
883 static PetscErrorCode mandel_2d_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
884 {
885 
886   Parameter  *param;
887   PetscErrorCode ierr;
888 
889   AppCtx *user = (AppCtx *) ctx;
890 
891   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
892   if (time <= 0.0) {
893     ierr = mandel_initial_eps(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
894   } else {
895     PetscInt NITER = user->niter;
896     PetscScalar alpha = param->alpha;
897     PetscScalar K_u = param->K_u;
898     PetscScalar M = param->M;
899     PetscScalar G = param->mu;
900     PetscScalar k = param->k;
901     PetscScalar mu_f = param->mu_f;
902     PetscScalar F = param->P_0;
903 
904     PetscScalar K_d = K_u - alpha*alpha*M;
905     PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
906     PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
907     PetscScalar kappa = k / mu_f;
908     //const PetscScalar B = (alpha*M)/(K_d + alpha*alpha * M);
909 
910     //const PetscScalar b = (YMAX - YMIN) / 2.0;
911     PetscScalar a = (param->xmax - param->xmin) / 2.0;
912     PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
913 
914     // Series term
915     PetscScalar eps_A = 0.0;
916     PetscScalar eps_B = 0.0;
917     PetscScalar eps_C = 0.0;
918 
919     for (PetscInt n=1; n < NITER+1; n++)
920     {
921       PetscReal aa = user->zeroArray[n-1];
922 
923       eps_A += (aa * PetscExpReal( (-1.0*aa*aa*c*time)/(a*a) )*PetscCosReal(aa)*PetscCosReal( (aa*x[0])/a )) / (a * (aa - PetscSinReal(aa)*PetscCosReal(aa)));
924 
925       eps_B += ( PetscExpReal( (-1.0*aa*aa*c*time)/(a*a) )*PetscSinReal(aa)*PetscCosReal(aa) ) / (aa - PetscSinReal(aa)*PetscCosReal(aa));
926 
927       eps_C += ( PetscExpReal( (-1.0*aa*aa*c*time)/(aa*aa) )*PetscSinReal(aa)*PetscCosReal(aa) ) / (aa - PetscSinReal(aa)*PetscCosReal(aa));
928     }
929 
930     u[0] = (F/G)*eps_A + ( (F*nu)/(2.0*G*a) ) - eps_B/(G*a) - (F*(1-nu))/(2*G*a) + eps_C/(G*a);
931   }
932   return 0;
933 
934 }
935 
936 // Pressure
937 static PetscErrorCode mandel_2d_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
938 {
939 
940   Parameter  *param;
941   PetscErrorCode ierr;
942 
943   AppCtx *user = (AppCtx *) ctx;
944 
945   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
946   if (time <= 0.0) {
947     ierr = mandel_drainage_pressure(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
948   } else {
949     PetscInt NITER = user->niter;
950 
951     PetscScalar alpha = param->alpha;
952     PetscScalar K_u = param->K_u;
953     PetscScalar M = param->M;
954     PetscScalar G = param->mu;
955     PetscScalar k = param->k;
956     PetscScalar mu_f = param->mu_f;
957     PetscScalar F = param->P_0;
958 
959     PetscScalar K_d = K_u - alpha*alpha*M;
960     PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
961     PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
962     PetscScalar kappa = k / mu_f;
963     PetscScalar B = (alpha*M)/(K_d + alpha*alpha * M);
964 
965     PetscReal   a  = (param->xmax - param->xmin) / 2.0;
966     PetscReal   c  = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
967     PetscScalar A1 = 3.0 / (B * (1.0 + nu_u));
968     //PetscScalar A2 = (alpha * (1.0 - 2.0*nu)) / (1.0 - nu);
969 
970     // Series term
971     PetscScalar aa = 0.0;
972     PetscScalar p  = 0.0;
973 
974     for (PetscInt n=1; n < NITER+1; n++)
975     {
976       aa = user->zeroArray[n-1];
977       p += (PetscSinReal(aa)/ (aa - PetscSinReal(aa)*PetscCosReal(aa))) * (PetscCosReal( (aa*x[0]) / a) - PetscCosReal(aa)) * PetscExpReal(-1.0*(aa*aa * c * time)/(a*a));
978     }
979     u[0] = ((2.0 * F) / (a*A1) ) * p;
980   }
981   return 0;
982 }
983 
984 // Time derivative of displacement
985 static PetscErrorCode mandel_2d_u_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
986 {
987 
988   Parameter  *param;
989   PetscErrorCode ierr;
990 
991   AppCtx *user = (AppCtx *) ctx;
992 
993   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
994 
995   PetscInt NITER = user->niter;
996   PetscScalar alpha = param->alpha;
997   PetscScalar K_u = param->K_u;
998   PetscScalar M = param->M;
999   PetscScalar G = param->mu;
1000   PetscScalar F = param->P_0;
1001 
1002   PetscScalar K_d = K_u - alpha*alpha*M;
1003   PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
1004   PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
1005   PetscScalar kappa = param->k / param->mu_f;
1006   PetscReal   a = (param->xmax - param->xmin) / 2.0;
1007   PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
1008 
1009   // Series term
1010   PetscScalar A_s_t = 0.0;
1011   PetscScalar B_s_t = 0.0;
1012 
1013   for (PetscInt n=1; n < NITER+1; n++)
1014   {
1015     PetscReal alpha_n = user->zeroArray[n-1];
1016 
1017     A_s_t += (-1.0*alpha_n*alpha_n*c*PetscExpReal( (-1.0*alpha_n*alpha_n*time)/(a*a))*PetscSinReal( (alpha_n*x[0])/a ) * PetscCosReal(alpha_n) ) / ( a*a*(alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) );
1018     B_s_t += (-1.0*alpha_n*alpha_n*c*PetscExpReal( (-1.0*alpha_n*alpha_n*time)/(a*a))*PetscSinReal(  alpha_n         ) * PetscCosReal(alpha_n) ) / ( a*a*(alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) );
1019   }
1020 
1021   u[0] = (F/G)*A_s_t - ( (F*nu_u*x[0])/(G*a) )*B_s_t;
1022   u[1] = ( (F*x[1]*(1 - nu_u)) / (G*a) )*B_s_t;
1023 
1024   return 0;
1025 }
1026 
1027 // Time derivative of trace strain
1028 static PetscErrorCode mandel_2d_eps_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1029 {
1030 
1031   Parameter  *param;
1032   PetscErrorCode ierr;
1033 
1034   AppCtx *user = (AppCtx *) ctx;
1035 
1036   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1037 
1038   PetscInt NITER = user->niter;
1039   PetscScalar alpha = param->alpha;
1040   PetscScalar K_u = param->K_u;
1041   PetscScalar M = param->M;
1042   PetscScalar G = param->mu;
1043   PetscScalar k = param->k;
1044   PetscScalar mu_f = param->mu_f;
1045   PetscScalar F = param->P_0;
1046 
1047   PetscScalar K_d = K_u - alpha*alpha*M;
1048   PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
1049   PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
1050   PetscScalar kappa = k / mu_f;
1051   //const PetscScalar B = (alpha*M)/(K_d + alpha*alpha * M);
1052 
1053   //const PetscScalar b = (YMAX - YMIN) / 2.0;
1054   PetscReal   a = (param->xmax - param->xmin) / 2.0;
1055   PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
1056 
1057   // Series term
1058   PetscScalar eps_As = 0.0;
1059   PetscScalar eps_Bs = 0.0;
1060   PetscScalar eps_Cs = 0.0;
1061 
1062   for (PetscInt n=1; n < NITER+1; n++)
1063   {
1064     PetscReal alpha_n = user->zeroArray[n-1];
1065 
1066     eps_As += (-1.0*alpha_n*alpha_n*alpha_n*c*PetscExpReal( (-1.0*alpha_n*alpha_n*c*time)/(a*a) )*PetscCosReal(alpha_n)*PetscCosReal( (alpha_n*x[0])/a ) ) / ( alpha_n*alpha_n*alpha_n*(alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) );
1067     eps_Bs += (-1.0*alpha_n*alpha_n*c*PetscExpReal( (-1.0*alpha_n*alpha_n*c*time)/(a*a) )*PetscSinReal(alpha_n)*PetscCosReal(alpha_n) ) / (alpha_n*alpha_n * (alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) );
1068     eps_Cs += (-1.0*alpha_n*alpha_n*c*PetscExpReal( (-1.0*alpha_n*alpha_n*c*time)/(a*a) )*PetscSinReal(alpha_n)*PetscCosReal(alpha_n) ) / (alpha_n*alpha_n * (alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n)) );
1069   }
1070 
1071   u[0] = (F/G)*eps_As - ( (F*nu_u)/(G*a) )*eps_Bs + ( (F*(1-nu_u))/(G*a) )*eps_Cs;
1072   return 0;
1073 
1074 }
1075 
1076 // Time derivative of pressure
1077 static PetscErrorCode mandel_2d_p_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1078 {
1079 
1080   Parameter  *param;
1081   PetscErrorCode ierr;
1082 
1083   AppCtx *user = (AppCtx *) ctx;
1084 
1085   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1086 
1087   PetscInt NITER = user->niter;
1088 
1089   PetscScalar alpha = param->alpha;
1090   PetscScalar K_u = param->K_u;
1091   PetscScalar M = param->M;
1092   PetscScalar G = param->mu;
1093   PetscScalar k = param->k;
1094   PetscScalar mu_f = param->mu_f;
1095   PetscScalar F = param->P_0;
1096 
1097   PetscScalar K_d = K_u - alpha*alpha*M;
1098   PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
1099   PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
1100   PetscScalar kappa = k / mu_f;
1101 
1102   PetscReal   a = (param->xmax - param->xmin) / 2.0;
1103   PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
1104   //PetscScalar A1 = 3.0 / (B * (1.0 + nu_u));
1105   //PetscScalar A2 = (alpha * (1.0 - 2.0*nu)) / (1.0 - nu);
1106 
1107   // Series term
1108   PetscScalar P_s = 0.0;
1109 
1110   for (PetscInt n=1; n < NITER+1; n++)
1111   {
1112     PetscReal alpha_n = user->zeroArray[n-1];
1113 
1114     P_s += (-1.0*alpha_n*alpha_n*c*( -1.0*PetscCosReal(alpha_n) + PetscCosReal( (alpha_n*x[0])/a ) )*PetscExpReal( (-1.0*alpha_n*alpha_n*c*time)/(a*a) )*PetscSinReal(alpha_n) ) / ( a*a*(alpha_n - PetscSinReal(alpha_n)*PetscCosReal(alpha_n) ) );
1115   }
1116   u[0] = ( (2.0*F*(-2.0*nu + 3.0*nu_u))/(3.0*a*alpha*(1.0 - 2.0*nu) ) );
1117 
1118   return 0;
1119 }
1120 
1121 /* Cryer Solutions */
1122 static PetscErrorCode cryer_drainage_pressure(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1123 {
1124   AppCtx        *user = (AppCtx *) ctx;
1125   Parameter     *param;
1126   PetscErrorCode ierr;
1127 
1128   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1129   if (time <= 0.0) {
1130     PetscScalar alpha = param->alpha; /* -  */
1131     PetscScalar K_u   = param->K_u;   /* Pa */
1132     PetscScalar M     = param->M;     /* Pa */
1133     PetscScalar P_0   = param->P_0;   /* Pa */
1134     PetscScalar B     = alpha*M / K_u; /* -, Cheng (B.12) */
1135 
1136     u[0] = P_0*B;
1137   } else {
1138     u[0] = 0.0;
1139   }
1140   return 0;
1141 }
1142 
1143 static PetscErrorCode cryer_initial_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1144 {
1145   AppCtx        *user = (AppCtx *) ctx;
1146   Parameter     *param;
1147   PetscErrorCode ierr;
1148 
1149   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1150   {
1151     PetscScalar K_u   = param->K_u;   /* Pa */
1152     PetscScalar G     = param->mu;    /* Pa */
1153     PetscScalar P_0   = param->P_0;   /* Pa */
1154     PetscReal   R_0   = param->ymax;  /* m */
1155     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1156 
1157     PetscScalar u_0   = -P_0*R_0*(1. - 2.*nu_u) / (2.*G*(1. + nu_u)); /* Cheng (7.407) */
1158     PetscReal   u_sc  = PetscRealPart(u_0)/R_0;
1159 
1160     u[0] = u_sc * x[0];
1161     u[1] = u_sc * x[1];
1162     u[2] = u_sc * x[2];
1163   }
1164   return 0;
1165 }
1166 
1167 static PetscErrorCode cryer_initial_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1168 {
1169   AppCtx        *user = (AppCtx *) ctx;
1170   Parameter     *param;
1171   PetscErrorCode ierr;
1172 
1173   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1174   {
1175     PetscScalar K_u   = param->K_u;   /* Pa */
1176     PetscScalar G     = param->mu;    /* Pa */
1177     PetscScalar P_0   = param->P_0;   /* Pa */
1178     PetscReal   R_0   = param->ymax;  /* m */
1179     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1180 
1181     PetscScalar u_0   = -P_0*R_0*(1. - 2.*nu_u) / (2.*G*(1. + nu_u)); /* Cheng (7.407) */
1182     PetscReal   u_sc  = PetscRealPart(u_0)/R_0;
1183 
1184     /* div R = 1/R^2 d/dR R^2 R = 3 */
1185     u[0] = 3.*u_sc;
1186     u[1] = 3.*u_sc;
1187     u[2] = 3.*u_sc;
1188   }
1189   return 0;
1190 }
1191 
1192 // Displacement
1193 static PetscErrorCode cryer_3d_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1194 {
1195   AppCtx        *user = (AppCtx *) ctx;
1196   Parameter     *param;
1197   PetscErrorCode ierr;
1198 
1199   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1200   if (time <= 0.0) {
1201     ierr = cryer_initial_u(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
1202   } else {
1203     PetscScalar alpha = param->alpha; /* -  */
1204     PetscScalar K_u   = param->K_u;   /* Pa */
1205     PetscScalar M     = param->M;     /* Pa */
1206     PetscScalar G     = param->mu;    /* Pa */
1207     PetscScalar P_0   = param->P_0;   /* Pa */
1208     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
1209     PetscReal   R_0   = param->ymax;  /* m */
1210     PetscInt    N     = user->niter, n;
1211 
1212     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
1213     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
1214     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1215     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
1216     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
1217     PetscScalar u_inf = -P_0*R_0*(1. - 2.*nu) / (2.*G*(1. + nu));  /* m,       Cheng (7.388) */
1218 
1219     PetscReal   R      = PetscSqrtReal(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
1220     PetscReal   R_star = R/R_0;
1221     PetscReal   tstar  = PetscRealPart(c*time) / PetscSqr(R_0);    /* - */
1222     PetscReal   A_n    = 0.0;
1223     PetscScalar u_sc;
1224 
1225     for (n = 1; n < N+1; ++n) {
1226       const PetscReal x_n = user->zeroArray[n-1];
1227       const PetscReal E_n = PetscRealPart(PetscSqr(1 - nu)*PetscSqr(1 + nu_u)*x_n - 18.0*(1 + nu)*(nu_u - nu)*(1 - nu_u));
1228 
1229       /* m , Cheng (7.404) */
1230       A_n += PetscRealPart(
1231              (12.0*(1.0 + nu)*(nu_u - nu))/((1.0 - 2.0*nu)*E_n*PetscSqr(R_star)*x_n*PetscSinReal(PetscSqrtReal(x_n))) *
1232              (3.0*(nu_u - nu) * (PetscSinReal(R_star * PetscSqrtReal(x_n)) - R_star*PetscSqrtReal(x_n)*PetscCosReal(R_star * PetscSqrtReal(x_n)))
1233               + (1.0 - nu)*(1.0 - 2.0*nu)*PetscPowRealInt(R_star, 3)*x_n*PetscSinReal(PetscSqrtReal(x_n))) * PetscExpReal(-x_n * tstar));
1234     }
1235     u_sc = PetscRealPart(u_inf) * (R_star - A_n);
1236     u[0] = u_sc * x[0] / R;
1237     u[1] = u_sc * x[1] / R;
1238     u[2] = u_sc * x[2] / R;
1239   }
1240   return 0;
1241 }
1242 
1243 // Volumetric Strain
1244 static PetscErrorCode cryer_3d_eps(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1245 {
1246   AppCtx        *user = (AppCtx *) ctx;
1247   Parameter     *param;
1248   PetscErrorCode ierr;
1249 
1250   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1251   if (time <= 0.0) {
1252     ierr = cryer_initial_eps(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
1253   } else {
1254     PetscScalar alpha = param->alpha; /* -  */
1255     PetscScalar K_u   = param->K_u;   /* Pa */
1256     PetscScalar M     = param->M;     /* Pa */
1257     PetscScalar G     = param->mu;    /* Pa */
1258     PetscScalar P_0   = param->P_0;   /* Pa */
1259     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
1260     PetscReal   R_0   = param->ymax;  /* m */
1261     PetscInt    N     = user->niter, n;
1262 
1263     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
1264     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
1265     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1266     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
1267     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
1268     PetscScalar u_inf = -P_0*R_0*(1. - 2.*nu) / (2.*G*(1. + nu));  /* m,       Cheng (7.388) */
1269 
1270     PetscReal   R      = PetscSqrtReal(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
1271     PetscReal   R_star = R/R_0;
1272     PetscReal   tstar  = PetscRealPart(c*time) / PetscSqr(R_0);    /* - */
1273     PetscReal   divA_n = 0.0;
1274 
1275     if (R_star < PETSC_SMALL) {
1276       for (n = 1; n < N+1; ++n) {
1277         const PetscReal x_n = user->zeroArray[n-1];
1278         const PetscReal E_n = PetscRealPart(PetscSqr(1 - nu)*PetscSqr(1 + nu_u)*x_n - 18.0*(1 + nu)*(nu_u - nu)*(1 - nu_u));
1279 
1280         divA_n += PetscRealPart(
1281                   (12.0*(1.0 + nu)*(nu_u - nu))/((1.0 - 2.0*nu)*E_n*PetscSqr(R_star)*x_n*PetscSinReal(PetscSqrtReal(x_n))) *
1282                   (3.0*(nu_u - nu) * PetscSqrtReal(x_n) * ((2.0 + PetscSqr(R_star*PetscSqrtReal(x_n))) - 2.0*PetscCosReal(R_star * PetscSqrtReal(x_n)))
1283                   + 5.0 * (1.0 - nu)*(1.0 - 2.0*nu)*PetscPowRealInt(R_star, 2)*x_n*PetscSinReal(PetscSqrtReal(x_n))) * PetscExpReal(-x_n * tstar));
1284       }
1285     } else {
1286       for (n = 1; n < N+1; ++n) {
1287         const PetscReal x_n = user->zeroArray[n-1];
1288         const PetscReal E_n = PetscRealPart(PetscSqr(1 - nu)*PetscSqr(1 + nu_u)*x_n - 18.0*(1 + nu)*(nu_u - nu)*(1 - nu_u));
1289 
1290         divA_n += PetscRealPart(
1291                   (12.0*(1.0 + nu)*(nu_u - nu))/((1.0 - 2.0*nu)*E_n*PetscSqr(R_star)*x_n*PetscSinReal(PetscSqrtReal(x_n))) *
1292                   (3.0*(nu_u - nu) * PetscSqrtReal(x_n) * ((2.0/(R_star*PetscSqrtReal(x_n)) + R_star*PetscSqrtReal(x_n))*PetscSinReal(R_star * PetscSqrtReal(x_n)) - 2.0*PetscCosReal(R_star * PetscSqrtReal(x_n)))
1293                   + 5.0 * (1.0 - nu)*(1.0 - 2.0*nu)*PetscPowRealInt(R_star, 2)*x_n*PetscSinReal(PetscSqrtReal(x_n))) * PetscExpReal(-x_n * tstar));
1294       }
1295     }
1296     if (PetscAbsReal(divA_n) > 1e3) PetscPrintf(PETSC_COMM_SELF, "(%g, %g, %g) divA_n: %g\n", x[0], x[1], x[2], divA_n);
1297     u[0] = PetscRealPart(u_inf)/R_0 * (3.0 - divA_n);
1298   }
1299   return 0;
1300 }
1301 
1302 // Pressure
1303 static PetscErrorCode cryer_3d_p(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1304 {
1305   AppCtx        *user = (AppCtx *) ctx;
1306   Parameter     *param;
1307   PetscErrorCode ierr;
1308 
1309   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1310   if (time <= 0.0) {
1311     ierr = cryer_drainage_pressure(dim, time, x, Nc, u, ctx);CHKERRQ(ierr);
1312   } else {
1313     PetscScalar alpha = param->alpha; /* -  */
1314     PetscScalar K_u   = param->K_u;   /* Pa */
1315     PetscScalar M     = param->M;     /* Pa */
1316     PetscScalar G     = param->mu;    /* Pa */
1317     PetscScalar P_0   = param->P_0;   /* Pa */
1318     PetscReal   R_0   = param->ymax;  /* m */
1319     PetscScalar kappa = param->k / param->mu_f;    /* m^2 / (Pa s) */
1320     PetscInt    N     = user->niter, n;
1321 
1322     PetscScalar K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
1323     PetscScalar eta   = (3.0*alpha*G) / (3.0*K_d + 4.0*G);         /* -,       Cheng (B.11) */
1324     PetscScalar nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
1325     PetscScalar nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1326     PetscScalar S     = (3.0*K_u + 4.0*G) / (M*(3.0*K_d + 4.0*G)); /* Pa^{-1}, Cheng (B.14) */
1327     PetscScalar c     = kappa / S;                                 /* m^2 / s, Cheng (B.16) */
1328     PetscScalar R     = PetscSqrtReal(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
1329 
1330     PetscScalar R_star = R / R_0;
1331     PetscScalar t_star = PetscRealPart(c * time) / PetscSqr(R_0);
1332     PetscReal   A_x    = 0.0;
1333 
1334     for (n = 1; n < N+1; ++n) {
1335       const PetscReal x_n = user->zeroArray[n-1];
1336       const PetscReal E_n = PetscRealPart(PetscSqr(1 - nu)*PetscSqr(1 + nu_u)*x_n - 18.0*(1 + nu)*(nu_u - nu)*(1 - nu_u));
1337 
1338       A_x += PetscRealPart(((18.0*PetscSqr(nu_u - nu)) / (eta * E_n)) * (PetscSinReal(R_star * PetscSqrtReal(x_n)) / (R_star * PetscSinReal(PetscSqrtReal(x_n))) - 1.0) * PetscExpReal(-x_n * t_star)); /* Cheng (7.395) */
1339     }
1340     u[0] = P_0 * A_x;
1341   }
1342   return 0;
1343 }
1344 
1345 /* Boundary Kernels */
1346 static void f0_terzaghi_bd_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1347                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1348                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1349                                     PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1350 {
1351   const PetscReal P = PetscRealPart(constants[5]);
1352 
1353   f0[0] = 0.0;
1354   f0[1] = P;
1355 }
1356 
1357 static void f0_mandel_bd_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1358                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1359                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1360                                     PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1361 {
1362   // Uniform stress distribution
1363   /* PetscScalar xmax =  0.5;
1364   PetscScalar xmin = -0.5;
1365   PetscScalar ymax =  0.5;
1366   PetscScalar ymin = -0.5;
1367   PetscScalar P = constants[5];
1368   PetscScalar aL = (xmax - xmin) / 2.0;
1369   PetscScalar sigma_zz = -1.0*P / aL; */
1370 
1371   // Analytical (parabolic) stress distribution
1372   PetscReal a1, a2, am;
1373   PetscReal y1, y2, ym;
1374 
1375   PetscInt NITER = 500;
1376   PetscReal EPS = 0.000001;
1377   PetscReal zeroArray[500]; /* NITER */
1378   PetscReal xmax =  1.0;
1379   PetscReal xmin =  0.0;
1380   PetscReal ymax =  0.1;
1381   PetscReal ymin =  0.0;
1382   PetscReal lower[2], upper[2];
1383 
1384   lower[0] = xmin - (xmax - xmin) / 2.0;
1385   lower[1] = ymin - (ymax - ymin) / 2.0;
1386   upper[0] = xmax - (xmax - xmin) / 2.0;
1387   upper[1] = ymax - (ymax - ymin) / 2.0;
1388 
1389   xmin = lower[0];
1390   ymin = lower[1];
1391   xmax = upper[0];
1392   ymax = upper[1];
1393 
1394   PetscScalar G     = constants[0];
1395   PetscScalar K_u   = constants[1];
1396   PetscScalar alpha = constants[2];
1397   PetscScalar M     = constants[3];
1398   PetscScalar kappa = constants[4];
1399   PetscScalar F     = constants[5];
1400 
1401   PetscScalar K_d = K_u - alpha*alpha*M;
1402   PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
1403   PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
1404   PetscReal   aL = (xmax - xmin) / 2.0;
1405   PetscReal   c = PetscRealPart(((2.0*kappa*G) * (1.0 - nu) * (nu_u - nu)) / (alpha*alpha * (1.0 - 2.0*nu) * (1.0 - nu_u)));
1406   PetscScalar B = (3.0 * (nu_u - nu) ) / ( alpha * (1.0 - 2.0*nu) * (1.0 + nu_u));
1407   PetscScalar A1 = 3.0 / (B * (1.0 + nu_u));
1408   PetscScalar A2 = (alpha * (1.0 - 2.0*nu)) / (1.0 - nu);
1409 
1410   // Generate zero values
1411   for (PetscInt i=1; i < NITER+1; i++)
1412   {
1413     a1 = ((PetscReal) i - 1.0 ) * PETSC_PI * PETSC_PI / 4.0 + EPS;
1414     a2 = a1 + PETSC_PI/2;
1415     for (PetscInt j=0; j<NITER; j++)
1416     {
1417       y1 = PetscTanReal(a1) - PetscRealPart(A1/A2)*a1;
1418       y2 = PetscTanReal(a2) - PetscRealPart(A1/A2)*a2;
1419       am = (a1 + a2)/2.0;
1420       ym = PetscTanReal(am) - PetscRealPart(A1/A2)*am;
1421       if ((ym*y1) > 0)
1422       {
1423         a1 = am;
1424       } else {
1425         a2 = am;
1426       }
1427       if (PetscAbsReal(y2) < EPS)
1428       {
1429         am = a2;
1430       }
1431     }
1432     zeroArray[i-1] = am;
1433   }
1434 
1435   // Solution for sigma_zz
1436   PetscScalar A_x = 0.0;
1437   PetscScalar B_x = 0.0;
1438 
1439   for (PetscInt n=1; n < NITER+1; n++)
1440   {
1441     PetscReal alpha_n = zeroArray[n-1];
1442 
1443     A_x += ( PetscSinReal(alpha_n) / (alpha_n - PetscSinReal(alpha_n) * PetscCosReal(alpha_n))) * PetscCosReal( (alpha_n * x[0]) / aL) * PetscExpReal( -1.0*( (alpha_n*alpha_n*c*t)/(aL*aL) ) );
1444     B_x += ( (PetscSinReal(alpha_n) * PetscCosReal(alpha_n) )/(alpha_n - PetscSinReal(alpha_n) * PetscCosReal(alpha_n)) ) * PetscExpReal( -1.0*( (alpha_n*alpha_n*c*t)/(aL*aL) ) );
1445   }
1446 
1447   PetscScalar sigma_zz = -1.0*(F/aL) - ((2.0*F)/aL) * (A2/A1) * A_x + ((2.0*F)/aL) * B_x;
1448 
1449 
1450   if (x[1] == ymax) {
1451     f0[1] += sigma_zz;
1452   } else if (x[1] == ymin) {
1453     f0[1] -= sigma_zz;
1454   }
1455 }
1456 
1457 static void f0_cryer_bd_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1458                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1459                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1460                                     PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1461 {
1462   const PetscReal P_0 = PetscRealPart(constants[5]);
1463   const PetscReal R   = PetscSqrtReal(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
1464   PetscInt        d;
1465 
1466   for (d = 0; d < dim; ++d) f0[d] = -P_0*n[d];
1467   //PetscPrintf(PETSC_COMM_SELF, "R: %g P_0: %g n: (%g, %g, %g) hat n (%g, %g, %g)\n", R, P_0, n[0], n[1], n[2], x[0]/R, x[1]/R, x[2]/R);
1468   for (d = 0; d < dim; ++d) if (PetscAbsReal(n[d] - x[d]/R) > 1.0) PetscPrintf(PETSC_COMM_SELF, "WTF? R: %g P_0: %g n: (%g, %g, %g) hat n (%g, %g, %g)\n", R, P_0, n[0], n[1], n[2], x[0]/R, x[1]/R, x[2]/R);
1469   //for (d = 0; d < dim; ++d) f0[d] = -P_0*x[d]/R;
1470 }
1471 
1472 /* Standard Kernels - Residual */
1473 /* f0_e */
1474 static void f0_epsilon(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1475                        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1476                        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1477                        PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1478 {
1479   PetscInt d;
1480 
1481   for (d = 0; d < dim; ++d) {
1482     f0[0] += u_x[d*dim+d];
1483   }
1484   f0[0] -= u[uOff[1]];
1485 }
1486 
1487 /* f0_p */
1488 static void f0_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1489                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1490                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1491                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1492 {
1493   const PetscReal alpha  = PetscRealPart(constants[2]);
1494   const PetscReal M      = PetscRealPart(constants[3]);
1495 
1496   f0[0] += alpha*u_t[uOff[1]];
1497   f0[0] += u_t[uOff[2]]/M;
1498 }
1499 
1500 /* f1_u */
1501 static void f1_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1502                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1503                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1504                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
1505 {
1506   const PetscInt  Nc     = dim;
1507   const PetscReal G      = PetscRealPart(constants[0]);
1508   const PetscReal K_u    = PetscRealPart(constants[1]);
1509   const PetscReal alpha  = PetscRealPart(constants[2]);
1510   const PetscReal M      = PetscRealPart(constants[3]);
1511   const PetscReal K_d    = K_u - alpha*alpha*M;
1512   const PetscReal lambda = K_d - (2.0 * G) / 3.0;
1513   PetscInt        c, d;
1514 
1515   for (c = 0; c < Nc; ++c)
1516   {
1517     for (d = 0; d < dim; ++d)
1518     {
1519       f1[c*dim+d] -= G*(u_x[c*dim+d] + u_x[d*dim+c]);
1520     }
1521     f1[c*dim+c] -= lambda*u[uOff[1]];
1522     f1[c*dim+c] += alpha*u[uOff[2]];
1523   }
1524 }
1525 
1526 /* f1_p */
1527 static void f1_p(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1528                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1529                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1530                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
1531 {
1532   const PetscReal kappa = PetscRealPart(constants[4]);
1533   PetscInt        d;
1534 
1535   for (d = 0; d < dim; ++d) {
1536     f1[d] += kappa*u_x[uOff_x[2]+d];
1537   }
1538 }
1539 
1540 /*
1541   \partial_df \phi_fc g_{fc,gc,df,dg} \partial_dg \phi_gc
1542 
1543   \partial_df \phi_fc \lambda \delta_{fc,df} \sum_gc \partial_dg \phi_gc \delta_{gc,dg}
1544   = \partial_fc \phi_fc \sum_gc \partial_gc \phi_gc
1545 */
1546 
1547 
1548 /* Standard Kernels - Jacobian */
1549 /* g0_ee */
1550 static void g0_ee(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1551            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1552            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1553            PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1554 {
1555   g0[0] = -1.0;
1556 }
1557 
1558 /* g0_pe */
1559 static void g0_pe(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1560            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1561            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1562            PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1563 {
1564   const PetscReal alpha = PetscRealPart(constants[2]);
1565 
1566   g0[0] = u_tShift*alpha;
1567 }
1568 
1569 /* g0_pp */
1570 static void g0_pp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1571                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1572                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1573                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1574 {
1575   const PetscReal M = PetscRealPart(constants[3]);
1576 
1577   g0[0] = u_tShift/M;
1578 }
1579 
1580 /* g1_eu */
1581 static void g1_eu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1582            const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1583            const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1584            PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
1585 {
1586   PetscInt d;
1587   for (d = 0; d < dim; ++d) g1[d*dim+d] = 1.0; /* \frac{\partial\phi^{u_d}}{\partial x_d} */
1588 }
1589 
1590 /* g2_ue */
1591 static void g2_ue(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1592                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1593                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1594                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
1595 {
1596   const PetscReal G      = PetscRealPart(constants[0]);
1597   const PetscReal K_u    = PetscRealPart(constants[1]);
1598   const PetscReal alpha  = PetscRealPart(constants[2]);
1599   const PetscReal M      = PetscRealPart(constants[3]);
1600   const PetscReal K_d    = K_u - alpha*alpha*M;
1601   const PetscReal lambda = K_d - (2.0 * G) / 3.0;
1602   PetscInt        d;
1603 
1604   for (d = 0; d < dim; ++d) {
1605     g2[d*dim + d] -= lambda;
1606   }
1607 }
1608 /* g2_up */
1609 static void g2_up(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1610                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1611                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1612                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
1613 {
1614   const PetscReal alpha = PetscRealPart(constants[2]);
1615   PetscInt        d;
1616 
1617   for (d = 0; d < dim; ++d) {
1618     g2[d*dim + d] += alpha;
1619   }
1620 }
1621 
1622 /* g3_uu */
1623 static void g3_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1624                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1625                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1626                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
1627 {
1628   const PetscInt  Nc = dim;
1629   const PetscReal G  = PetscRealPart(constants[0]);
1630   PetscInt        c, d;
1631 
1632   for (c = 0; c < Nc; ++c) {
1633     for (d = 0; d < dim; ++d) {
1634       g3[((c*Nc + c)*dim + d)*dim + d] -= G;
1635       g3[((c*Nc + d)*dim + d)*dim + c] -= G;
1636     }
1637   }
1638 }
1639 
1640 /* g3_pp */
1641 static void g3_pp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1642                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1643                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1644                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
1645 {
1646   const PetscReal kappa = PetscRealPart(constants[4]);
1647   PetscInt        d;
1648 
1649   for (d = 0; d < dim; ++d) g3[d*dim+d] += kappa;
1650 }
1651 
1652 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
1653 {
1654   PetscInt sol;
1655   PetscErrorCode ierr;
1656 
1657   PetscFunctionBeginUser;
1658   options->dim      = 2;
1659   options->simplex  = PETSC_TRUE;
1660   options->refLimit = -1.0;
1661   options->solType  = SOL_QUADRATIC_TRIG;
1662   options->niter    = 500;
1663   options->eps      = PETSC_SMALL;
1664   ierr = PetscStrncpy(options->dmType, DMPLEX, 256);CHKERRQ(ierr);
1665 
1666   ierr = PetscOptionsBegin(comm, "", "Biot Poroelasticity Options", "DMPLEX");CHKERRQ(ierr);
1667   ierr = PetscOptionsInt("-dim", "The topological mesh dimension", "ex53.c", options->dim, &options->dim, NULL);CHKERRQ(ierr);
1668   ierr = PetscOptionsInt("-niter", "Number of series term iterations in exact solutions", "ex53.c", options->niter, &options->niter, NULL);CHKERRQ(ierr);
1669   ierr = PetscOptionsBool("-simplex", "Simplicial (true) or tensor (false) mesh", "ex53.c", options->simplex, &options->simplex, NULL);CHKERRQ(ierr);
1670   ierr = PetscOptionsReal("-ref_limit", "Maximum cell volume for refined mesh", "ex53.c", options->refLimit, &options->refLimit, NULL);CHKERRQ(ierr);
1671   sol  = options->solType;
1672   ierr = PetscOptionsEList("-sol_type", "Type of exact solution", "ex53.c", solutionTypes, NUM_SOLUTION_TYPES, solutionTypes[options->solType], &sol, NULL);CHKERRQ(ierr);
1673   options->solType = (SolutionType) sol;
1674   ierr = PetscOptionsFList("-dm_type", "Convert DMPlex to another format", "ex53.c", DMList, options->dmType, options->dmType, 256, NULL);CHKERRQ(ierr);
1675   ierr = PetscOptionsReal("-eps", " Precision value for root finding", "ex53.c", options->eps, &options->eps, NULL);CHKERRQ(ierr);
1676 
1677   // Wrap up loose ends
1678   if (options->solType == SOL_CRYER) {
1679     options->dim = 3;
1680   }
1681 
1682   ierr = PetscOptionsEnd();CHKERRQ(ierr);
1683   PetscFunctionReturn(0);
1684 }
1685 
1686 static PetscErrorCode mandelZeros(MPI_Comm comm, AppCtx *ctx, Parameter *param)
1687 {
1688   //PetscBag       bag;
1689   PetscReal a1, a2, am;
1690   PetscReal y1, y2, ym;
1691 
1692   PetscFunctionBeginUser;
1693   //ierr = PetscBagGetData(ctx->bag, (void **) &param);CHKERRQ(ierr);
1694   PetscInt NITER = ctx->niter;
1695   PetscReal EPS = ctx->eps;
1696   //const PetscScalar YMAX = param->ymax;
1697   //const PetscScalar YMIN = param->ymin;
1698   PetscScalar alpha = param->alpha;
1699   PetscScalar K_u = param->K_u;
1700   PetscScalar M = param->M;
1701   PetscScalar G = param->mu;
1702   //const PetscScalar k = param->k;
1703   //const PetscScalar mu_f = param->mu_f;
1704   //const PetscScalar P_0 = param->P_0;
1705 
1706   PetscScalar K_d = K_u - alpha*alpha*M;
1707   PetscScalar nu = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G ));
1708   PetscScalar nu_u = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G ));
1709   //const PetscScalar kappa = k / mu_f;
1710 
1711   // Generate zero values
1712   for (PetscInt i=1; i < NITER+1; i++)
1713   {
1714     a1 = ((PetscReal) i - 1.0 ) * PETSC_PI * PETSC_PI / 4.0 + EPS;
1715     a2 = a1 + PETSC_PI/2;
1716     am = a1;
1717     for (PetscInt j=0; j<NITER; j++)
1718     {
1719       y1 = PetscTanReal(a1) - PetscRealPart((1.0 - nu)/(nu_u - nu))*a1;
1720       y2 = PetscTanReal(a2) - PetscRealPart((1.0 - nu)/(nu_u - nu))*a2;
1721       am = (a1 + a2)/2.0;
1722       ym = PetscTanReal(am) - PetscRealPart((1.0 - nu)/(nu_u - nu))*am;
1723       if ((ym*y1) > 0)
1724       {
1725         a1 = am;
1726       } else {
1727         a2 = am;
1728       }
1729       if (PetscAbsReal(y2) < EPS)
1730       {
1731         am = a2;
1732       }
1733     }
1734     ctx->zeroArray[i-1] = am;
1735   }
1736   PetscFunctionReturn(0);
1737 }
1738 
1739 static PetscReal CryerFunction(PetscReal nu_u, PetscReal nu, PetscReal x)
1740 {
1741   return PetscTanReal(PetscSqrtReal(x))*(6.0*(nu_u - nu) - (1.0 - nu)*(1.0 + nu_u)*x) - (6.0*(nu_u - nu)*PetscSqrtReal(x));
1742 }
1743 
1744 static PetscErrorCode cryerZeros(MPI_Comm comm, AppCtx *ctx, Parameter *param)
1745 {
1746   PetscReal   alpha = PetscRealPart(param->alpha); /* -  */
1747   PetscReal   K_u   = PetscRealPart(param->K_u);   /* Pa */
1748   PetscReal   M     = PetscRealPart(param->M);     /* Pa */
1749   PetscReal   G     = PetscRealPart(param->mu);    /* Pa */
1750   PetscInt    N     = ctx->niter, n;
1751 
1752   PetscReal   K_d   = K_u - alpha*alpha*M;                       /* Pa,      Cheng (B.5)  */
1753   PetscReal   nu    = (3.0*K_d - 2.0*G) / (2.0*(3.0*K_d + G));   /* -,       Cheng (B.8)  */
1754   PetscReal   nu_u  = (3.0*K_u - 2.0*G) / (2.0*(3.0*K_u + G));   /* -,       Cheng (B.9)  */
1755 
1756   PetscFunctionBeginUser;
1757   for (n = 1; n < N+1; ++n) {
1758     PetscReal tol = PetscPowReal(n, 1.5)*ctx->eps;
1759     PetscReal a1 = 0., a2 = 0., am = 0.;
1760     PetscReal y1, y2, ym;
1761     PetscInt  j, k = n-1;
1762 
1763     y1 = y2 = 1.;
1764     while (y1*y2 > 0) {
1765       ++k;
1766       a1 = PetscSqr(n*PETSC_PI) - k*PETSC_PI;
1767       a2 = PetscSqr(n*PETSC_PI) + k*PETSC_PI;
1768       y1 = CryerFunction(nu_u, nu, a1);
1769       y2 = CryerFunction(nu_u, nu, a2);
1770     }
1771     for (j = 0; j < 50000; ++j) {
1772       y1 = CryerFunction(nu_u, nu, a1);
1773       y2 = CryerFunction(nu_u, nu, a2);
1774       if (y1*y2 > 0) SETERRQ5(comm, PETSC_ERR_PLIB, "Invalid root finding initialization for root %D, (%g, %g)--(%g, %g)", n, a1, y1, a2, y2);
1775       am = (a1 + a2) / 2.0;
1776       ym = CryerFunction(nu_u, nu, am);
1777       if ((ym * y1) < 0) a2 = am;
1778       else               a1 = am;
1779       if (PetscAbsScalar(ym) < tol) break;
1780     }
1781     if (PetscAbsScalar(ym) >= tol) SETERRQ2(comm, PETSC_ERR_PLIB, "Root finding did not converge for root %D (%g)", n, PetscAbsScalar(ym));
1782     ctx->zeroArray[n-1] = am;
1783   }
1784   PetscFunctionReturn(0);
1785 }
1786 
1787 static PetscErrorCode SetupParameters(MPI_Comm comm, AppCtx *ctx)
1788 {
1789   PetscBag       bag;
1790   Parameter     *p;
1791   PetscErrorCode ierr;
1792 
1793   PetscFunctionBeginUser;
1794   /* setup PETSc parameter bag */
1795   ierr = PetscBagGetData(ctx->bag,(void**)&p);CHKERRQ(ierr);
1796   ierr = PetscBagSetName(ctx->bag,"par","Poroelastic Parameters");CHKERRQ(ierr);
1797   bag  = ctx->bag;
1798   if (ctx->solType == SOL_TERZAGHI) {
1799     // Realistic values - Terzaghi
1800     ierr = PetscBagRegisterScalar(bag, &p->mu,     3.0,                 "mu",    "Shear Modulus, Pa");CHKERRQ(ierr);
1801     ierr = PetscBagRegisterScalar(bag, &p->K_u,    9.76,                "K_u",   "Undrained Bulk Modulus, Pa");CHKERRQ(ierr);
1802     ierr = PetscBagRegisterScalar(bag, &p->alpha,  0.6,                 "alpha", "Biot Effective Stress Coefficient, -");CHKERRQ(ierr);
1803     ierr = PetscBagRegisterScalar(bag, &p->M,      16.0,                "M",     "Biot Modulus, Pa");CHKERRQ(ierr);
1804     ierr = PetscBagRegisterScalar(bag, &p->k,      1.5,                 "k",     "Isotropic Permeability, m**2");CHKERRQ(ierr);
1805     ierr = PetscBagRegisterScalar(bag, &p->mu_f,   1.0,                 "mu_f",  "Fluid Dynamic Viscosity, Pa*s");CHKERRQ(ierr);
1806     ierr = PetscBagRegisterScalar(bag, &p->zmax,   1.0,                 "zmax",  "Depth Maximum Extent, m");CHKERRQ(ierr);
1807     ierr = PetscBagRegisterScalar(bag, &p->zmin,   0.0,                 "zmin",  "Depth Minimum Extent, m");CHKERRQ(ierr);
1808     ierr = PetscBagRegisterScalar(bag, &p->ymax,   10.0,                "ymax",  "Vertical Maximum Extent, m");CHKERRQ(ierr);
1809     ierr = PetscBagRegisterScalar(bag, &p->ymin,   0.0,                 "ymin",  "Vertical Minimum Extent, m");CHKERRQ(ierr);
1810     ierr = PetscBagRegisterScalar(bag, &p->xmax,   10.0,                "xmax",  "Horizontal Maximum Extent, m");CHKERRQ(ierr);
1811     ierr = PetscBagRegisterScalar(bag, &p->xmin,   0.0,                 "xmin",  "Horizontal Minimum Extent, m");CHKERRQ(ierr);
1812     ierr = PetscBagRegisterScalar(bag, &p->P_0,    1.0,                 "P_0",   "Magnitude of Vertical Stress, Pa");CHKERRQ(ierr);
1813   } else if (ctx->solType == SOL_MANDEL) {
1814     // Realistic values - Mandel
1815     ierr = PetscBagRegisterScalar(bag, &p->mu,     0.75,                "mu",    "Shear Modulus, Pa");CHKERRQ(ierr);
1816     ierr = PetscBagRegisterScalar(bag, &p->K_u,    2.6941176470588233,  "K_u",   "Undrained Bulk Modulus, Pa");CHKERRQ(ierr);
1817     ierr = PetscBagRegisterScalar(bag, &p->alpha,  0.6,                 "alpha", "Biot Effective Stress Coefficient, -");CHKERRQ(ierr);
1818     ierr = PetscBagRegisterScalar(bag, &p->M,      4.705882352941176,   "M",     "Biot Modulus, Pa");CHKERRQ(ierr);
1819     ierr = PetscBagRegisterScalar(bag, &p->k,      1.5,                 "k",     "Isotropic Permeability, m**2");CHKERRQ(ierr);
1820     ierr = PetscBagRegisterScalar(bag, &p->mu_f,   1.0,                 "mu_f",  "Fluid Dynamic Viscosity, Pa*s");CHKERRQ(ierr);
1821     ierr = PetscBagRegisterScalar(bag, &p->zmax,   1.0,                 "zmax",  "Depth Maximum Extent, m");CHKERRQ(ierr);
1822     ierr = PetscBagRegisterScalar(bag, &p->zmin,   0.0,                 "zmin",  "Depth Minimum Extent, m");CHKERRQ(ierr);
1823     ierr = PetscBagRegisterScalar(bag, &p->ymax,   0.25,                "ymax",  "Vertical Maximum Extent, m");CHKERRQ(ierr);
1824     ierr = PetscBagRegisterScalar(bag, &p->ymin,   0.0,                 "ymin",  "Vertical Minimum Extent, m");CHKERRQ(ierr);
1825     ierr = PetscBagRegisterScalar(bag, &p->xmax,   1.0,                 "xmax",  "Horizontal Maximum Extent, m");CHKERRQ(ierr);
1826     ierr = PetscBagRegisterScalar(bag, &p->xmin,   0.0,                 "xmin",  "Horizontal Minimum Extent, m");CHKERRQ(ierr);
1827     ierr = PetscBagRegisterScalar(bag, &p->P_0,    1.0,                 "P_0",   "Magnitude of Vertical Stress, Pa");CHKERRQ(ierr);
1828   } else if (ctx->solType == SOL_CRYER) {
1829     // Realistic values - Mandel
1830     ierr = PetscBagRegisterScalar(bag, &p->mu,     0.75,                "mu",    "Shear Modulus, Pa");CHKERRQ(ierr);
1831     ierr = PetscBagRegisterScalar(bag, &p->K_u,    2.6941176470588233,  "K_u",   "Undrained Bulk Modulus, Pa");CHKERRQ(ierr);
1832     ierr = PetscBagRegisterScalar(bag, &p->alpha,  0.6,                 "alpha", "Biot Effective Stress Coefficient, -");CHKERRQ(ierr);
1833     ierr = PetscBagRegisterScalar(bag, &p->M,      4.705882352941176,   "M",     "Biot Modulus, Pa");CHKERRQ(ierr);
1834     ierr = PetscBagRegisterScalar(bag, &p->k,      1.5,                 "k",     "Isotropic Permeability, m**2");CHKERRQ(ierr);
1835     ierr = PetscBagRegisterScalar(bag, &p->mu_f,   1.0,                 "mu_f",  "Fluid Dynamic Viscosity, Pa*s");CHKERRQ(ierr);
1836     ierr = PetscBagRegisterScalar(bag, &p->zmax,   1.0,                 "zmax",  "Depth Maximum Extent, m");CHKERRQ(ierr);
1837     ierr = PetscBagRegisterScalar(bag, &p->zmin,   0.0,                 "zmin",  "Depth Minimum Extent, m");CHKERRQ(ierr);
1838     ierr = PetscBagRegisterScalar(bag, &p->ymax,   1.0,                 "ymax",  "Vertical Maximum Extent, m");CHKERRQ(ierr);
1839     ierr = PetscBagRegisterScalar(bag, &p->ymin,   0.0,                 "ymin",  "Vertical Minimum Extent, m");CHKERRQ(ierr);
1840     ierr = PetscBagRegisterScalar(bag, &p->xmax,   1.0,                 "xmax",  "Horizontal Maximum Extent, m");CHKERRQ(ierr);
1841     ierr = PetscBagRegisterScalar(bag, &p->xmin,   0.0,                 "xmin",  "Horizontal Minimum Extent, m");CHKERRQ(ierr);
1842     ierr = PetscBagRegisterScalar(bag, &p->P_0,    1.0,                 "P_0",   "Magnitude of Vertical Stress, Pa");CHKERRQ(ierr);
1843   } else {
1844     // Nonsense values
1845     ierr = PetscBagRegisterScalar(bag, &p->mu,     1.0,                 "mu",    "Shear Modulus, Pa");CHKERRQ(ierr);
1846     ierr = PetscBagRegisterScalar(bag, &p->K_u,    1.0,                 "K_u",   "Undrained Bulk Modulus, Pa");CHKERRQ(ierr);
1847     ierr = PetscBagRegisterScalar(bag, &p->alpha,  1.0,                 "alpha", "Biot Effective Stress Coefficient, -");CHKERRQ(ierr);
1848     ierr = PetscBagRegisterScalar(bag, &p->M,      1.0,                 "M",     "Biot Modulus, Pa");CHKERRQ(ierr);
1849     ierr = PetscBagRegisterScalar(bag, &p->k,      1.0,                 "k",     "Isotropic Permeability, m**2");CHKERRQ(ierr);
1850     ierr = PetscBagRegisterScalar(bag, &p->mu_f,   1.0,                 "mu_f",  "Fluid Dynamic Viscosity, Pa*s");CHKERRQ(ierr);
1851     ierr = PetscBagRegisterScalar(bag, &p->zmax,   1.0,                 "zmax",  "Depth Maximum Extent, m");CHKERRQ(ierr);
1852     ierr = PetscBagRegisterScalar(bag, &p->zmin,   0.0,                 "zmin",  "Depth Minimum Extent, m");CHKERRQ(ierr);
1853     ierr = PetscBagRegisterScalar(bag, &p->ymax,   1.0,                 "ymax",  "Vertical Maximum Extent, m");CHKERRQ(ierr);
1854     ierr = PetscBagRegisterScalar(bag, &p->ymin,   0.0,                 "ymin",  "Vertical Minimum Extent, m");CHKERRQ(ierr);
1855     ierr = PetscBagRegisterScalar(bag, &p->xmax,   1.0,                 "xmax",  "Horizontal Maximum Extent, m");CHKERRQ(ierr);
1856     ierr = PetscBagRegisterScalar(bag, &p->xmin,   0.0,                 "xmin",  "Horizontal Minimum Extent, m");CHKERRQ(ierr);
1857     ierr = PetscBagRegisterScalar(bag, &p->P_0,    1.0,                 "P_0",   "Magnitude of Vertical Stress, Pa");CHKERRQ(ierr);
1858   }
1859   ierr = PetscBagSetFromOptions(bag);CHKERRQ(ierr);
1860   {
1861     PetscScalar K_d  = p->K_u - p->alpha*p->alpha*p->M;
1862     PetscScalar nu_u = (3.0*p->K_u - 2.0*p->mu) / (2.0*(3.0*p->K_u + p->mu));
1863     PetscScalar nu   = (3.0*K_d - 2.0*p->mu) / (2.0*(3.0*K_d + p->mu));
1864     PetscScalar S    = (3.0*p->K_u + 4.0*p->mu) / (p->M*(3.0*K_d + 4.0*p->mu));
1865     PetscReal   c    = PetscRealPart((p->k/p->mu_f) / S);
1866 
1867     PetscViewer       viewer;
1868     PetscViewerFormat format;
1869     PetscBool         flg;
1870 
1871     switch (ctx->solType) {
1872       case SOL_QUADRATIC_LINEAR:
1873       case SOL_QUADRATIC_TRIG:
1874       case SOL_TRIG_LINEAR: ctx->t_r = PetscSqr(p->xmax - p->xmin)/c; break;
1875       case SOL_TERZAGHI:    ctx->t_r = PetscSqr(2.0*(p->ymax - p->ymin))/c; break;
1876       case SOL_MANDEL:      ctx->t_r = PetscSqr(2.0*(p->ymax - p->ymin))/c; break;
1877       case SOL_CRYER:       ctx->t_r = PetscSqr(p->ymax)/c; break;
1878       default: SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Invalid solution type: %s (%D)", solutionTypes[PetscMin(ctx->solType, NUM_SOLUTION_TYPES)], ctx->solType);
1879     }
1880     ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-param_view", &viewer, &format, &flg);CHKERRQ(ierr);
1881     if (flg) {
1882       ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr);
1883       ierr = PetscBagView(bag, viewer);CHKERRQ(ierr);
1884       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1885       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1886       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1887       ierr = PetscPrintf(comm, "  Max displacement: %g %g\n", p->P_0*(p->ymax - p->ymin)*(1. - 2.*nu_u)/(2.*p->mu*(1. - nu_u)), p->P_0*(p->ymax - p->ymin)*(1. - 2.*nu)/(2.*p->mu*(1. - nu)));
1888       ierr = PetscPrintf(comm, "  Relaxation time: %g\n", ctx->t_r);
1889     }
1890   }
1891   PetscFunctionReturn(0);
1892 }
1893 
1894 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
1895 {
1896   Parameter     *param;
1897   PetscBool      flg;
1898   PetscErrorCode ierr;
1899 
1900   PetscFunctionBeginUser;
1901   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1902   if (user->solType == SOL_CRYER) {
1903     DM rdm;
1904 
1905     if (!user->simplex) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Cannot create ball with cubic cells");
1906     if (param->xmin != 0.0 || param->ymin != 0.0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Cannot shift center of ball to (%g, %g)", param->xmin, param->ymin);
1907     if (param->xmax != param->ymax) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Cannot radius of ball must be equal in x and y: %g != %g", param->xmax, param->ymax);
1908     ierr = DMPlexCreateBallMesh(comm, user->dim, param->xmax, dm);CHKERRQ(ierr);
1909 
1910     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
1911     ierr = DMPlexSetRefinementLimit(*dm, user->refLimit);CHKERRQ(ierr);
1912     ierr = DMRefine(*dm, comm, &rdm);CHKERRQ(ierr);
1913     if (rdm) {
1914       ierr = DMDestroy(dm);CHKERRQ(ierr);
1915       *dm  = rdm;
1916     }
1917     ierr = DMPlexSetRefinementUniform(*dm, PETSC_TRUE);CHKERRQ(ierr);
1918   } else if (user->solType == SOL_MANDEL) {
1919     PetscReal lower[2], upper[2];
1920 
1921     lower[0] = param->xmin - (param->xmax - param->xmin) / 2.0;
1922     lower[1] = param->ymin - (param->ymax - param->ymin) / 2.0;
1923     upper[0] = param->xmax - (param->xmax - param->xmin) / 2.0;
1924     upper[1] = param->ymax - (param->ymax - param->ymin) / 2.0;
1925     //reset min / max values for mandel
1926     param->xmin = lower[0];
1927     param->ymin = lower[1];
1928     param->xmax = upper[0];
1929     param->ymax = upper[1];
1930     ierr = DMPlexCreateBoxMesh(comm, user->dim, user->simplex, NULL, lower, upper, NULL, PETSC_TRUE, dm);CHKERRQ(ierr);
1931   } else {
1932     Parameter *param;
1933     PetscReal  lower[3], upper[3];
1934 
1935     ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1936     lower[0] = param->xmin;
1937     lower[1] = param->ymin;
1938     lower[2] = param->zmin;
1939     upper[0] = param->xmax;
1940     upper[1] = param->ymax;
1941     upper[2] = param->zmax;
1942     ierr = DMPlexCreateBoxMesh(comm, user->dim, user->simplex, NULL, lower, upper, NULL, PETSC_TRUE, dm);CHKERRQ(ierr);
1943   }
1944   {
1945     DM               pdm = NULL;
1946     PetscPartitioner part;
1947 
1948     ierr = DMPlexGetPartitioner(*dm, &part);CHKERRQ(ierr);
1949     ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr);
1950     ierr = DMPlexDistribute(*dm, 0, NULL, &pdm);CHKERRQ(ierr);
1951     if (pdm) {
1952       ierr = DMDestroy(dm);CHKERRQ(ierr);
1953       *dm  = pdm;
1954     }
1955   }
1956   ierr = PetscStrcmp(user->dmType, DMPLEX, &flg);CHKERRQ(ierr);
1957   if (flg) {
1958     DM ndm;
1959 
1960     ierr = DMConvert(*dm, user->dmType, &ndm);CHKERRQ(ierr);
1961     if (ndm) {
1962       ierr = DMDestroy(dm);CHKERRQ(ierr);
1963       *dm  = ndm;
1964     }
1965   }
1966   ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr);
1967 
1968   ierr = PetscObjectSetName((PetscObject) *dm, "Mesh");CHKERRQ(ierr);
1969   ierr = DMSetApplicationContext(*dm, user);CHKERRQ(ierr);
1970   ierr = DMSetFromOptions(*dm);CHKERRQ(ierr);
1971   ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr);
1972   PetscFunctionReturn(0);
1973 }
1974 
1975 static PetscErrorCode SetupPrimalProblem(DM dm, AppCtx *user)
1976 {
1977   PetscErrorCode (*exact[3])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *);
1978   PetscErrorCode (*exact_t[3])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *);
1979   PetscDS          prob;
1980   Parameter       *param;
1981   PetscInt         id_mandel[2];
1982   PetscInt         comp[1];
1983   PetscInt         comp_mandel[2];
1984   PetscInt         dim, id, f;
1985   PetscErrorCode   ierr;
1986 
1987   PetscFunctionBeginUser;
1988   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
1989   ierr = PetscDSGetSpatialDimension(prob, &dim);CHKERRQ(ierr);
1990   ierr = PetscBagGetData(user->bag, (void **) &param);CHKERRQ(ierr);
1991   exact_t[0] = exact_t[1] = exact_t[2] = zero;
1992 
1993   /* Setup Problem Formulation and Boundary Conditions */
1994   switch (user->solType) {
1995   case SOL_QUADRATIC_LINEAR:
1996     ierr = PetscDSSetResidual(prob, 0, f0_quadratic_linear_u, f1_u);CHKERRQ(ierr);
1997     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,            NULL);CHKERRQ(ierr);
1998     ierr = PetscDSSetResidual(prob, 2, f0_quadratic_linear_p, f1_p);CHKERRQ(ierr);
1999     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2000     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2001     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2002     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2003     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2004     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe, NULL,  NULL,  NULL);CHKERRQ(ierr);
2005     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp, NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2006     exact[0]   = quadratic_u;
2007     exact[1]   = linear_eps;
2008     exact[2]   = linear_linear_p;
2009     exact_t[2] = linear_linear_p_t;
2010 
2011     id = 1;
2012     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall displacement", "marker", 0, 0, NULL, (void (*)(void)) exact[0], NULL,                        1, &id, user);CHKERRQ(ierr);
2013     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall pressure",     "marker", 2, 0, NULL, (void (*)(void)) exact[2], (void (*)(void)) exact_t[2], 1, &id, user);CHKERRQ(ierr);
2014     break;
2015   case SOL_TRIG_LINEAR:
2016     ierr = PetscDSSetResidual(prob, 0, f0_trig_linear_u, f1_u);CHKERRQ(ierr);
2017     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,       NULL);CHKERRQ(ierr);
2018     ierr = PetscDSSetResidual(prob, 2, f0_trig_linear_p, f1_p);CHKERRQ(ierr);
2019     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2020     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2021     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2022     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2023     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2024     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe, NULL,  NULL,  NULL);CHKERRQ(ierr);
2025     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp, NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2026     exact[0]   = trig_u;
2027     exact[1]   = trig_eps;
2028     exact[2]   = trig_linear_p;
2029     exact_t[2] = trig_linear_p_t;
2030 
2031     id = 1;
2032     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall displacement", "marker", 0, 0, NULL, (void (*)(void)) exact[0], NULL,                        1, &id, user);CHKERRQ(ierr);
2033     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall pressure",     "marker", 2, 0, NULL, (void (*)(void)) exact[2], (void (*)(void)) exact_t[2], 1, &id, user);CHKERRQ(ierr);
2034     break;
2035   case SOL_QUADRATIC_TRIG:
2036     ierr = PetscDSSetResidual(prob, 0, f0_quadratic_trig_u, f1_u);CHKERRQ(ierr);
2037     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,          NULL);CHKERRQ(ierr);
2038     ierr = PetscDSSetResidual(prob, 2, f0_quadratic_trig_p, f1_p);CHKERRQ(ierr);
2039     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2040     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2041     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2042     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2043     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2044     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe, NULL,  NULL,  NULL);CHKERRQ(ierr);
2045     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp, NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2046     exact[0]   = quadratic_u;
2047     exact[1]   = linear_eps;
2048     exact[2]   = linear_trig_p;
2049     exact_t[2] = linear_trig_p_t;
2050 
2051     id = 1;
2052     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall displacement", "marker", 0, 0, NULL, (void (*)(void)) exact[0],                        NULL, 1, &id, user);CHKERRQ(ierr);
2053     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall pressure",     "marker", 2, 0, NULL, (void (*)(void)) exact[2], (void (*)(void)) exact_t[2], 1, &id, user);CHKERRQ(ierr);
2054     break;
2055   case SOL_TERZAGHI:
2056     ierr = PetscDSSetResidual(prob, 0, NULL, f1_u);CHKERRQ(ierr);
2057     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,     NULL);CHKERRQ(ierr);
2058     ierr = PetscDSSetResidual(prob, 2, f0_p,           f1_p);CHKERRQ(ierr);
2059     ierr = PetscDSSetBdResidual(prob, 0, f0_terzaghi_bd_u, NULL);CHKERRQ(ierr);
2060     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2061     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2062     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2063     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2064     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2065     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe,  NULL,  NULL,  NULL);CHKERRQ(ierr);
2066     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp,  NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2067 
2068     exact[0] = terzaghi_2d_u;
2069     exact[1] = terzaghi_2d_eps;
2070     exact[2] = terzaghi_2d_p;
2071     exact_t[0] = terzaghi_2d_u_t;
2072     exact_t[1] = terzaghi_2d_eps_t;
2073     exact_t[2] = terzaghi_2d_p_t;
2074 
2075     id = 1;
2076     ierr = DMAddBoundary(dm, DM_BC_NATURAL, "vertical stress", "marker", 0, 0, NULL, NULL, NULL, 1, &id, user);CHKERRQ(ierr);
2077     id = 3;
2078     comp[0] = 1;
2079     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed base", "marker", 0, 1, comp, (void (*)(void)) zero, NULL, 1, &id, user);CHKERRQ(ierr);
2080     id = 2;
2081     comp[0] = 0;
2082     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed side", "marker", 0, 1, comp, (void (*)(void)) zero, NULL, 1, &id, user);CHKERRQ(ierr);
2083     id = 4;
2084     comp[0] = 0;
2085     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed side", "marker", 0, 1, comp, (void (*)(void)) zero, NULL, 1, &id, user);CHKERRQ(ierr);
2086     id = 1;
2087     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "drained surface", "marker", 2, 0, NULL, (void (*)(void)) terzaghi_drainage_pressure, NULL, 1, &id, user);CHKERRQ(ierr);
2088     break;
2089   case SOL_MANDEL:
2090     ierr = PetscDSSetResidual(prob, 0, NULL, f1_u);CHKERRQ(ierr);
2091     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,     NULL);CHKERRQ(ierr);
2092     ierr = PetscDSSetResidual(prob, 2, f0_p,           f1_p);CHKERRQ(ierr);
2093     ierr = PetscDSSetBdResidual(prob, 0, f0_mandel_bd_u, NULL);CHKERRQ(ierr);
2094     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2095     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2096     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2097     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2098     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2099     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe,  NULL,  NULL,  NULL);CHKERRQ(ierr);
2100     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp,  NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2101 
2102     ierr = mandelZeros(PETSC_COMM_WORLD, user, param);CHKERRQ(ierr);
2103 
2104     exact[0] = mandel_2d_u;
2105     exact[1] = mandel_2d_eps;
2106     exact[2] = mandel_2d_p;
2107     exact_t[0] = mandel_2d_u_t;
2108     exact_t[1] = mandel_2d_eps_t;
2109     exact_t[2] = mandel_2d_p_t;
2110 
2111     id_mandel[0] = 3;
2112     id_mandel[1] = 1;
2113     //comp[0] = 1;
2114     comp_mandel[0] = 0;
2115     comp_mandel[1] = 1;
2116     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "vertical stress", "marker", 0, 2, comp_mandel, (void (*)(void)) mandel_2d_u, NULL, 2, id_mandel, user);CHKERRQ(ierr);
2117     //ierr = DMAddBoundary(dm, DM_BC_NATURAL, "vertical stress", "marker", 0, 1, comp, NULL, 2, id_mandel, user);CHKERRQ(ierr);
2118     //ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "fixed base", "marker", 0, 1, comp, (void (*)(void)) zero, 2, id_mandel, user);CHKERRQ(ierr);
2119 
2120     id_mandel[0] = 2;
2121     id_mandel[1] = 4;
2122     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "drained surface", "marker", 2, 0, NULL, (void (*)(void)) zero, NULL, 2, id_mandel, user);CHKERRQ(ierr);
2123     break;
2124   case SOL_CRYER:
2125     ierr = PetscDSSetResidual(prob, 0, NULL, f1_u);CHKERRQ(ierr);
2126     ierr = PetscDSSetResidual(prob, 1, f0_epsilon,     NULL);CHKERRQ(ierr);
2127     ierr = PetscDSSetResidual(prob, 2, f0_p,           f1_p);CHKERRQ(ierr);
2128     ierr = PetscDSSetBdResidual(prob, 0, f0_cryer_bd_u, NULL);CHKERRQ(ierr);
2129     ierr = PetscDSSetJacobian(prob, 0, 0, NULL,  NULL,  NULL,  g3_uu);CHKERRQ(ierr);
2130     ierr = PetscDSSetJacobian(prob, 0, 1, NULL,  NULL,  g2_ue, NULL);CHKERRQ(ierr);
2131     ierr = PetscDSSetJacobian(prob, 0, 2, NULL,  NULL,  g2_up, NULL);CHKERRQ(ierr);
2132     ierr = PetscDSSetJacobian(prob, 1, 0, NULL,  g1_eu, NULL,  NULL);CHKERRQ(ierr);
2133     ierr = PetscDSSetJacobian(prob, 1, 1, g0_ee, NULL,  NULL,  NULL);CHKERRQ(ierr);
2134     ierr = PetscDSSetJacobian(prob, 2, 1, g0_pe,  NULL,  NULL,  NULL);CHKERRQ(ierr);
2135     ierr = PetscDSSetJacobian(prob, 2, 2, g0_pp,  NULL,  NULL,  g3_pp);CHKERRQ(ierr);
2136 
2137     ierr = cryerZeros(PETSC_COMM_WORLD, user, param);CHKERRQ(ierr);
2138 
2139     exact[0] = cryer_3d_u;
2140     exact[1] = cryer_3d_eps;
2141     exact[2] = cryer_3d_p;
2142 
2143     id = 1;
2144     ierr = DMAddBoundary(dm, DM_BC_NATURAL,   "normal stress",   "marker", 0, 0, NULL, NULL,                                     NULL, 1, &id, user);CHKERRQ(ierr);
2145     ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "drained surface", "marker", 2, 0, NULL, (void (*)(void)) cryer_drainage_pressure, NULL, 1, &id, user);CHKERRQ(ierr);
2146     break;
2147   default: SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Invalid solution type: %s (%D)", solutionTypes[PetscMin(user->solType, NUM_SOLUTION_TYPES)], user->solType);
2148   }
2149   for (f = 0; f < 3; ++f) {
2150     ierr = PetscDSSetExactSolution(prob, f, exact[f], user);CHKERRQ(ierr);
2151     ierr = PetscDSSetExactSolutionTimeDerivative(prob, f, exact_t[f], user);CHKERRQ(ierr);
2152   }
2153 
2154   /* Setup constants */
2155   {
2156     PetscScalar constants[6];
2157     constants[0] = param->mu;            /* shear modulus, Pa */
2158     constants[1] = param->K_u;           /* undrained bulk modulus, Pa */
2159     constants[2] = param->alpha;         /* Biot effective stress coefficient, - */
2160     constants[3] = param->M;             /* Biot modulus, Pa */
2161     constants[4] = param->k/param->mu_f; /* Darcy coefficient, m**2 / Pa*s */
2162     constants[5] = param->P_0;           /* Magnitude of Vertical Stress, Pa */
2163     ierr = PetscDSSetConstants(prob, 6, constants);CHKERRQ(ierr);
2164   }
2165   PetscFunctionReturn(0);
2166 }
2167 
2168 static PetscErrorCode CreateElasticityNullSpace(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullspace)
2169 {
2170   PetscErrorCode ierr;
2171 
2172   PetscFunctionBegin;
2173   ierr = DMPlexCreateRigidBody(dm, origField, nullspace);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 static PetscErrorCode SetupFE(DM dm, PetscBool simplex, PetscInt Nf, PetscInt Nc[], const char *name[], PetscErrorCode (*setup)(DM, AppCtx *), void *ctx)
2178 {
2179   AppCtx         *user = (AppCtx *) ctx;
2180   DM              cdm  = dm;
2181   PetscFE         fe;
2182   PetscQuadrature q = NULL;
2183   char            prefix[PETSC_MAX_PATH_LEN];
2184   PetscInt        dim, f;
2185   PetscErrorCode  ierr;
2186 
2187   PetscFunctionBegin;
2188   /* Create finite element */
2189   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
2190   for (f = 0; f < Nf; ++f) {
2191     ierr = PetscSNPrintf(prefix, PETSC_MAX_PATH_LEN, "%s_", name[f]);CHKERRQ(ierr);
2192     ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, Nc[f], simplex, name[f] ? prefix : NULL, -1, &fe);CHKERRQ(ierr);
2193     ierr = PetscObjectSetName((PetscObject) fe, name[f]);CHKERRQ(ierr);
2194     if (!q) {ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr);}
2195     ierr = PetscFESetQuadrature(fe, q);CHKERRQ(ierr);
2196     ierr = DMSetField(dm, f, NULL, (PetscObject) fe);CHKERRQ(ierr);
2197     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
2198   }
2199   ierr = DMCreateDS(dm);CHKERRQ(ierr);
2200   ierr = (*setup)(dm, user);CHKERRQ(ierr);
2201   while (cdm) {
2202     ierr = DMCopyDisc(dm, cdm);CHKERRQ(ierr);
2203     if (0) {ierr = DMSetNearNullSpaceConstructor(cdm, 0, CreateElasticityNullSpace);CHKERRQ(ierr);}
2204     /* TODO: Check whether the boundary of coarse meshes is marked */
2205     ierr = DMGetCoarseDM(cdm, &cdm);CHKERRQ(ierr);
2206   }
2207   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
2208   PetscFunctionReturn(0);
2209 }
2210 
2211 static PetscErrorCode SetInitialConditions(TS ts, Vec u)
2212 {
2213   DM             dm;
2214   PetscReal      t;
2215   PetscErrorCode ierr;
2216 
2217   PetscFunctionBegin;
2218   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
2219   ierr = TSGetTime(ts, &t);CHKERRQ(ierr);
2220   if (t <= 0.0) {
2221     PetscErrorCode (*funcs[3])(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *);
2222     void            *ctxs[3];
2223     AppCtx          *ctx;
2224 
2225     ierr = DMGetApplicationContext(dm, (void **) &ctx);CHKERRQ(ierr);
2226     switch (ctx->solType) {
2227       case SOL_TERZAGHI:
2228         funcs[0] = terzaghi_initial_u;         ctxs[0] = ctx;
2229         funcs[1] = terzaghi_initial_eps;       ctxs[1] = ctx;
2230         funcs[2] = terzaghi_drainage_pressure; ctxs[2] = ctx;
2231         ierr = DMProjectFunction(dm, t, funcs, ctxs, INSERT_VALUES, u);CHKERRQ(ierr);
2232         break;
2233       case SOL_MANDEL:
2234         funcs[0] = mandel_initial_u;         ctxs[0] = ctx;
2235         funcs[1] = mandel_initial_eps;       ctxs[1] = ctx;
2236         funcs[2] = mandel_drainage_pressure; ctxs[2] = ctx;
2237         ierr = DMProjectFunction(dm, t, funcs, ctxs, INSERT_VALUES, u);CHKERRQ(ierr);
2238         break;
2239       case SOL_CRYER:
2240         funcs[0] = cryer_initial_u;         ctxs[0] = ctx;
2241         funcs[1] = cryer_initial_eps;       ctxs[1] = ctx;
2242         funcs[2] = cryer_drainage_pressure; ctxs[2] = ctx;
2243         ierr = DMProjectFunction(dm, t, funcs, ctxs, INSERT_VALUES, u);CHKERRQ(ierr);
2244         break;
2245       default:
2246         ierr = DMComputeExactSolution(dm, t, u, NULL);CHKERRQ(ierr);
2247     }
2248   } else {
2249     ierr = DMComputeExactSolution(dm, t, u, NULL);CHKERRQ(ierr);
2250   }
2251   PetscFunctionReturn(0);
2252 }
2253 
2254 /* Need to create Viewer each time because HDF5 can get corrupted */
2255 static PetscErrorCode SolutionMonitor(TS ts, PetscInt steps, PetscReal time, Vec u, void *mctx)
2256 {
2257   DM                dm;
2258   Vec               exact;
2259   PetscViewer       viewer;
2260   PetscViewerFormat format;
2261   PetscOptions      options;
2262   const char       *prefix;
2263   PetscErrorCode    ierr;
2264 
2265   PetscFunctionBegin;
2266   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
2267   ierr = PetscObjectGetOptions((PetscObject) ts, &options);CHKERRQ(ierr);
2268   ierr = PetscObjectGetOptionsPrefix((PetscObject) ts, &prefix);CHKERRQ(ierr);
2269   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) ts), options, prefix, "-monitor_solution", &viewer, &format, NULL);CHKERRQ(ierr);
2270   ierr = DMGetGlobalVector(dm, &exact);CHKERRQ(ierr);
2271   ierr = DMComputeExactSolution(dm, time, exact, NULL);CHKERRQ(ierr);
2272   ierr = DMSetOutputSequenceNumber(dm, steps, time);CHKERRQ(ierr);
2273   ierr = VecView(exact, viewer);CHKERRQ(ierr);
2274   ierr = VecView(u, viewer);CHKERRQ(ierr);
2275   ierr = DMRestoreGlobalVector(dm, &exact);CHKERRQ(ierr);
2276   {
2277     PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
2278     void            **ectxs;
2279     PetscReal        *err;
2280     PetscInt          Nf, f;
2281 
2282     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
2283     ierr = PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err);CHKERRQ(ierr);
2284     {
2285       PetscInt Nds, s;
2286 
2287       ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
2288       for (s = 0; s < Nds; ++s) {
2289         PetscDS         ds;
2290         DMLabel         label;
2291         IS              fieldIS;
2292         const PetscInt *fields;
2293         PetscInt        dsNf, f;
2294 
2295         ierr = DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);CHKERRQ(ierr);
2296         ierr = PetscDSGetNumFields(ds, &dsNf);CHKERRQ(ierr);
2297         ierr = ISGetIndices(fieldIS, &fields);CHKERRQ(ierr);
2298         for (f = 0; f < dsNf; ++f) {
2299           const PetscInt field = fields[f];
2300           ierr = PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);CHKERRQ(ierr);
2301         }
2302         ierr = ISRestoreIndices(fieldIS, &fields);CHKERRQ(ierr);
2303       }
2304     }
2305     ierr = DMComputeL2FieldDiff(dm, time, exacts, ectxs, u, err);CHKERRQ(ierr);
2306     ierr = PetscPrintf(PetscObjectComm((PetscObject) ts), "Time: %g L_2 Error: [", time);CHKERRQ(ierr);
2307     for (f = 0; f < Nf; ++f) {
2308       if (f) {ierr = PetscPrintf(PetscObjectComm((PetscObject) ts), ", ");CHKERRQ(ierr);}
2309       ierr = PetscPrintf(PetscObjectComm((PetscObject) ts), "%g", (double) err[f]);CHKERRQ(ierr);
2310     }
2311     ierr = PetscPrintf(PetscObjectComm((PetscObject) ts), "]\n");CHKERRQ(ierr);
2312     ierr = PetscFree3(exacts, ectxs, err);CHKERRQ(ierr);
2313   }
2314   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
2315   PetscFunctionReturn(0);
2316 }
2317 
2318 static PetscErrorCode SetupMonitor(TS ts, AppCtx *ctx)
2319 {
2320   PetscViewer       viewer;
2321   PetscViewerFormat format;
2322   PetscOptions      options;
2323   const char       *prefix;
2324   PetscBool         flg;
2325   PetscErrorCode    ierr;
2326 
2327   PetscFunctionBegin;
2328   ierr = PetscObjectGetOptions((PetscObject) ts, &options);CHKERRQ(ierr);
2329   ierr = PetscObjectGetOptionsPrefix((PetscObject) ts, &prefix);CHKERRQ(ierr);
2330   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) ts), options, prefix, "-monitor_solution", &viewer, &format, &flg);CHKERRQ(ierr);
2331   if (flg) {ierr = TSMonitorSet(ts, SolutionMonitor, ctx, NULL);CHKERRQ(ierr);}
2332   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
2333   PetscFunctionReturn(0);
2334 }
2335 
2336 static PetscErrorCode TSAdaptChoose_Terzaghi(TSAdapt adapt, TS ts, PetscReal h, PetscInt *next_sc, PetscReal *next_h, PetscBool *accept, PetscReal *wlte, PetscReal *wltea, PetscReal *wlter)
2337 {
2338   static PetscReal dtTarget = -1.0;
2339   PetscReal        dtInitial;
2340   DM               dm;
2341   AppCtx          *ctx;
2342   PetscInt         step;
2343   PetscErrorCode   ierr;
2344 
2345   PetscFunctionBegin;
2346   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
2347   ierr = DMGetApplicationContext(dm, (void **) &ctx);CHKERRQ(ierr);
2348   ierr = TSGetStepNumber(ts, &step);CHKERRQ(ierr);
2349   dtInitial = 1.0e-4*ctx->t_r;
2350   if (!step) {
2351     if (PetscAbsReal(dtInitial - h) > PETSC_SMALL) {
2352       *accept  = PETSC_FALSE;
2353       *next_h  = dtInitial;
2354       dtTarget = h;
2355     } else {
2356       *accept  = PETSC_TRUE;
2357       *next_h  = dtTarget < 0.0 ? dtInitial : dtTarget;
2358       dtTarget = -1.0;
2359     }
2360   } else {
2361     *accept = PETSC_TRUE;
2362     *next_h = h;
2363   }
2364   *next_sc = 0;  /* Reuse the same order scheme */
2365   *wlte    = -1; /* Weighted local truncation error was not evaluated */
2366   *wltea   = -1; /* Weighted absolute local truncation error was not evaluated */
2367   *wlter   = -1; /* Weighted relative local truncation error was not evaluated */
2368   PetscFunctionReturn(0);
2369 }
2370 
2371 int main(int argc, char **argv)
2372 {
2373   AppCtx         ctx;       /* User-defined work context */
2374   DM             dm;        /* Problem specification */
2375   TS             ts;        /* Time Series / Nonlinear solver */
2376   Vec            u;         /* Solutions */
2377   const char    *name[3] = {"displacement", "tracestrain", "pressure"};
2378   PetscReal      t;
2379   PetscInt       Nc[3];
2380   PetscErrorCode ierr;
2381 
2382   ierr = PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr;
2383   ierr = ProcessOptions(PETSC_COMM_WORLD, &ctx);CHKERRQ(ierr);
2384   ierr = PetscBagCreate(PETSC_COMM_SELF, sizeof(Parameter), &ctx.bag);CHKERRQ(ierr);
2385   ierr = PetscMalloc1(ctx.niter, &ctx.zeroArray);CHKERRQ(ierr);
2386   ierr = SetupParameters(PETSC_COMM_WORLD, &ctx);CHKERRQ(ierr);
2387   /* Primal System */
2388   ierr = TSCreate(PETSC_COMM_WORLD, &ts);CHKERRQ(ierr);
2389   ierr = CreateMesh(PETSC_COMM_WORLD, &ctx, &dm);CHKERRQ(ierr);
2390   ierr = DMSetApplicationContext(dm, &ctx);CHKERRQ(ierr);
2391   ierr = TSSetDM(ts, dm);CHKERRQ(ierr);
2392 
2393   Nc[0] = ctx.dim;
2394   Nc[1] = 1;
2395   Nc[2] = 1;
2396 
2397   ierr = SetupFE(dm, ctx.simplex, 3, Nc, name, SetupPrimalProblem, &ctx);CHKERRQ(ierr);
2398   ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr);
2399   ierr = DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &ctx);CHKERRQ(ierr);
2400   ierr = DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx);CHKERRQ(ierr);
2401   ierr = DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx);CHKERRQ(ierr);
2402   ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr);
2403   ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
2404   ierr = TSSetComputeInitialCondition(ts, SetInitialConditions);CHKERRQ(ierr);
2405   ierr = SetupMonitor(ts, &ctx);CHKERRQ(ierr);
2406 
2407   if (ctx.solType != SOL_QUADRATIC_TRIG) {
2408     TSAdapt adapt;
2409 
2410     ierr = TSGetAdapt(ts, &adapt);CHKERRQ(ierr);
2411     adapt->ops->choose = TSAdaptChoose_Terzaghi;
2412   }
2413   if (ctx.solType == SOL_CRYER) {
2414     Mat          J;
2415     MatNullSpace sp;
2416 
2417     ierr = TSSetUp(ts);CHKERRQ(ierr);
2418     ierr = TSGetIJacobian(ts, &J, NULL, NULL, NULL);CHKERRQ(ierr);
2419     ierr = DMPlexCreateRigidBody(dm, 0, &sp); CHKERRQ(ierr);
2420     ierr = MatSetNullSpace(J, sp);CHKERRQ(ierr);
2421     ierr = MatNullSpaceDestroy(&sp);CHKERRQ(ierr);
2422   }
2423   ierr = TSGetTime(ts, &t);CHKERRQ(ierr);
2424   ierr = DMSetOutputSequenceNumber(dm, 0, t);CHKERRQ(ierr);
2425   ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr);
2426   ierr = SetInitialConditions(ts, u);CHKERRQ(ierr);
2427   ierr = PetscObjectSetName((PetscObject) u, "solution");CHKERRQ(ierr);
2428   ierr = TSSolve(ts, u);CHKERRQ(ierr);
2429   ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr);
2430   ierr = TSGetSolution(ts, &u);CHKERRQ(ierr);
2431   ierr = VecViewFromOptions(u, NULL, "-sol_vec_view");CHKERRQ(ierr);
2432 
2433   /* Cleanup */
2434   ierr = VecDestroy(&u);CHKERRQ(ierr);
2435   ierr = TSDestroy(&ts);CHKERRQ(ierr);
2436   ierr = DMDestroy(&dm);CHKERRQ(ierr);
2437   ierr = PetscBagDestroy(&ctx.bag);CHKERRQ(ierr);
2438   ierr = PetscFree(ctx.zeroArray);CHKERRQ(ierr);
2439   ierr = PetscFinalize();
2440   return ierr;
2441 }
2442 
2443 /*TEST
2444 
2445   test:
2446     suffix: 2d_quad_linear
2447     requires: triangle
2448     args: -sol_type quadratic_linear -dm_refine 2 \
2449       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2450       -dmts_check .0001 -ts_max_steps 5 -ts_monitor_extreme
2451 
2452   test:
2453     suffix: 3d_quad_linear
2454     requires: ctetgen
2455     args: -dim 3 -sol_type quadratic_linear -dm_refine 1 \
2456       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2457       -dmts_check .0001 -ts_max_steps 5 -ts_monitor_extreme
2458 
2459   test:
2460     suffix: 2d_trig_linear
2461     requires: triangle
2462     args: -sol_type trig_linear -dm_refine 1 \
2463       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2464       -dmts_check .0001 -ts_max_steps 5 -ts_dt 0.00001 -ts_monitor_extreme
2465 
2466   test:
2467     # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9, 2.1, 1.8]
2468     suffix: 2d_trig_linear_sconv
2469     requires: triangle
2470     args: -sol_type trig_linear -dm_refine 1 \
2471       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2472       -convest_num_refine 1 -ts_convergence_estimate -ts_convergence_temporal 0 -ts_max_steps 1 -ts_dt 0.00001 -pc_type lu
2473 
2474   test:
2475     suffix: 3d_trig_linear
2476     requires: ctetgen
2477     args: -dim 3 -sol_type trig_linear -dm_refine 1 \
2478       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2479       -dmts_check .0001 -ts_max_steps 2 -ts_monitor_extreme
2480 
2481   test:
2482     # -dm_refine 1 -convest_num_refine 2 gets L_2 convergence rate: [2.0, 2.1, 1.9]
2483     suffix: 3d_trig_linear_sconv
2484     requires: ctetgen
2485     args: -dim 3 -sol_type trig_linear -dm_refine 1 \
2486       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2487       -convest_num_refine 1 -ts_convergence_estimate -ts_convergence_temporal 0 -ts_max_steps 1 -pc_type lu
2488 
2489   test:
2490     suffix: 2d_quad_trig
2491     requires: triangle
2492     args: -sol_type quadratic_trig -dm_refine 2 \
2493       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2494       -dmts_check .0001 -ts_max_steps 5 -ts_monitor_extreme
2495 
2496   test:
2497     # Using -dm_refine 4 gets the convergence rates to [0.95, 0.97, 0.90]
2498     suffix: 2d_quad_trig_tconv
2499     requires: triangle
2500     args: -sol_type quadratic_trig -dm_refine 1 \
2501       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2502       -convest_num_refine 3 -ts_convergence_estimate -ts_max_steps 5 -pc_type lu
2503 
2504   test:
2505     suffix: 3d_quad_trig
2506     requires: ctetgen
2507     args: -dim 3 -sol_type quadratic_trig -dm_refine 1 \
2508       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2509       -dmts_check .0001 -ts_max_steps 5 -ts_monitor_extreme
2510 
2511   test:
2512     # Using -dm_refine 2 -convest_num_refine 3 gets the convergence rates to [1.0, 1.0, 1.0]
2513     suffix: 3d_quad_trig_tconv
2514     requires: ctetgen
2515     args: -dim 3 -sol_type quadratic_trig -dm_refine 1 \
2516       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2517       -convest_num_refine 1 -ts_convergence_estimate -ts_max_steps 5 -pc_type lu
2518 
2519   test:
2520     suffix: 2d_terzaghi
2521     requires: triangle
2522     args: -sol_type terzaghi -dm_plex_separate_marker -dm_plex_box_faces 1,8 -simplex 0 \
2523       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 -niter 16000 \
2524       -ts_dt 0.0028666667 -ts_max_steps 2 -ts_monitor -dmts_check .0001 -pc_type lu
2525 
2526   test:
2527     # -dm_plex_box_faces 1,64 -ts_max_steps 4 -convest_num_refine 3 gives L_2 convergence rate: [1.1, 1.1, 1.1]
2528     suffix: 2d_terzaghi_tconv
2529     requires: triangle
2530     args: -sol_type terzaghi -dm_plex_separate_marker -dm_plex_box_faces 1,8 -simplex 0 \
2531       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 -niter 16000 \
2532       -ts_dt 0.023 -ts_max_steps 2 -ts_convergence_estimate -convest_num_refine 1 -pc_type lu
2533 
2534   test:
2535     suffix: 2d_mandel
2536     requires: triangle
2537     args: -sol_type mandel -dm_plex_separate_marker -dm_refine 1 \
2538       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2539       -ts_dt 0.0028666667 -ts_max_steps 2 -ts_monitor -dmts_check .0001 -pc_type lu
2540 
2541   test:
2542     # -dm_refine 5 -ts_max_steps 4 -convest_num_refine 3 gives L_2 convergence rate: [0.26, -0.0058, 0.26]
2543     suffix: 2d_mandel_tconv
2544     requires: triangle
2545     args: -sol_type mandel -dm_plex_separate_marker -dm_refine 1 \
2546       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2547       -ts_dt 0.023 -ts_max_steps 2 -ts_convergence_estimate -convest_num_refine 1 -pc_type lu
2548 
2549   test:
2550     suffix: 3d_cryer
2551     requires: ctetgen !complex
2552     args: -sol_type cryer \
2553       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2554       -ts_dt 0.0028666667 -ts_max_time 0.014333 -ts_max_steps 2 -dmts_check .0001 -pc_type lu -pc_factor_shift_type nonzero
2555 
2556   test:
2557     # Displacement and Pressure converge. The analytic expression for trace strain is inaccurate at the origin
2558     # -bd_dm_refine 3 -ref_limit 0.00666667 -ts_max_steps 5 -convest_num_refine 2 gives L_2 convergence rate: [0.47, -0.43, 1.5]
2559     suffix: 3d_cryer_tconv
2560     requires: ctetgen !complex
2561     args: -sol_type cryer -bd_dm_refine 1 -ref_limit 0.00666667 \
2562       -displacement_petscspace_degree 2 -tracestrain_petscspace_degree 1 -pressure_petscspace_degree 1 \
2563       -ts_dt 0.023 -ts_max_time 0.092 -ts_max_steps 2 -ts_convergence_estimate -convest_num_refine 1 -pc_type lu -pc_factor_shift_type nonzero
2564 
2565 TEST*/
2566