1 static char help[] = "Poisson Problem in 2d and 3d with simplicial finite elements in both primal and mixed form.\n\
2 We solve the Poisson problem in a rectangular\n\
3 domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\
4 This example solves mixed form equation to get the flux field to calculate flux norm. We then use that for adaptive mesh refinement. \n\n\n";
5
6 /*
7 The primal (or original) Poisson problem, in the strong form, is given by,
8
9 \begin{align}
10 - \nabla \cdot ( \nabla u ) = f
11 \end{align}
12 where $u$ is potential.
13
14 The weak form of this equation is
15
16 \begin{align}
17 < \nabla v, \nabla u > - < v, \nabla u \cdot \hat{n} >_\Gamma - < v, f > = 0
18 \end{align}
19
20 The mixed Poisson problem, in the strong form, is given by,
21
22 \begin{align}
23 q - \nabla u &= 0 \\
24 - \nabla \cdot q &= f
25 \end{align}
26 where $u$ is the potential and $q$ is the flux.
27
28 The weak form of this equation is
29
30 \begin{align}
31 < t, q > + < \nabla \cdot t, u > - < t \cdot \hat{n}, u >_\Gamma &= 0 \\
32 <v, \nabla \cdot q> - < v, f > &= 0
33 \end{align}
34
35 We solve both primal and mixed problem and calculate the error in the flux norm, namely || e || = || q^m_h - \nabla u^p_h ||. Here superscript 'm' represents field from mixed form and 'p' represents field from the primal form.
36
37 The following boundary conditions are prescribed.
38
39 Primal problem:
40 \begin{align}
41 u = u_0 on \Gamma_D
42 \nabla u \cdot \hat{n} = g on \Gamma_N
43 \end{align}
44
45 Mixed problem:
46 \begin{align}
47 u = u_0 on \Gamma_D
48 q \cdot \hat{n} = g on \Gamma_N
49 \end{align}
50 __________\Gamma_D_____________
51 | |
52 | |
53 | |
54 \Gamma_N \Gamma_N
55 | |
56 | |
57 | |
58 |_________\Gamma_D_____________|
59
60 To visualize the automated adaptation
61
62 -dm_adapt_pre_view draw -dm_adapt_view draw -draw_pause -1 -geometry 0,0,1024,1024
63
64 and to compare with a naice gradient estimator use
65
66 -adaptor_type gradient
67
68 To see a sequence of adaptations
69
70 -snes_adapt_sequence 8 -adaptor_monitor_error draw::draw_lg
71 -dm_adapt_pre_view draw -dm_adapt_iter_view draw -dm_adapt_view draw -draw_pause 1 -geometry 0,0,1024,1024
72
73 To get a better view of the by-hand process, use
74
75 -dm_view hdf5:${PWD}/mesh.h5
76 -primal_sol_vec_view hdf5:${PWD}/mesh.h5::append
77 -flux_error_vec_view hdf5:${PWD}/mesh.h5::append
78 -exact_error_vec_view hdf5:${PWD}/mesh.h5::append
79 -refine_vec_view hdf5:${PWD}/mesh.h5::append
80 -adapt_dm_view draw -draw_pause -1
81
82 This is also possible with the automated path
83
84 -dm_view hdf5:${PWD}/mesh.h5
85 -adapt_primal_sol_vec_view hdf5:${PWD}/mesh.h5::append
86 -adapt_error_vec_view hdf5:${PWD}/mesh.h5::append
87 -adapt_vec_view hdf5:${PWD}/mesh.h5::append
88 */
89
90 #include <petsc/private/petscfeimpl.h>
91 #include <petscdmplex.h>
92 #include <petscsnes.h>
93 #include <petscdmadaptor.h>
94 #include <petscds.h>
95 #include <petscviewerhdf5.h>
96 #include <petscbag.h>
97
98 PETSC_EXTERN PetscErrorCode SetupMixed(DMAdaptor, DM);
99
100 typedef enum {
101 SOL_QUADRATIC,
102 SOL_TRIG,
103 SOL_SENSOR,
104 SOL_UNKNOWN,
105 NUM_SOL_TYPE
106 } SolType;
107 const char *SolTypeNames[NUM_SOL_TYPE + 4] = {"quadratic", "trig", "sensor", "unknown", "SolType", "SOL_", NULL};
108
109 typedef struct {
110 PetscBag param;
111 SolType solType;
112 PetscBool byHand;
113 PetscInt numAdapt;
114 } AppCtx;
115
116 typedef struct {
117 PetscReal k;
118 } Parameter;
119
120 /* Exact solution: u = x^2 + y^2 */
quadratic_u(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)121 static PetscErrorCode quadratic_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
122 {
123 PetscInt d;
124
125 u[0] = 0.0;
126 for (d = 0; d < dim; ++d) u[0] += x[d] * x[d];
127 return PETSC_SUCCESS;
128 }
129 /* Exact solution: q = (2x, 2y) */
quadratic_q(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)130 static PetscErrorCode quadratic_q(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
131 {
132 PetscInt c;
133 for (c = 0; c < Nc; ++c) u[c] = 2.0 * x[c];
134 return PETSC_SUCCESS;
135 }
136
137 /* Exact solution: u = sin( n \pi x ) * sin( n \pi y ) */
trig_u(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)138 static PetscErrorCode trig_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
139 {
140 const PetscReal n = 5.5;
141
142 u[0] = 1.0;
143 for (PetscInt d = 0; d < dim; ++d) u[0] *= PetscSinReal(n * PETSC_PI * x[d]);
144 return PETSC_SUCCESS;
145 }
trig_q(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)146 static PetscErrorCode trig_q(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
147 {
148 const PetscReal n = 5.5;
149
150 for (PetscInt c = 0; c < Nc; c++) u[c] = n * PETSC_PI * PetscCosReal(n * PETSC_PI * x[c]) * PetscSinReal(n * PETSC_PI * x[Nc - c - 1]);
151 return PETSC_SUCCESS;
152 }
153
154 /*
155 Classic hyperbolic sensor function for testing multi-scale anisotropic mesh adaptation:
156
157 f:[-1, 1]x[-1, 1] \to R,
158 f(x, y) = sin(50xy)/100 if |xy| > 2\pi/50 else sin(50xy)
159
160 (mapped to have domain [0,1] x [0,1] in this case).
161 */
sensor_u(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar u[],PetscCtx ctx)162 static PetscErrorCode sensor_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], PetscCtx ctx)
163 {
164 const PetscReal xref = 2. * x[0] - 1.;
165 const PetscReal yref = 2. * x[1] - 1.;
166 const PetscReal xy = xref * yref;
167
168 u[0] = PetscSinReal(50. * xy);
169 if (PetscAbsReal(xy) > 2. * PETSC_PI / 50.) u[0] *= 0.01;
170
171 return PETSC_SUCCESS;
172 }
173
174 /* Flux is (cos(50xy) * 50y/100, cos(50xy) * 50x/100) if |xy| > 2\pi/50 else (cos(50xy) * 50y, cos(50xy) * 50x) */
sensor_q(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar u[],PetscCtx ctx)175 static PetscErrorCode sensor_q(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], PetscCtx ctx)
176 {
177 const PetscReal xref = 2. * x[0] - 1.;
178 const PetscReal yref = 2. * x[1] - 1.;
179 const PetscReal xy = xref * yref;
180
181 u[0] = 50. * yref * PetscCosReal(50. * xy) * 2.0;
182 u[1] = 50. * xref * PetscCosReal(50. * xy) * 2.0;
183 if (PetscAbsReal(xy) > 2. * PETSC_PI / 50.) {
184 u[0] *= 0.01;
185 u[1] *= 0.01;
186 }
187 return PETSC_SUCCESS;
188 }
189
190 /* We set up residuals and Jacobians for the primal problem. */
f0_quadratic_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])191 static void f0_quadratic_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
192 {
193 f0[0] = 4.0;
194 }
195
f0_trig_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])196 static void f0_trig_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
197 {
198 const PetscReal n = 5.5;
199
200 f0[0] = -2.0 * PetscSqr(n * PETSC_PI) * PetscSinReal(n * PETSC_PI * x[0]) * PetscSinReal(n * PETSC_PI * x[1]);
201 }
202
f0_sensor_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])203 static void f0_sensor_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
204 {
205 const PetscReal xref = 2. * x[0] - 1.;
206 const PetscReal yref = 2. * x[1] - 1.;
207 const PetscReal xy = xref * yref;
208
209 f0[0] = -2500.0 * PetscSinReal(50. * xy) * (xref * xref + yref * yref) * 4.0;
210 if (PetscAbsReal(xy) > 2. * PETSC_PI / 50.) f0[0] *= 0.01;
211 }
212
f1_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])213 static void f1_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
214 {
215 const PetscReal k = PetscRealPart(constants[0]);
216
217 for (PetscInt d = 0; d < dim; ++d) f1[d] = k * u_x[uOff_x[0] + d];
218 }
219
f0_quadratic_bd_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])220 static void f0_quadratic_bd_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
221 {
222 const PetscReal k = PetscRealPart(constants[0]);
223 PetscScalar flux;
224
225 PetscCallAbort(PETSC_COMM_SELF, quadratic_q(dim, t, x, dim, &flux, NULL));
226 for (PetscInt d = 0; d < dim; ++d) f0[d] = -k * flux * n[d];
227 }
228
f0_trig_bd_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])229 static void f0_trig_bd_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
230 {
231 const PetscReal k = PetscRealPart(constants[0]);
232 PetscScalar flux;
233
234 PetscCallAbort(PETSC_COMM_SELF, trig_q(dim, t, x, dim, &flux, NULL));
235 for (PetscInt d = 0; d < dim; ++d) f0[d] = -k * flux * n[d];
236 }
237
f0_sensor_bd_primal(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])238 static void f0_sensor_bd_primal(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
239 {
240 const PetscReal k = PetscRealPart(constants[0]);
241 PetscScalar flux[2];
242
243 PetscCallAbort(PETSC_COMM_SELF, sensor_q(dim, t, x, dim, flux, NULL));
244 for (PetscInt d = 0; d < dim; ++d) f0[d] = -k * flux[d] * n[d];
245 }
246
g3_primal_uu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g3[])247 static void g3_primal_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
248 {
249 const PetscReal k = PetscRealPart(constants[0]);
250
251 for (PetscInt d = 0; d < dim; ++d) g3[d * dim + d] = k;
252 }
253
254 /* Now we set up the residuals and Jacobians mixed problem. */
f0_mixed_quadratic_u(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])255 static void f0_mixed_quadratic_u(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
256 {
257 f0[0] = 4.0;
258 for (PetscInt d = 0; d < dim; ++d) f0[0] += -u_x[uOff_x[0] + d * dim + d];
259 }
f0_mixed_trig_u(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])260 static void f0_mixed_trig_u(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
261 {
262 PetscReal n = 5.5;
263
264 f0[0] = -2.0 * PetscSqr(n * PETSC_PI) * PetscSinReal(n * PETSC_PI * x[0]) * PetscSinReal(n * PETSC_PI * x[1]);
265 for (PetscInt d = 0; d < dim; ++d) f0[0] += -u_x[uOff_x[0] + d * dim + d];
266 }
f0_mixed_sensor_u(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])267 static void f0_mixed_sensor_u(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
268 {
269 const PetscReal xref = 2. * x[0] - 1.;
270 const PetscReal yref = 2. * x[1] - 1.;
271 const PetscReal xy = xref * yref;
272
273 f0[0] = -2500.0 * PetscSinReal(50. * xy) * (xref * xref + yref * yref) * 4.0;
274 if (PetscAbsReal(xy) > 2. * PETSC_PI / 50.) f0[0] *= 0.01;
275 for (PetscInt d = 0; d < dim; ++d) f0[0] += -u_x[uOff_x[0] + d * dim + d];
276 }
277
f0_mixed_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])278 static void f0_mixed_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
279 {
280 for (PetscInt d = 0; d < dim; d++) f0[d] = u[uOff[0] + d];
281 }
282
f1_mixed_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])283 static void f1_mixed_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
284 {
285 const PetscReal k = PetscRealPart(constants[0]);
286
287 for (PetscInt d = 0; d < dim; d++) f1[d * dim + d] = k * u[uOff[1]];
288 }
289
f0_quadratic_bd_mixed_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])290 static void f0_quadratic_bd_mixed_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
291 {
292 const PetscReal k = PetscRealPart(constants[0]);
293 PetscScalar potential;
294
295 PetscCallAbort(PETSC_COMM_SELF, quadratic_u(dim, t, x, dim, &potential, NULL));
296 for (PetscInt d = 0; d < dim; ++d) f0[d] = -k * potential * n[d];
297 }
298
f0_trig_bd_mixed_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])299 static void f0_trig_bd_mixed_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
300 {
301 const PetscReal k = PetscRealPart(constants[0]);
302 PetscScalar potential;
303
304 PetscCallAbort(PETSC_COMM_SELF, trig_u(dim, t, x, dim, &potential, NULL));
305 for (PetscInt d = 0; d < dim; ++d) f0[d * dim + d] = -k * potential * n[d];
306 }
307
f0_sensor_bd_mixed_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])308 static void f0_sensor_bd_mixed_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
309 {
310 const PetscReal k = PetscRealPart(constants[0]);
311 PetscScalar potential;
312
313 PetscCallAbort(PETSC_COMM_SELF, sensor_u(dim, t, x, dim, &potential, NULL));
314 for (PetscInt d = 0; d < dim; ++d) f0[d * dim + d] = -k * potential * n[d];
315 }
316
317 /* <v, \nabla\cdot q> */
g1_mixed_uq(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g1[])318 static void g1_mixed_uq(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[])
319 {
320 for (PetscInt d = 0; d < dim; d++) g1[d * dim + d] = -1.0;
321 }
322
323 /* < t, q> */
g0_mixed_qq(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])324 static void g0_mixed_qq(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
325 {
326 for (PetscInt d = 0; d < dim; d++) g0[d * dim + d] = 1.0;
327 }
328
329 /* <\nabla\cdot t, u> = <\nabla t, Iu> */
g2_mixed_qu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g2[])330 static void g2_mixed_qu(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[])
331 {
332 const PetscReal k = PetscRealPart(constants[0]);
333
334 for (PetscInt d = 0; d < dim; d++) g2[d * dim + d] = k;
335 }
336
ProcessOptions(MPI_Comm comm,AppCtx * user)337 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *user)
338 {
339 PetscFunctionBeginUser;
340 PetscOptionsBegin(comm, "", "Flux norm error in primal poisson problem Options", "DMPLEX");
341 user->byHand = PETSC_TRUE;
342 user->numAdapt = 1;
343 user->solType = SOL_QUADRATIC;
344
345 PetscCall(PetscOptionsGetBool(NULL, NULL, "-by_hand", &user->byHand, NULL));
346 PetscCall(PetscOptionsGetInt(NULL, NULL, "-num_adapt", &user->numAdapt, NULL));
347 PetscCall(PetscOptionsEnum("-sol_type", "Type of exact solution", "ex27.c", SolTypeNames, (PetscEnum)user->solType, (PetscEnum *)&user->solType, NULL));
348 PetscOptionsEnd();
349 PetscFunctionReturn(PETSC_SUCCESS);
350 }
351
SetupParameters(PetscBag bag,AppCtx * user)352 static PetscErrorCode SetupParameters(PetscBag bag, AppCtx *user)
353 {
354 Parameter *param;
355
356 PetscFunctionBeginUser;
357 PetscCall(PetscBagGetData(bag, ¶m));
358 PetscCall(PetscBagSetName(bag, "par", "Poisson parameters"));
359 PetscCall(PetscBagRegisterReal(bag, ¶m->k, 1.0, "k", "Thermal conductivity"));
360 PetscCall(PetscBagSetFromOptions(bag));
361 PetscFunctionReturn(PETSC_SUCCESS);
362 }
363
CreateMesh(MPI_Comm comm,AppCtx * user,DM * dm)364 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
365 {
366 PetscFunctionBeginUser;
367 PetscCall(DMCreate(comm, dm));
368 PetscCall(DMSetType(*dm, DMPLEX));
369 PetscCall(DMSetFromOptions(*dm));
370 PetscCall(DMSetApplicationContext(*dm, &user));
371 PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
372 PetscFunctionReturn(PETSC_SUCCESS);
373 }
374
SetupPrimalProblem(DM dm,AppCtx * user)375 static PetscErrorCode SetupPrimalProblem(DM dm, AppCtx *user)
376 {
377 PetscDS ds;
378 DMLabel label;
379 PetscInt id, bd;
380 Parameter *param;
381 PetscWeakForm wf;
382
383 PetscFunctionBeginUser;
384 PetscCall(DMGetDS(dm, &ds));
385 PetscCall(DMGetLabel(dm, "marker", &label));
386
387 PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, g3_primal_uu));
388
389 switch (user->solType) {
390 case SOL_QUADRATIC:
391 PetscCall(PetscDSSetResidual(ds, 0, f0_quadratic_primal, f1_primal));
392
393 id = 1;
394 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "bottom wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)quadratic_u, NULL, user, NULL));
395
396 id = 2;
397 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "right wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
398 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
399 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_quadratic_bd_primal, 0, NULL));
400
401 id = 3;
402 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "top wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)quadratic_u, NULL, user, NULL));
403
404 id = 4;
405 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "left wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
406 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
407 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_quadratic_bd_primal, 0, NULL));
408
409 PetscCall(PetscDSSetExactSolution(ds, 0, quadratic_u, user));
410 break;
411 case SOL_TRIG:
412 PetscCall(PetscDSSetResidual(ds, 0, f0_trig_primal, f1_primal));
413
414 id = 1;
415 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "bottom wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)trig_u, NULL, user, NULL));
416
417 id = 2;
418 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "right wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
419 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
420 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_trig_bd_primal, 0, NULL));
421
422 id = 3;
423 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "top wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)trig_u, NULL, user, NULL));
424
425 id = 4;
426 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "left wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
427 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
428 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_trig_bd_primal, 0, NULL));
429
430 PetscCall(PetscDSSetExactSolution(ds, 0, trig_u, user));
431 break;
432 case SOL_SENSOR:
433 PetscCall(PetscDSSetResidual(ds, 0, f0_sensor_primal, f1_primal));
434
435 id = 1;
436 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "bottom wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)sensor_u, NULL, user, NULL));
437
438 id = 2;
439 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "right wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
440 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
441 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_sensor_bd_primal, 0, NULL));
442
443 id = 3;
444 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "top wall primal potential", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)sensor_u, NULL, user, NULL));
445
446 id = 4;
447 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "left wall flux", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
448 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
449 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_sensor_bd_primal, 0, NULL));
450
451 PetscCall(PetscDSSetExactSolution(ds, 0, sensor_u, user));
452 break;
453 default:
454 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid exact solution type %s", SolTypeNames[PetscMin(user->solType, SOL_UNKNOWN)]);
455 }
456
457 /* Setup constants */
458 {
459 PetscCall(PetscBagGetData(user->param, ¶m));
460 PetscScalar constants[1];
461
462 constants[0] = param->k;
463
464 PetscCall(PetscDSSetConstants(ds, 1, constants));
465 }
466 PetscFunctionReturn(PETSC_SUCCESS);
467 }
468
SetupPrimalDiscretization(DM dm,AppCtx * user)469 static PetscErrorCode SetupPrimalDiscretization(DM dm, AppCtx *user)
470 {
471 DM cdm = dm;
472 PetscFE fe[1];
473 DMPolytopeType ct;
474 PetscInt dim, cStart;
475 MPI_Comm comm;
476
477 PetscFunctionBeginUser;
478 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
479 PetscCall(DMGetDimension(dm, &dim));
480
481 /* Create finite element */
482 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
483 PetscCall(DMPlexGetCellType(dm, cStart, &ct));
484 PetscCall(PetscFECreateByCell(comm, dim, 1, ct, "primal_potential_", PETSC_DEFAULT, &fe[0]));
485 PetscCall(PetscObjectSetName((PetscObject)fe[0], "primal potential"));
486
487 /* Set discretization and boundary conditions for each mesh */
488 PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe[0]));
489 PetscCall(DMCreateDS(dm));
490 while (cdm) {
491 PetscCall(DMCopyDisc(dm, cdm));
492 PetscCall(DMGetCoarseDM(cdm, &cdm));
493 }
494
495 PetscCall(PetscFEDestroy(&fe[0]));
496 PetscFunctionReturn(PETSC_SUCCESS);
497 }
498
SetupMixedProblem(DM dm,AppCtx * user)499 static PetscErrorCode SetupMixedProblem(DM dm, AppCtx *user)
500 {
501 PetscDS ds;
502 DMLabel label;
503 PetscInt id, bd;
504 Parameter *param;
505 PetscWeakForm wf;
506
507 PetscFunctionBeginUser;
508 PetscCall(DMGetDS(dm, &ds));
509 PetscCall(DMGetLabel(dm, "marker", &label));
510
511 /* Residual terms */
512 PetscCall(PetscDSSetResidual(ds, 0, f0_mixed_q, f1_mixed_q));
513
514 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_mixed_qq, NULL, NULL, NULL));
515 PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, g2_mixed_qu, NULL));
516
517 PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, g1_mixed_uq, NULL, NULL));
518
519 switch (user->solType) {
520 case SOL_QUADRATIC:
521 PetscCall(PetscDSSetResidual(ds, 1, f0_mixed_quadratic_u, NULL));
522
523 id = 1;
524 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral bottom wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
525 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
526 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_quadratic_bd_mixed_q, 0, NULL));
527
528 id = 2;
529 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "right wall flux", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)quadratic_q, NULL, user, NULL));
530
531 id = 4;
532 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "left wall flux", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)quadratic_q, NULL, user, NULL));
533
534 id = 3;
535 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral top wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
536 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
537 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_quadratic_bd_mixed_q, 0, NULL));
538
539 PetscCall(PetscDSSetExactSolution(ds, 0, quadratic_q, user));
540 PetscCall(PetscDSSetExactSolution(ds, 1, quadratic_u, user));
541 break;
542 case SOL_TRIG:
543 PetscCall(PetscDSSetResidual(ds, 1, f0_mixed_trig_u, NULL));
544
545 id = 1;
546 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral bottom wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
547 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
548 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_trig_bd_mixed_q, 0, NULL));
549
550 id = 2;
551 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "right wall flux", label, 1, &id, 1, 0, NULL, (PetscVoidFn *)trig_q, NULL, user, NULL));
552
553 id = 4;
554 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "left wall flux", label, 1, &id, 1, 0, NULL, (PetscVoidFn *)trig_q, NULL, user, NULL));
555
556 id = 3;
557 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral top wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
558 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
559 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_trig_bd_mixed_q, 0, NULL));
560
561 PetscCall(PetscDSSetExactSolution(ds, 0, trig_q, user));
562 PetscCall(PetscDSSetExactSolution(ds, 1, trig_u, user));
563 break;
564 case SOL_SENSOR:
565 PetscCall(PetscDSSetResidual(ds, 1, f0_mixed_sensor_u, NULL));
566
567 id = 1;
568 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral bottom wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
569 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
570 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_sensor_bd_mixed_q, 0, NULL));
571
572 id = 2;
573 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "right wall flux", label, 1, &id, 1, 0, NULL, (PetscVoidFn *)sensor_q, NULL, user, NULL));
574
575 id = 4;
576 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "left wall flux", label, 1, &id, 1, 0, NULL, (PetscVoidFn *)sensor_q, NULL, user, NULL));
577
578 id = 3;
579 PetscCall(DMAddBoundary(dm, DM_BC_NATURAL, "Dirichlet Bd Integral top wall", label, 1, &id, 0, 0, NULL, NULL, NULL, user, &bd));
580 PetscCall(PetscDSGetBoundary(ds, bd, &wf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
581 PetscCall(PetscWeakFormSetIndexBdResidual(wf, label, id, 0, 0, 0, f0_sensor_bd_mixed_q, 0, NULL));
582
583 PetscCall(PetscDSSetExactSolution(ds, 0, sensor_q, user));
584 PetscCall(PetscDSSetExactSolution(ds, 1, sensor_u, user));
585 break;
586 default:
587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid exact solution type %s", SolTypeNames[PetscMin(user->solType, SOL_UNKNOWN)]);
588 }
589
590 /* Setup constants */
591 {
592 PetscCall(PetscBagGetData(user->param, ¶m));
593 PetscScalar constants[1];
594
595 constants[0] = param->k;
596
597 PetscCall(PetscDSSetConstants(ds, 1, constants));
598 }
599 PetscFunctionReturn(PETSC_SUCCESS);
600 }
601
SetupMixedDiscretization(DM dm,AppCtx * user)602 static PetscErrorCode SetupMixedDiscretization(DM dm, AppCtx *user)
603 {
604 DM cdm = dm;
605 PetscFE fe[2];
606 DMPolytopeType ct;
607 PetscInt dim, cStart;
608 MPI_Comm comm;
609
610 PetscFunctionBeginUser;
611 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
612 PetscCall(DMGetDimension(dm, &dim));
613
614 /* Create finite element */
615 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
616 PetscCall(DMPlexGetCellType(dm, cStart, &ct));
617 PetscCall(PetscFECreateByCell(comm, dim, dim, ct, "mixed_flux_", PETSC_DEFAULT, &fe[0]));
618 PetscCall(PetscObjectSetName((PetscObject)fe[0], "mixed flux"));
619 /* NOTE: Set the same quadrature order as the primal problem here or use the command line option. */
620
621 PetscCall(PetscFECreateByCell(comm, dim, 1, ct, "mixed_potential_", PETSC_DEFAULT, &fe[1]));
622 PetscCall(PetscFECopyQuadrature(fe[0], fe[1]));
623 PetscCall(PetscObjectSetName((PetscObject)fe[1], "mixed potential"));
624
625 /* Set discretization and boundary conditions for each mesh */
626 PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe[0]));
627 PetscCall(DMSetField(dm, 1, NULL, (PetscObject)fe[1]));
628 PetscCall(DMCreateDS(dm));
629 while (cdm) {
630 PetscCall(DMCopyDisc(dm, cdm));
631 PetscCall(DMGetCoarseDM(cdm, &cdm));
632 }
633 PetscCall(PetscFEDestroy(&fe[0]));
634 PetscCall(PetscFEDestroy(&fe[1]));
635 PetscFunctionReturn(PETSC_SUCCESS);
636 }
637
SetupMixed(DMAdaptor adaptor,DM mdm)638 PetscErrorCode SetupMixed(DMAdaptor adaptor, DM mdm)
639 {
640 AppCtx *ctx;
641
642 PetscFunctionBeginUser;
643 PetscCall(DMGetApplicationContext(mdm, &ctx));
644 PetscCall(SetupMixedDiscretization(mdm, ctx));
645 PetscCall(SetupMixedProblem(mdm, ctx));
646 PetscFunctionReturn(PETSC_SUCCESS);
647 }
648
main(int argc,char ** argv)649 int main(int argc, char **argv)
650 {
651 DM dm, mdm; /* problem specification */
652 SNES snes, msnes; /* nonlinear solvers */
653 Vec u, mu; /* solution vectors */
654 Vec fluxError, exactError; /* Element wise error vector */
655 PetscReal fluxNorm, exactNorm; /* Flux error norm */
656 AppCtx user; /* user-defined work context */
657
658 PetscFunctionBeginUser;
659 PetscCall(PetscInitialize(&argc, &argv, NULL, help));
660 PetscCall(PetscBagCreate(PETSC_COMM_WORLD, sizeof(Parameter), &user.param));
661 PetscCall(SetupParameters(user.param, &user));
662 PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
663
664 // Set up and solve primal problem
665 PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
666 PetscCall(DMSetApplicationContext(dm, &user));
667 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
668 PetscCall(SNESSetDM(snes, dm));
669
670 PetscCall(SetupPrimalDiscretization(dm, &user));
671 PetscCall(SetupPrimalProblem(dm, &user));
672 PetscCall(DMCreateGlobalVector(dm, &u));
673 PetscCall(VecSet(u, 0.0));
674 PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, &user));
675 PetscCall(SNESSetFromOptions(snes));
676 PetscCall(DMSNESCheckFromOptions(snes, u));
677
678 for (PetscInt a = 0; a < user.numAdapt; ++a) {
679 if (a > 0) {
680 char prefix[16];
681
682 PetscCall(PetscSNPrintf(prefix, 16, "a%d_", (int)a));
683 PetscCall(SNESSetOptionsPrefix(snes, prefix));
684 }
685 PetscCall(SNESSolve(snes, NULL, u));
686
687 // Needed if you allow SNES to refine
688 PetscCall(SNESGetSolution(snes, &u));
689 PetscCall(VecGetDM(u, &dm));
690 }
691
692 PetscCall(PetscObjectSetName((PetscObject)u, "Primal Solution "));
693 PetscCall(VecViewFromOptions(u, NULL, "-primal_sol_vec_view"));
694
695 if (user.byHand) {
696 // Set up and solve mixed problem
697 PetscCall(DMClone(dm, &mdm));
698 PetscCall(SNESCreate(PETSC_COMM_WORLD, &msnes));
699 PetscCall(SNESSetOptionsPrefix(msnes, "mixed_"));
700 PetscCall(SNESSetDM(msnes, mdm));
701
702 PetscCall(SetupMixedDiscretization(mdm, &user));
703 PetscCall(SetupMixedProblem(mdm, &user));
704 PetscCall(DMCreateGlobalVector(mdm, &mu));
705 PetscCall(VecSet(mu, 0.0));
706 PetscCall(DMPlexSetSNESLocalFEM(mdm, PETSC_FALSE, &user));
707 PetscCall(SNESSetFromOptions(msnes));
708
709 PetscCall(DMSNESCheckFromOptions(msnes, mu));
710 PetscCall(SNESSolve(msnes, NULL, mu));
711 PetscCall(PetscObjectSetName((PetscObject)mu, "Mixed Solution "));
712 PetscCall(VecViewFromOptions(mu, NULL, "-mixed_sol_vec_view"));
713
714 // Create the error space of piecewise constants
715 DM dmErr;
716 PetscFE feErr;
717 DMPolytopeType ct;
718 PetscInt dim, cStart;
719
720 PetscCall(DMClone(dm, &dmErr));
721 PetscCall(DMGetDimension(dmErr, &dim));
722 PetscCall(DMPlexGetHeightStratum(dmErr, 0, &cStart, NULL));
723 PetscCall(DMPlexGetCellType(dmErr, cStart, &ct));
724 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, 0, PETSC_DEFAULT, &feErr));
725 PetscCall(PetscObjectSetName((PetscObject)feErr, "Error"));
726 PetscCall(DMSetField(dmErr, 0, NULL, (PetscObject)feErr));
727 PetscCall(PetscFEDestroy(&feErr));
728 PetscCall(DMCreateDS(dmErr));
729 PetscCall(DMViewFromOptions(dmErr, NULL, "-dmerr_view"));
730
731 // Compute the flux norm
732 PetscCall(DMGetGlobalVector(dmErr, &fluxError));
733 PetscCall(PetscObjectSetName((PetscObject)fluxError, "Flux Error"));
734 PetscCall(DMGetGlobalVector(dmErr, &exactError));
735 PetscCall(PetscObjectSetName((PetscObject)exactError, "Analytical Error"));
736 PetscCall(DMPlexComputeL2FluxDiffVec(u, 0, mu, 0, fluxError));
737 {
738 PetscDS ds;
739 PetscSimplePointFn *func[2] = {NULL, NULL};
740 void *ctx[2] = {NULL, NULL};
741
742 PetscCall(DMGetDS(mdm, &ds));
743 PetscCall(PetscDSGetExactSolution(ds, 0, &func[0], &ctx[0]));
744 PetscCall(DMPlexComputeL2DiffVec(mdm, 0.0, func, ctx, mu, exactError));
745 }
746 PetscCall(VecNorm(fluxError, NORM_2, &fluxNorm));
747 PetscCall(VecNorm(exactError, NORM_2, &exactNorm));
748 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Flux error norm = %g\t Exact flux error norm = %g\n", (double)fluxNorm, (double)exactNorm));
749 PetscCall(VecViewFromOptions(fluxError, NULL, "-flux_error_vec_view"));
750 PetscCall(VecViewFromOptions(exactError, NULL, "-exact_error_vec_view"));
751
752 // Adaptive refinement based on calculated error
753 DM rdm;
754 VecTagger refineTag;
755 DMLabel adaptLabel;
756 IS refineIS;
757 Vec ref;
758
759 PetscCall(DMLabelCreate(PETSC_COMM_WORLD, "adapt", &adaptLabel));
760 PetscCall(DMLabelSetDefaultValue(adaptLabel, DM_ADAPT_COARSEN));
761 PetscCall(VecTaggerCreate(PETSC_COMM_WORLD, &refineTag));
762 PetscCall(VecTaggerSetFromOptions(refineTag));
763 PetscCall(VecTaggerSetUp(refineTag));
764 PetscCall(PetscObjectViewFromOptions((PetscObject)refineTag, NULL, "-tag_view"));
765
766 PetscCall(VecTaggerComputeIS(refineTag, fluxError, &refineIS, NULL));
767 PetscCall(VecTaggerDestroy(&refineTag));
768 PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE, refineIS));
769 PetscCall(ISViewFromOptions(refineIS, NULL, "-refine_is_view"));
770 PetscCall(ISDestroy(&refineIS));
771
772 PetscCall(DMPlexCreateLabelField(dm, adaptLabel, &ref));
773 PetscCall(VecViewFromOptions(ref, NULL, "-refine_vec_view"));
774 PetscCall(VecDestroy(&ref));
775
776 // Mark adaptation phase with prefix ref_
777 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, "adapt_"));
778 PetscCall(DMAdaptLabel(dm, adaptLabel, &rdm));
779 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, NULL));
780 PetscCall(PetscObjectSetName((PetscObject)rdm, "Adaptively Refined DM"));
781 PetscCall(DMViewFromOptions(rdm, NULL, "-adapt_dm_view"));
782 PetscCall(DMDestroy(&rdm));
783 PetscCall(DMLabelDestroy(&adaptLabel));
784
785 // Destroy the error structures
786 PetscCall(DMRestoreGlobalVector(dmErr, &fluxError));
787 PetscCall(DMRestoreGlobalVector(dmErr, &exactError));
788 PetscCall(DMDestroy(&dmErr));
789
790 // Destroy the mixed structures
791 PetscCall(VecDestroy(&mu));
792 PetscCall(DMDestroy(&mdm));
793 PetscCall(SNESDestroy(&msnes));
794 }
795
796 // Destroy the primal structures
797 PetscCall(VecDestroy(&u));
798 PetscCall(DMDestroy(&dm));
799 PetscCall(SNESDestroy(&snes));
800 PetscCall(PetscBagDestroy(&user.param));
801 PetscCall(PetscFinalize());
802 return 0;
803 }
804
805 /*TEST
806
807 # Tests using the explicit code above
808 testset:
809 suffix: 2d_p2_rt0p0_byhand
810 requires: triangle
811 args: -dm_plex_box_faces 1,1 -dm_plex_box_lower 0,0 -dm_plex_box_upper 1,1 -dm_refine 3 \
812 -primal_potential_petscspace_degree 2 \
813 -mixed_potential_petscdualspace_lagrange_continuity 0 \
814 -mixed_flux_petscspace_type ptrimmed \
815 -mixed_flux_petscspace_components 2 \
816 -mixed_flux_petscspace_ptrimmed_form_degree -1 \
817 -mixed_flux_petscdualspace_order 1 \
818 -mixed_flux_petscdualspace_form_degree -1 \
819 -mixed_flux_petscdualspace_lagrange_trimmed true \
820 -mixed_flux_petscfe_default_quadrature_order 2 \
821 -vec_tagger_type cdf -vec_tagger_box 0.9,1.0 \
822 -tag_view \
823 -adapt_dm_adaptor cellrefiner -adapt_dm_plex_transform_type refine_sbr \
824 -dmsnes_check 0.001 -mixed_dmsnes_check 0.001 -pc_type jacobi -mixed_pc_type jacobi
825 test:
826 suffix: quadratic
827 args: -sol_type quadratic
828 test:
829 suffix: trig
830 args: -sol_type trig
831 test:
832 suffix: sensor
833 args: -sol_type sensor
834
835 # Tests using the embedded adaptor in SNES
836 testset:
837 suffix: 2d_p2_rt0p0
838 requires: triangle defined(PETSC_HAVE_EXECUTABLE_EXPORT)
839 args: -dm_plex_box_faces 1,1 -dm_plex_box_lower 0,0 -dm_plex_box_upper 1,1 -dm_refine 3 \
840 -primal_potential_petscspace_degree 2 \
841 -mixed_potential_petscdualspace_lagrange_continuity 0 \
842 -mixed_flux_petscspace_type ptrimmed \
843 -mixed_flux_petscspace_components 2 \
844 -mixed_flux_petscspace_ptrimmed_form_degree -1 \
845 -mixed_flux_petscdualspace_order 1 \
846 -mixed_flux_petscdualspace_form_degree -1 \
847 -mixed_flux_petscdualspace_lagrange_trimmed true \
848 -mixed_flux_petscfe_default_quadrature_order 2 \
849 -by_hand 0 \
850 -refine_vec_tagger_type cdf -refine_vec_tagger_box 0.9,1.0 \
851 -snes_adapt_view \
852 -adapt_dm_adaptor cellrefiner -adapt_dm_plex_transform_type refine_sbr \
853 -adaptor_criterion label -adaptor_type flux -adaptor_mixed_setup_function SetupMixed \
854 -snes_adapt_sequence 1 -pc_type jacobi -mixed_pc_type jacobi
855 test:
856 suffix: quadratic
857 args: -sol_type quadratic -adaptor_monitor_error
858 test:
859 suffix: trig
860 args: -sol_type trig -adaptor_monitor_error
861 test:
862 suffix: sensor
863 args: -sol_type sensor
864
865 # Tests using multiple adaptor loops
866 testset:
867 suffix: 2d_p2_rt0p0_a2
868 requires: triangle defined(PETSC_HAVE_EXECUTABLE_EXPORT)
869 args: -dm_plex_box_faces 1,1 -dm_plex_box_lower 0,0 -dm_plex_box_upper 1,1 -dm_refine 3 \
870 -primal_potential_petscspace_degree 2 \
871 -mixed_potential_petscdualspace_lagrange_continuity 0 \
872 -mixed_flux_petscspace_type ptrimmed \
873 -mixed_flux_petscspace_components 2 \
874 -mixed_flux_petscspace_ptrimmed_form_degree -1 \
875 -mixed_flux_petscdualspace_order 1 \
876 -mixed_flux_petscdualspace_form_degree -1 \
877 -mixed_flux_petscdualspace_lagrange_trimmed true \
878 -mixed_flux_petscfe_default_quadrature_order 2 \
879 -by_hand 0 \
880 -num_adapt 2 \
881 -refine_vec_tagger_type cdf -refine_vec_tagger_box 0.9,1.0 \
882 -snes_adapt_view \
883 -adapt_dm_adaptor cellrefiner -adapt_dm_plex_transform_type refine_sbr \
884 -adaptor_criterion label -adaptor_type gradient -adaptor_mixed_setup_function SetupMixed \
885 -snes_adapt_sequence 2 -pc_type jacobi \
886 -a1_refine_vec_tagger_type cdf -a1_refine_vec_tagger_box 0.9,1.0 \
887 -a1_snes_adapt_view \
888 -a1_adaptor_criterion label -a1_adaptor_type flux -a1_adaptor_mixed_setup_function SetupMixed \
889 -a1_snes_adapt_sequence 1 -a1_pc_type jacobi -a1_mixed_pc_type jacobi
890 test:
891 suffix: sensor
892 args: -sol_type sensor
893
894 TEST*/
895