xref: /petsc/src/ksp/ksp/tutorials/ex42.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1 static char help[] = "Solves the incompressible, variable viscosity Stokes equation in 3d using Q1Q1 elements, \n\
2 stabilized with Bochev's polynomial projection method. Note that implementation here assumes \n\
3 all boundaries are free-slip, i.e. zero normal flow and zero tangential stress \n\
4      -mx : number elements in x-direction \n\
5      -my : number elements in y-direction \n\
6      -mz : number elements in z-direction \n\
7      -stokes_ksp_monitor_blocks : active monitor for each component u,v,w,p \n\
8      -model : defines viscosity and forcing function. Choose either: 0 (isoviscous), 1 (manufactured-broken), 2 (solcx-2d), 3 (sinker), 4 (subdomain jumps) \n";
9 
10 /* Contributed by Dave May */
11 
12 #include <petscksp.h>
13 #include <petscdmda.h>
14 
15 #define PROFILE_TIMING
16 #define ASSEMBLE_LOWER_TRIANGULAR
17 
18 #define NSD          3 /* number of spatial dimensions */
19 #define NODES_PER_EL 8 /* nodes per element */
20 #define U_DOFS       3 /* degrees of freedom per velocity node */
21 #define P_DOFS       1 /* degrees of freedom per pressure node */
22 #define GAUSS_POINTS 8
23 
24 /* Gauss point based evaluation */
25 typedef struct {
26   PetscScalar gp_coords[NSD * GAUSS_POINTS];
27   PetscScalar eta[GAUSS_POINTS];
28   PetscScalar fx[GAUSS_POINTS];
29   PetscScalar fy[GAUSS_POINTS];
30   PetscScalar fz[GAUSS_POINTS];
31   PetscScalar hc[GAUSS_POINTS];
32 } GaussPointCoefficients;
33 
34 typedef struct {
35   PetscScalar u_dof;
36   PetscScalar v_dof;
37   PetscScalar w_dof;
38   PetscScalar p_dof;
39 } StokesDOF;
40 
41 typedef struct _p_CellProperties *CellProperties;
42 struct _p_CellProperties {
43   PetscInt                ncells;
44   PetscInt                mx, my, mz;
45   PetscInt                sex, sey, sez;
46   GaussPointCoefficients *gpc;
47 };
48 
49 /* elements */
CellPropertiesCreate(DM da_stokes,CellProperties * C)50 PetscErrorCode CellPropertiesCreate(DM da_stokes, CellProperties *C)
51 {
52   CellProperties cells;
53   PetscInt       mx, my, mz, sex, sey, sez;
54 
55   PetscFunctionBeginUser;
56   PetscCall(PetscNew(&cells));
57 
58   PetscCall(DMDAGetElementsCorners(da_stokes, &sex, &sey, &sez));
59   PetscCall(DMDAGetElementsSizes(da_stokes, &mx, &my, &mz));
60   cells->mx     = mx;
61   cells->my     = my;
62   cells->mz     = mz;
63   cells->ncells = mx * my * mz;
64   cells->sex    = sex;
65   cells->sey    = sey;
66   cells->sez    = sez;
67 
68   PetscCall(PetscMalloc1(mx * my * mz, &cells->gpc));
69 
70   *C = cells;
71   PetscFunctionReturn(PETSC_SUCCESS);
72 }
73 
CellPropertiesDestroy(CellProperties * C)74 PetscErrorCode CellPropertiesDestroy(CellProperties *C)
75 {
76   CellProperties cells;
77 
78   PetscFunctionBeginUser;
79   if (!C) PetscFunctionReturn(PETSC_SUCCESS);
80   cells = *C;
81   PetscCall(PetscFree(cells->gpc));
82   PetscCall(PetscFree(cells));
83   *C = NULL;
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
CellPropertiesGetCell(CellProperties C,PetscInt II,PetscInt J,PetscInt K,GaussPointCoefficients ** G)87 PetscErrorCode CellPropertiesGetCell(CellProperties C, PetscInt II, PetscInt J, PetscInt K, GaussPointCoefficients **G)
88 {
89   PetscFunctionBeginUser;
90   *G = &C->gpc[(II - C->sex) + (J - C->sey) * C->mx + (K - C->sez) * C->mx * C->my];
91   PetscFunctionReturn(PETSC_SUCCESS);
92 }
93 
94 /* FEM routines */
95 /*
96  Element: Local basis function ordering
97  1-----2
98  |     |
99  |     |
100  0-----3
101  */
ShapeFunctionQ13D_Evaluate(PetscScalar _xi[],PetscScalar Ni[])102 static void ShapeFunctionQ13D_Evaluate(PetscScalar _xi[], PetscScalar Ni[])
103 {
104   PetscReal xi   = PetscRealPart(_xi[0]);
105   PetscReal eta  = PetscRealPart(_xi[1]);
106   PetscReal zeta = PetscRealPart(_xi[2]);
107 
108   Ni[0] = 0.125 * (1.0 - xi) * (1.0 - eta) * (1.0 - zeta);
109   Ni[1] = 0.125 * (1.0 - xi) * (1.0 + eta) * (1.0 - zeta);
110   Ni[2] = 0.125 * (1.0 + xi) * (1.0 + eta) * (1.0 - zeta);
111   Ni[3] = 0.125 * (1.0 + xi) * (1.0 - eta) * (1.0 - zeta);
112 
113   Ni[4] = 0.125 * (1.0 - xi) * (1.0 - eta) * (1.0 + zeta);
114   Ni[5] = 0.125 * (1.0 - xi) * (1.0 + eta) * (1.0 + zeta);
115   Ni[6] = 0.125 * (1.0 + xi) * (1.0 + eta) * (1.0 + zeta);
116   Ni[7] = 0.125 * (1.0 + xi) * (1.0 - eta) * (1.0 + zeta);
117 }
118 
ShapeFunctionQ13D_Evaluate_dxi(PetscScalar _xi[],PetscScalar GNi[][NODES_PER_EL])119 static void ShapeFunctionQ13D_Evaluate_dxi(PetscScalar _xi[], PetscScalar GNi[][NODES_PER_EL])
120 {
121   PetscReal xi   = PetscRealPart(_xi[0]);
122   PetscReal eta  = PetscRealPart(_xi[1]);
123   PetscReal zeta = PetscRealPart(_xi[2]);
124   /* xi deriv */
125   GNi[0][0] = -0.125 * (1.0 - eta) * (1.0 - zeta);
126   GNi[0][1] = -0.125 * (1.0 + eta) * (1.0 - zeta);
127   GNi[0][2] = 0.125 * (1.0 + eta) * (1.0 - zeta);
128   GNi[0][3] = 0.125 * (1.0 - eta) * (1.0 - zeta);
129 
130   GNi[0][4] = -0.125 * (1.0 - eta) * (1.0 + zeta);
131   GNi[0][5] = -0.125 * (1.0 + eta) * (1.0 + zeta);
132   GNi[0][6] = 0.125 * (1.0 + eta) * (1.0 + zeta);
133   GNi[0][7] = 0.125 * (1.0 - eta) * (1.0 + zeta);
134   /* eta deriv */
135   GNi[1][0] = -0.125 * (1.0 - xi) * (1.0 - zeta);
136   GNi[1][1] = 0.125 * (1.0 - xi) * (1.0 - zeta);
137   GNi[1][2] = 0.125 * (1.0 + xi) * (1.0 - zeta);
138   GNi[1][3] = -0.125 * (1.0 + xi) * (1.0 - zeta);
139 
140   GNi[1][4] = -0.125 * (1.0 - xi) * (1.0 + zeta);
141   GNi[1][5] = 0.125 * (1.0 - xi) * (1.0 + zeta);
142   GNi[1][6] = 0.125 * (1.0 + xi) * (1.0 + zeta);
143   GNi[1][7] = -0.125 * (1.0 + xi) * (1.0 + zeta);
144   /* zeta deriv */
145   GNi[2][0] = -0.125 * (1.0 - xi) * (1.0 - eta);
146   GNi[2][1] = -0.125 * (1.0 - xi) * (1.0 + eta);
147   GNi[2][2] = -0.125 * (1.0 + xi) * (1.0 + eta);
148   GNi[2][3] = -0.125 * (1.0 + xi) * (1.0 - eta);
149 
150   GNi[2][4] = 0.125 * (1.0 - xi) * (1.0 - eta);
151   GNi[2][5] = 0.125 * (1.0 - xi) * (1.0 + eta);
152   GNi[2][6] = 0.125 * (1.0 + xi) * (1.0 + eta);
153   GNi[2][7] = 0.125 * (1.0 + xi) * (1.0 - eta);
154 }
155 
matrix_inverse_3x3(PetscScalar A[3][3],PetscScalar B[3][3])156 static void matrix_inverse_3x3(PetscScalar A[3][3], PetscScalar B[3][3])
157 {
158   PetscScalar t4, t6, t8, t10, t12, t14, t17;
159 
160   t4  = A[2][0] * A[0][1];
161   t6  = A[2][0] * A[0][2];
162   t8  = A[1][0] * A[0][1];
163   t10 = A[1][0] * A[0][2];
164   t12 = A[0][0] * A[1][1];
165   t14 = A[0][0] * A[1][2];
166   t17 = 0.1e1 / (t4 * A[1][2] - t6 * A[1][1] - t8 * A[2][2] + t10 * A[2][1] + t12 * A[2][2] - t14 * A[2][1]);
167 
168   B[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) * t17;
169   B[0][1] = -(A[0][1] * A[2][2] - A[0][2] * A[2][1]) * t17;
170   B[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) * t17;
171   B[1][0] = -(-A[2][0] * A[1][2] + A[1][0] * A[2][2]) * t17;
172   B[1][1] = (-t6 + A[0][0] * A[2][2]) * t17;
173   B[1][2] = -(-t10 + t14) * t17;
174   B[2][0] = (-A[2][0] * A[1][1] + A[1][0] * A[2][1]) * t17;
175   B[2][1] = -(-t4 + A[0][0] * A[2][1]) * t17;
176   B[2][2] = (-t8 + t12) * t17;
177 }
178 
ShapeFunctionQ13D_Evaluate_dx(PetscScalar GNi[][NODES_PER_EL],PetscScalar GNx[][NODES_PER_EL],PetscScalar coords[],PetscScalar * det_J)179 static void ShapeFunctionQ13D_Evaluate_dx(PetscScalar GNi[][NODES_PER_EL], PetscScalar GNx[][NODES_PER_EL], PetscScalar coords[], PetscScalar *det_J)
180 {
181   PetscScalar J00, J01, J02, J10, J11, J12, J20, J21, J22;
182   PetscInt    n;
183   PetscScalar iJ[3][3], JJ[3][3];
184 
185   J00 = J01 = J02 = 0.0;
186   J10 = J11 = J12 = 0.0;
187   J20 = J21 = J22 = 0.0;
188   for (n = 0; n < NODES_PER_EL; n++) {
189     PetscScalar cx = coords[NSD * n + 0];
190     PetscScalar cy = coords[NSD * n + 1];
191     PetscScalar cz = coords[NSD * n + 2];
192 
193     /* J_ij = d(x_j) / d(xi_i) */ /* J_ij = \sum _I GNi[j][I} * x_i */
194     J00 = J00 + GNi[0][n] * cx;   /* J_xx */
195     J01 = J01 + GNi[0][n] * cy;   /* J_xy = dx/deta */
196     J02 = J02 + GNi[0][n] * cz;   /* J_xz = dx/dzeta */
197 
198     J10 = J10 + GNi[1][n] * cx; /* J_yx = dy/dxi */
199     J11 = J11 + GNi[1][n] * cy; /* J_yy */
200     J12 = J12 + GNi[1][n] * cz; /* J_yz */
201 
202     J20 = J20 + GNi[2][n] * cx; /* J_zx */
203     J21 = J21 + GNi[2][n] * cy; /* J_zy */
204     J22 = J22 + GNi[2][n] * cz; /* J_zz */
205   }
206 
207   JJ[0][0] = J00;
208   JJ[0][1] = J01;
209   JJ[0][2] = J02;
210   JJ[1][0] = J10;
211   JJ[1][1] = J11;
212   JJ[1][2] = J12;
213   JJ[2][0] = J20;
214   JJ[2][1] = J21;
215   JJ[2][2] = J22;
216 
217   matrix_inverse_3x3(JJ, iJ);
218 
219   *det_J = J00 * J11 * J22 - J00 * J12 * J21 - J10 * J01 * J22 + J10 * J02 * J21 + J20 * J01 * J12 - J20 * J02 * J11;
220 
221   for (n = 0; n < NODES_PER_EL; n++) {
222     GNx[0][n] = GNi[0][n] * iJ[0][0] + GNi[1][n] * iJ[0][1] + GNi[2][n] * iJ[0][2];
223     GNx[1][n] = GNi[0][n] * iJ[1][0] + GNi[1][n] * iJ[1][1] + GNi[2][n] * iJ[1][2];
224     GNx[2][n] = GNi[0][n] * iJ[2][0] + GNi[1][n] * iJ[2][1] + GNi[2][n] * iJ[2][2];
225   }
226 }
227 
ConstructGaussQuadrature3D(PetscInt * ngp,PetscScalar gp_xi[][NSD],PetscScalar gp_weight[])228 static void ConstructGaussQuadrature3D(PetscInt *ngp, PetscScalar gp_xi[][NSD], PetscScalar gp_weight[])
229 {
230   *ngp        = 8;
231   gp_xi[0][0] = -0.57735026919;
232   gp_xi[0][1] = -0.57735026919;
233   gp_xi[0][2] = -0.57735026919;
234   gp_xi[1][0] = -0.57735026919;
235   gp_xi[1][1] = 0.57735026919;
236   gp_xi[1][2] = -0.57735026919;
237   gp_xi[2][0] = 0.57735026919;
238   gp_xi[2][1] = 0.57735026919;
239   gp_xi[2][2] = -0.57735026919;
240   gp_xi[3][0] = 0.57735026919;
241   gp_xi[3][1] = -0.57735026919;
242   gp_xi[3][2] = -0.57735026919;
243 
244   gp_xi[4][0] = -0.57735026919;
245   gp_xi[4][1] = -0.57735026919;
246   gp_xi[4][2] = 0.57735026919;
247   gp_xi[5][0] = -0.57735026919;
248   gp_xi[5][1] = 0.57735026919;
249   gp_xi[5][2] = 0.57735026919;
250   gp_xi[6][0] = 0.57735026919;
251   gp_xi[6][1] = 0.57735026919;
252   gp_xi[6][2] = 0.57735026919;
253   gp_xi[7][0] = 0.57735026919;
254   gp_xi[7][1] = -0.57735026919;
255   gp_xi[7][2] = 0.57735026919;
256 
257   gp_weight[0] = 1.0;
258   gp_weight[1] = 1.0;
259   gp_weight[2] = 1.0;
260   gp_weight[3] = 1.0;
261 
262   gp_weight[4] = 1.0;
263   gp_weight[5] = 1.0;
264   gp_weight[6] = 1.0;
265   gp_weight[7] = 1.0;
266 }
267 
268 /*
269  i,j are the element indices
270  The unknown is a vector quantity.
271  The s[].c is used to indicate the degree of freedom.
272  */
DMDAGetElementEqnums3D_up(MatStencil s_u[],MatStencil s_p[],PetscInt i,PetscInt j,PetscInt k)273 static PetscErrorCode DMDAGetElementEqnums3D_up(MatStencil s_u[], MatStencil s_p[], PetscInt i, PetscInt j, PetscInt k)
274 {
275   PetscInt n;
276 
277   PetscFunctionBeginUser;
278   /* velocity */
279   n = 0;
280   /* node 0 */
281   s_u[n].i = i;
282   s_u[n].j = j;
283   s_u[n].k = k;
284   s_u[n].c = 0;
285   n++; /* Vx0 */
286   s_u[n].i = i;
287   s_u[n].j = j;
288   s_u[n].k = k;
289   s_u[n].c = 1;
290   n++; /* Vy0 */
291   s_u[n].i = i;
292   s_u[n].j = j;
293   s_u[n].k = k;
294   s_u[n].c = 2;
295   n++; /* Vz0 */
296 
297   s_u[n].i = i;
298   s_u[n].j = j + 1;
299   s_u[n].k = k;
300   s_u[n].c = 0;
301   n++;
302   s_u[n].i = i;
303   s_u[n].j = j + 1;
304   s_u[n].k = k;
305   s_u[n].c = 1;
306   n++;
307   s_u[n].i = i;
308   s_u[n].j = j + 1;
309   s_u[n].k = k;
310   s_u[n].c = 2;
311   n++;
312 
313   s_u[n].i = i + 1;
314   s_u[n].j = j + 1;
315   s_u[n].k = k;
316   s_u[n].c = 0;
317   n++;
318   s_u[n].i = i + 1;
319   s_u[n].j = j + 1;
320   s_u[n].k = k;
321   s_u[n].c = 1;
322   n++;
323   s_u[n].i = i + 1;
324   s_u[n].j = j + 1;
325   s_u[n].k = k;
326   s_u[n].c = 2;
327   n++;
328 
329   s_u[n].i = i + 1;
330   s_u[n].j = j;
331   s_u[n].k = k;
332   s_u[n].c = 0;
333   n++;
334   s_u[n].i = i + 1;
335   s_u[n].j = j;
336   s_u[n].k = k;
337   s_u[n].c = 1;
338   n++;
339   s_u[n].i = i + 1;
340   s_u[n].j = j;
341   s_u[n].k = k;
342   s_u[n].c = 2;
343   n++;
344 
345   /* */
346   s_u[n].i = i;
347   s_u[n].j = j;
348   s_u[n].k = k + 1;
349   s_u[n].c = 0;
350   n++; /* Vx4 */
351   s_u[n].i = i;
352   s_u[n].j = j;
353   s_u[n].k = k + 1;
354   s_u[n].c = 1;
355   n++; /* Vy4 */
356   s_u[n].i = i;
357   s_u[n].j = j;
358   s_u[n].k = k + 1;
359   s_u[n].c = 2;
360   n++; /* Vz4 */
361 
362   s_u[n].i = i;
363   s_u[n].j = j + 1;
364   s_u[n].k = k + 1;
365   s_u[n].c = 0;
366   n++;
367   s_u[n].i = i;
368   s_u[n].j = j + 1;
369   s_u[n].k = k + 1;
370   s_u[n].c = 1;
371   n++;
372   s_u[n].i = i;
373   s_u[n].j = j + 1;
374   s_u[n].k = k + 1;
375   s_u[n].c = 2;
376   n++;
377 
378   s_u[n].i = i + 1;
379   s_u[n].j = j + 1;
380   s_u[n].k = k + 1;
381   s_u[n].c = 0;
382   n++;
383   s_u[n].i = i + 1;
384   s_u[n].j = j + 1;
385   s_u[n].k = k + 1;
386   s_u[n].c = 1;
387   n++;
388   s_u[n].i = i + 1;
389   s_u[n].j = j + 1;
390   s_u[n].k = k + 1;
391   s_u[n].c = 2;
392   n++;
393 
394   s_u[n].i = i + 1;
395   s_u[n].j = j;
396   s_u[n].k = k + 1;
397   s_u[n].c = 0;
398   n++;
399   s_u[n].i = i + 1;
400   s_u[n].j = j;
401   s_u[n].k = k + 1;
402   s_u[n].c = 1;
403   n++;
404   s_u[n].i = i + 1;
405   s_u[n].j = j;
406   s_u[n].k = k + 1;
407   s_u[n].c = 2;
408   n++;
409 
410   /* pressure */
411   n = 0;
412 
413   s_p[n].i = i;
414   s_p[n].j = j;
415   s_p[n].k = k;
416   s_p[n].c = 3;
417   n++; /* P0 */
418   s_p[n].i = i;
419   s_p[n].j = j + 1;
420   s_p[n].k = k;
421   s_p[n].c = 3;
422   n++;
423   s_p[n].i = i + 1;
424   s_p[n].j = j + 1;
425   s_p[n].k = k;
426   s_p[n].c = 3;
427   n++;
428   s_p[n].i = i + 1;
429   s_p[n].j = j;
430   s_p[n].k = k;
431   s_p[n].c = 3;
432   n++;
433 
434   s_p[n].i = i;
435   s_p[n].j = j;
436   s_p[n].k = k + 1;
437   s_p[n].c = 3;
438   n++; /* P0 */
439   s_p[n].i = i;
440   s_p[n].j = j + 1;
441   s_p[n].k = k + 1;
442   s_p[n].c = 3;
443   n++;
444   s_p[n].i = i + 1;
445   s_p[n].j = j + 1;
446   s_p[n].k = k + 1;
447   s_p[n].c = 3;
448   n++;
449   s_p[n].i = i + 1;
450   s_p[n].j = j;
451   s_p[n].k = k + 1;
452   s_p[n].c = 3;
453   n++;
454   PetscFunctionReturn(PETSC_SUCCESS);
455 }
456 
GetElementCoords3D(DMDACoor3d *** coords,PetscInt i,PetscInt j,PetscInt k,PetscScalar el_coord[])457 static PetscErrorCode GetElementCoords3D(DMDACoor3d ***coords, PetscInt i, PetscInt j, PetscInt k, PetscScalar el_coord[])
458 {
459   PetscFunctionBeginUser;
460   /* get coords for the element */
461   el_coord[0] = coords[k][j][i].x;
462   el_coord[1] = coords[k][j][i].y;
463   el_coord[2] = coords[k][j][i].z;
464 
465   el_coord[3] = coords[k][j + 1][i].x;
466   el_coord[4] = coords[k][j + 1][i].y;
467   el_coord[5] = coords[k][j + 1][i].z;
468 
469   el_coord[6] = coords[k][j + 1][i + 1].x;
470   el_coord[7] = coords[k][j + 1][i + 1].y;
471   el_coord[8] = coords[k][j + 1][i + 1].z;
472 
473   el_coord[9]  = coords[k][j][i + 1].x;
474   el_coord[10] = coords[k][j][i + 1].y;
475   el_coord[11] = coords[k][j][i + 1].z;
476 
477   el_coord[12] = coords[k + 1][j][i].x;
478   el_coord[13] = coords[k + 1][j][i].y;
479   el_coord[14] = coords[k + 1][j][i].z;
480 
481   el_coord[15] = coords[k + 1][j + 1][i].x;
482   el_coord[16] = coords[k + 1][j + 1][i].y;
483   el_coord[17] = coords[k + 1][j + 1][i].z;
484 
485   el_coord[18] = coords[k + 1][j + 1][i + 1].x;
486   el_coord[19] = coords[k + 1][j + 1][i + 1].y;
487   el_coord[20] = coords[k + 1][j + 1][i + 1].z;
488 
489   el_coord[21] = coords[k + 1][j][i + 1].x;
490   el_coord[22] = coords[k + 1][j][i + 1].y;
491   el_coord[23] = coords[k + 1][j][i + 1].z;
492   PetscFunctionReturn(PETSC_SUCCESS);
493 }
494 
StokesDAGetNodalFields3D(StokesDOF *** field,PetscInt i,PetscInt j,PetscInt k,StokesDOF nodal_fields[])495 static PetscErrorCode StokesDAGetNodalFields3D(StokesDOF ***field, PetscInt i, PetscInt j, PetscInt k, StokesDOF nodal_fields[])
496 {
497   PetscFunctionBeginUser;
498   /* get the nodal fields for u */
499   nodal_fields[0].u_dof = field[k][j][i].u_dof;
500   nodal_fields[0].v_dof = field[k][j][i].v_dof;
501   nodal_fields[0].w_dof = field[k][j][i].w_dof;
502 
503   nodal_fields[1].u_dof = field[k][j + 1][i].u_dof;
504   nodal_fields[1].v_dof = field[k][j + 1][i].v_dof;
505   nodal_fields[1].w_dof = field[k][j + 1][i].w_dof;
506 
507   nodal_fields[2].u_dof = field[k][j + 1][i + 1].u_dof;
508   nodal_fields[2].v_dof = field[k][j + 1][i + 1].v_dof;
509   nodal_fields[2].w_dof = field[k][j + 1][i + 1].w_dof;
510 
511   nodal_fields[3].u_dof = field[k][j][i + 1].u_dof;
512   nodal_fields[3].v_dof = field[k][j][i + 1].v_dof;
513   nodal_fields[3].w_dof = field[k][j][i + 1].w_dof;
514 
515   nodal_fields[4].u_dof = field[k + 1][j][i].u_dof;
516   nodal_fields[4].v_dof = field[k + 1][j][i].v_dof;
517   nodal_fields[4].w_dof = field[k + 1][j][i].w_dof;
518 
519   nodal_fields[5].u_dof = field[k + 1][j + 1][i].u_dof;
520   nodal_fields[5].v_dof = field[k + 1][j + 1][i].v_dof;
521   nodal_fields[5].w_dof = field[k + 1][j + 1][i].w_dof;
522 
523   nodal_fields[6].u_dof = field[k + 1][j + 1][i + 1].u_dof;
524   nodal_fields[6].v_dof = field[k + 1][j + 1][i + 1].v_dof;
525   nodal_fields[6].w_dof = field[k + 1][j + 1][i + 1].w_dof;
526 
527   nodal_fields[7].u_dof = field[k + 1][j][i + 1].u_dof;
528   nodal_fields[7].v_dof = field[k + 1][j][i + 1].v_dof;
529   nodal_fields[7].w_dof = field[k + 1][j][i + 1].w_dof;
530 
531   /* get the nodal fields for p */
532   nodal_fields[0].p_dof = field[k][j][i].p_dof;
533   nodal_fields[1].p_dof = field[k][j + 1][i].p_dof;
534   nodal_fields[2].p_dof = field[k][j + 1][i + 1].p_dof;
535   nodal_fields[3].p_dof = field[k][j][i + 1].p_dof;
536 
537   nodal_fields[4].p_dof = field[k + 1][j][i].p_dof;
538   nodal_fields[5].p_dof = field[k + 1][j + 1][i].p_dof;
539   nodal_fields[6].p_dof = field[k + 1][j + 1][i + 1].p_dof;
540   nodal_fields[7].p_dof = field[k + 1][j][i + 1].p_dof;
541   PetscFunctionReturn(PETSC_SUCCESS);
542 }
543 
ASS_MAP_wIwDI_uJuDJ(PetscInt wi,PetscInt wd,PetscInt w_NPE,PetscInt w_dof,PetscInt ui,PetscInt ud,PetscInt u_NPE,PetscInt u_dof)544 static PetscInt ASS_MAP_wIwDI_uJuDJ(PetscInt wi, PetscInt wd, PetscInt w_NPE, PetscInt w_dof, PetscInt ui, PetscInt ud, PetscInt u_NPE, PetscInt u_dof)
545 {
546   PetscInt              ij;
547   PETSC_UNUSED PetscInt r, c, nr, nc;
548 
549   nr = w_NPE * w_dof;
550   nc = u_NPE * u_dof;
551 
552   r = w_dof * wi + wd;
553   c = u_dof * ui + ud;
554 
555   ij = r * nc + c;
556 
557   return ij;
558 }
559 
DMDASetValuesLocalStencil3D_ADD_VALUES(StokesDOF *** fields_F,MatStencil u_eqn[],MatStencil p_eqn[],PetscScalar Fe_u[],PetscScalar Fe_p[])560 static PetscErrorCode DMDASetValuesLocalStencil3D_ADD_VALUES(StokesDOF ***fields_F, MatStencil u_eqn[], MatStencil p_eqn[], PetscScalar Fe_u[], PetscScalar Fe_p[])
561 {
562   PetscInt n, II, J, K;
563 
564   PetscFunctionBeginUser;
565   for (n = 0; n < NODES_PER_EL; n++) {
566     II = u_eqn[NSD * n].i;
567     J  = u_eqn[NSD * n].j;
568     K  = u_eqn[NSD * n].k;
569 
570     fields_F[K][J][II].u_dof = fields_F[K][J][II].u_dof + Fe_u[NSD * n];
571 
572     II = u_eqn[NSD * n + 1].i;
573     J  = u_eqn[NSD * n + 1].j;
574     K  = u_eqn[NSD * n + 1].k;
575 
576     fields_F[K][J][II].v_dof = fields_F[K][J][II].v_dof + Fe_u[NSD * n + 1];
577 
578     II                       = u_eqn[NSD * n + 2].i;
579     J                        = u_eqn[NSD * n + 2].j;
580     K                        = u_eqn[NSD * n + 2].k;
581     fields_F[K][J][II].w_dof = fields_F[K][J][II].w_dof + Fe_u[NSD * n + 2];
582 
583     II = p_eqn[n].i;
584     J  = p_eqn[n].j;
585     K  = p_eqn[n].k;
586 
587     fields_F[K][J][II].p_dof = fields_F[K][J][II].p_dof + Fe_p[n];
588   }
589   PetscFunctionReturn(PETSC_SUCCESS);
590 }
591 
FormStressOperatorQ13D(PetscScalar Ke[],PetscScalar coords[],PetscScalar eta[])592 static void FormStressOperatorQ13D(PetscScalar Ke[], PetscScalar coords[], PetscScalar eta[])
593 {
594   PetscInt       ngp;
595   PetscScalar    gp_xi[GAUSS_POINTS][NSD];
596   PetscScalar    gp_weight[GAUSS_POINTS];
597   PetscInt       p, i, j, k;
598   PetscScalar    GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
599   PetscScalar    J_p, tildeD[6];
600   PetscScalar    B[6][U_DOFS * NODES_PER_EL];
601   const PetscInt nvdof = U_DOFS * NODES_PER_EL;
602 
603   /* define quadrature rule */
604   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
605 
606   /* evaluate integral */
607   for (p = 0; p < ngp; p++) {
608     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
609     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
610 
611     for (i = 0; i < NODES_PER_EL; i++) {
612       PetscScalar d_dx_i = GNx_p[0][i];
613       PetscScalar d_dy_i = GNx_p[1][i];
614       PetscScalar d_dz_i = GNx_p[2][i];
615 
616       B[0][3 * i]     = d_dx_i;
617       B[0][3 * i + 1] = 0.0;
618       B[0][3 * i + 2] = 0.0;
619       B[1][3 * i]     = 0.0;
620       B[1][3 * i + 1] = d_dy_i;
621       B[1][3 * i + 2] = 0.0;
622       B[2][3 * i]     = 0.0;
623       B[2][3 * i + 1] = 0.0;
624       B[2][3 * i + 2] = d_dz_i;
625 
626       B[3][3 * i]     = d_dy_i;
627       B[3][3 * i + 1] = d_dx_i;
628       B[3][3 * i + 2] = 0.0; /* e_xy */
629       B[4][3 * i]     = d_dz_i;
630       B[4][3 * i + 1] = 0.0;
631       B[4][3 * i + 2] = d_dx_i; /* e_xz */
632       B[5][3 * i]     = 0.0;
633       B[5][3 * i + 1] = d_dz_i;
634       B[5][3 * i + 2] = d_dy_i; /* e_yz */
635     }
636 
637     tildeD[0] = 2.0 * gp_weight[p] * J_p * eta[p];
638     tildeD[1] = 2.0 * gp_weight[p] * J_p * eta[p];
639     tildeD[2] = 2.0 * gp_weight[p] * J_p * eta[p];
640 
641     tildeD[3] = gp_weight[p] * J_p * eta[p];
642     tildeD[4] = gp_weight[p] * J_p * eta[p];
643     tildeD[5] = gp_weight[p] * J_p * eta[p];
644 
645     /* form Bt tildeD B */
646     /*
647      Ke_ij = Bt_ik . D_kl . B_lj
648      = B_ki . D_kl . B_lj
649      = B_ki . D_kk . B_kj
650      */
651     for (i = 0; i < nvdof; i++) {
652       for (j = i; j < nvdof; j++) {
653         for (k = 0; k < 6; k++) Ke[i * nvdof + j] += B[k][i] * tildeD[k] * B[k][j];
654       }
655     }
656   }
657   /* fill lower triangular part */
658 #if defined(ASSEMBLE_LOWER_TRIANGULAR)
659   for (i = 0; i < nvdof; i++) {
660     for (j = i; j < nvdof; j++) Ke[j * nvdof + i] = Ke[i * nvdof + j];
661   }
662 #endif
663 }
664 
FormGradientOperatorQ13D(PetscScalar Ke[],PetscScalar coords[])665 static void FormGradientOperatorQ13D(PetscScalar Ke[], PetscScalar coords[])
666 {
667   PetscInt    ngp;
668   PetscScalar gp_xi[GAUSS_POINTS][NSD];
669   PetscScalar gp_weight[GAUSS_POINTS];
670   PetscInt    p, i, j, di;
671   PetscScalar Ni_p[NODES_PER_EL];
672   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
673   PetscScalar J_p, fac;
674 
675   /* define quadrature rule */
676   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
677 
678   /* evaluate integral */
679   for (p = 0; p < ngp; p++) {
680     ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
681     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
682     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
683     fac = gp_weight[p] * J_p;
684 
685     for (i = 0; i < NODES_PER_EL; i++) {     /* u nodes */
686       for (di = 0; di < NSD; di++) {         /* u dofs */
687         for (j = 0; j < NODES_PER_EL; j++) { /* p nodes, p dofs = 1 (ie no loop) */
688           PetscInt IJ;
689           IJ = ASS_MAP_wIwDI_uJuDJ(i, di, NODES_PER_EL, 3, j, 0, NODES_PER_EL, 1);
690 
691           Ke[IJ] = Ke[IJ] - GNx_p[di][i] * Ni_p[j] * fac;
692         }
693       }
694     }
695   }
696 }
697 
FormDivergenceOperatorQ13D(PetscScalar De[],PetscScalar coords[])698 static void FormDivergenceOperatorQ13D(PetscScalar De[], PetscScalar coords[])
699 {
700   PetscScalar Ge[U_DOFS * NODES_PER_EL * P_DOFS * NODES_PER_EL];
701   PetscInt    i, j;
702   PetscInt    nr_g, nc_g;
703 
704   PetscCallAbort(PETSC_COMM_SELF, PetscMemzero(Ge, sizeof(Ge)));
705   FormGradientOperatorQ13D(Ge, coords);
706 
707   nr_g = U_DOFS * NODES_PER_EL;
708   nc_g = P_DOFS * NODES_PER_EL;
709 
710   for (i = 0; i < nr_g; i++) {
711     for (j = 0; j < nc_g; j++) De[nr_g * j + i] = Ge[nc_g * i + j];
712   }
713 }
714 
FormStabilisationOperatorQ13D(PetscScalar Ke[],PetscScalar coords[],PetscScalar eta[])715 static void FormStabilisationOperatorQ13D(PetscScalar Ke[], PetscScalar coords[], PetscScalar eta[])
716 {
717   PetscInt    ngp;
718   PetscScalar gp_xi[GAUSS_POINTS][NSD];
719   PetscScalar gp_weight[GAUSS_POINTS];
720   PetscInt    p, i, j;
721   PetscScalar Ni_p[NODES_PER_EL];
722   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
723   PetscScalar J_p, fac, eta_avg;
724 
725   /* define quadrature rule */
726   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
727 
728   /* evaluate integral */
729   for (p = 0; p < ngp; p++) {
730     ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
731     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
732     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
733     fac = gp_weight[p] * J_p;
734     /*
735      for (i = 0; i < NODES_PER_EL; i++) {
736      for (j = i; j < NODES_PER_EL; j++) {
737      Ke[NODES_PER_EL*i+j] -= fac*(Ni_p[i]*Ni_p[j]-0.015625);
738      }
739      }
740      */
741 
742     for (i = 0; i < NODES_PER_EL; i++) {
743       for (j = 0; j < NODES_PER_EL; j++) Ke[NODES_PER_EL * i + j] -= fac * (Ni_p[i] * Ni_p[j] - 0.015625);
744     }
745   }
746 
747   /* scale */
748   eta_avg = 0.0;
749   for (p = 0; p < ngp; p++) eta_avg += eta[p];
750   eta_avg = (1.0 / ((PetscScalar)ngp)) * eta_avg;
751   fac     = 1.0 / eta_avg;
752 
753   /*
754    for (i = 0; i < NODES_PER_EL; i++) {
755    for (j = i; j < NODES_PER_EL; j++) {
756    Ke[NODES_PER_EL*i+j] = fac*Ke[NODES_PER_EL*i+j];
757    #if defined(ASSEMBLE_LOWER_TRIANGULAR)
758    Ke[NODES_PER_EL*j+i] = Ke[NODES_PER_EL*i+j];
759    #endif
760    }
761    }
762    */
763 
764   for (i = 0; i < NODES_PER_EL; i++) {
765     for (j = 0; j < NODES_PER_EL; j++) Ke[NODES_PER_EL * i + j] = fac * Ke[NODES_PER_EL * i + j];
766   }
767 }
768 
FormScaledMassMatrixOperatorQ13D(PetscScalar Ke[],PetscScalar coords[],PetscScalar eta[])769 static void FormScaledMassMatrixOperatorQ13D(PetscScalar Ke[], PetscScalar coords[], PetscScalar eta[])
770 {
771   PetscInt    ngp;
772   PetscScalar gp_xi[GAUSS_POINTS][NSD];
773   PetscScalar gp_weight[GAUSS_POINTS];
774   PetscInt    p, i, j;
775   PetscScalar Ni_p[NODES_PER_EL];
776   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
777   PetscScalar J_p, fac, eta_avg;
778 
779   /* define quadrature rule */
780   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
781 
782   /* evaluate integral */
783   for (p = 0; p < ngp; p++) {
784     ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
785     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
786     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
787     fac = gp_weight[p] * J_p;
788 
789     /*
790      for (i = 0; i < NODES_PER_EL; i++) {
791      for (j = i; j < NODES_PER_EL; j++) {
792      Ke[NODES_PER_EL*i+j] = Ke[NODES_PER_EL*i+j]-fac*Ni_p[i]*Ni_p[j];
793      }
794      }
795      */
796 
797     for (i = 0; i < NODES_PER_EL; i++) {
798       for (j = 0; j < NODES_PER_EL; j++) Ke[NODES_PER_EL * i + j] = Ke[NODES_PER_EL * i + j] - fac * Ni_p[i] * Ni_p[j];
799     }
800   }
801 
802   /* scale */
803   eta_avg = 0.0;
804   for (p = 0; p < ngp; p++) eta_avg += eta[p];
805   eta_avg = (1.0 / ((PetscScalar)ngp)) * eta_avg;
806   fac     = 1.0 / eta_avg;
807   /*
808    for (i = 0; i < NODES_PER_EL; i++) {
809    for (j = i; j < NODES_PER_EL; j++) {
810    Ke[NODES_PER_EL*i+j] = fac*Ke[NODES_PER_EL*i+j];
811    #if defined(ASSEMBLE_LOWER_TRIANGULAR)
812    Ke[NODES_PER_EL*j+i] = Ke[NODES_PER_EL*i+j];
813    #endif
814    }
815    }
816    */
817 
818   for (i = 0; i < NODES_PER_EL; i++) {
819     for (j = 0; j < NODES_PER_EL; j++) Ke[NODES_PER_EL * i + j] = fac * Ke[NODES_PER_EL * i + j];
820   }
821 }
822 
FormMomentumRhsQ13D(PetscScalar Fe[],PetscScalar coords[],PetscScalar fx[],PetscScalar fy[],PetscScalar fz[])823 static void FormMomentumRhsQ13D(PetscScalar Fe[], PetscScalar coords[], PetscScalar fx[], PetscScalar fy[], PetscScalar fz[])
824 {
825   PetscInt    ngp;
826   PetscScalar gp_xi[GAUSS_POINTS][NSD];
827   PetscScalar gp_weight[GAUSS_POINTS];
828   PetscInt    p, i;
829   PetscScalar Ni_p[NODES_PER_EL];
830   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
831   PetscScalar J_p, fac;
832 
833   /* define quadrature rule */
834   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
835 
836   /* evaluate integral */
837   for (p = 0; p < ngp; p++) {
838     ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
839     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
840     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
841     fac = gp_weight[p] * J_p;
842 
843     for (i = 0; i < NODES_PER_EL; i++) {
844       Fe[NSD * i] -= fac * Ni_p[i] * fx[p];
845       Fe[NSD * i + 1] -= fac * Ni_p[i] * fy[p];
846       Fe[NSD * i + 2] -= fac * Ni_p[i] * fz[p];
847     }
848   }
849 }
850 
FormContinuityRhsQ13D(PetscScalar Fe[],PetscScalar coords[],PetscScalar hc[])851 static void FormContinuityRhsQ13D(PetscScalar Fe[], PetscScalar coords[], PetscScalar hc[])
852 {
853   PetscInt    ngp;
854   PetscScalar gp_xi[GAUSS_POINTS][NSD];
855   PetscScalar gp_weight[GAUSS_POINTS];
856   PetscInt    p, i;
857   PetscScalar Ni_p[NODES_PER_EL];
858   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
859   PetscScalar J_p, fac;
860 
861   /* define quadrature rule */
862   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
863 
864   /* evaluate integral */
865   for (p = 0; p < ngp; p++) {
866     ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
867     ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
868     ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, coords, &J_p);
869     fac = gp_weight[p] * J_p;
870 
871     for (i = 0; i < NODES_PER_EL; i++) Fe[i] -= fac * Ni_p[i] * hc[p];
872   }
873 }
874 
875 #define _ZERO_ROWCOL_i(A, i) \
876   do { \
877     PetscInt    KK; \
878     PetscScalar tmp = A[24 * (i) + (i)]; \
879     for (KK = 0; KK < 24; KK++) A[24 * (i) + KK] = 0.0; \
880     for (KK = 0; KK < 24; KK++) A[24 * KK + (i)] = 0.0; \
881     A[24 * (i) + (i)] = tmp; \
882   } while (0)
883 
884 #define _ZERO_ROW_i(A, i) \
885   do { \
886     PetscInt KK; \
887     for (KK = 0; KK < 8; KK++) A[8 * (i) + KK] = 0.0; \
888   } while (0)
889 
890 #define _ZERO_COL_i(A, i) \
891   do { \
892     PetscInt KK; \
893     for (KK = 0; KK < 8; KK++) A[24 * KK + (i)] = 0.0; \
894   } while (0)
895 
AssembleA_Stokes(Mat A,DM stokes_da,CellProperties cell_properties)896 static PetscErrorCode AssembleA_Stokes(Mat A, DM stokes_da, CellProperties cell_properties)
897 {
898   DM                      cda;
899   Vec                     coords;
900   DMDACoor3d           ***_coords;
901   MatStencil              u_eqn[NODES_PER_EL * U_DOFS];
902   MatStencil              p_eqn[NODES_PER_EL * P_DOFS];
903   PetscInt                sex, sey, sez, mx, my, mz;
904   PetscInt                ei, ej, ek;
905   PetscScalar             Ae[NODES_PER_EL * U_DOFS * NODES_PER_EL * U_DOFS];
906   PetscScalar             Ge[NODES_PER_EL * U_DOFS * NODES_PER_EL * P_DOFS];
907   PetscScalar             De[NODES_PER_EL * P_DOFS * NODES_PER_EL * U_DOFS];
908   PetscScalar             Ce[NODES_PER_EL * P_DOFS * NODES_PER_EL * P_DOFS];
909   PetscScalar             el_coords[NODES_PER_EL * NSD];
910   GaussPointCoefficients *props;
911   PetscScalar            *prop_eta;
912   PetscInt                n, M, N, P;
913 
914   PetscFunctionBeginUser;
915   PetscCall(DMDAGetInfo(stokes_da, 0, &M, &N, &P, 0, 0, 0, 0, 0, 0, 0, 0, 0));
916   /* setup for coords */
917   PetscCall(DMGetCoordinateDM(stokes_da, &cda));
918   PetscCall(DMGetCoordinatesLocal(stokes_da, &coords));
919   PetscCall(DMDAVecGetArray(cda, coords, &_coords));
920   PetscCall(DMDAGetElementsCorners(stokes_da, &sex, &sey, &sez));
921   PetscCall(DMDAGetElementsSizes(stokes_da, &mx, &my, &mz));
922   for (ek = sez; ek < sez + mz; ek++) {
923     for (ej = sey; ej < sey + my; ej++) {
924       for (ei = sex; ei < sex + mx; ei++) {
925         /* get coords for the element */
926         PetscCall(GetElementCoords3D(_coords, ei, ej, ek, el_coords));
927         /* get cell properties */
928         PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &props));
929         /* get coefficients for the element */
930         prop_eta = props->eta;
931 
932         /* initialise element stiffness matrix */
933         PetscCall(PetscMemzero(Ae, sizeof(Ae)));
934         PetscCall(PetscMemzero(Ge, sizeof(Ge)));
935         PetscCall(PetscMemzero(De, sizeof(De)));
936         PetscCall(PetscMemzero(Ce, sizeof(Ce)));
937 
938         /* form element stiffness matrix */
939         FormStressOperatorQ13D(Ae, el_coords, prop_eta);
940         FormGradientOperatorQ13D(Ge, el_coords);
941         /*#if defined(ASSEMBLE_LOWER_TRIANGULAR)*/
942         FormDivergenceOperatorQ13D(De, el_coords);
943         /*#endif*/
944         FormStabilisationOperatorQ13D(Ce, el_coords, prop_eta);
945 
946         /* insert element matrix into global matrix */
947         PetscCall(DMDAGetElementEqnums3D_up(u_eqn, p_eqn, ei, ej, ek));
948 
949         for (n = 0; n < NODES_PER_EL; n++) {
950           if ((u_eqn[3 * n].i == 0) || (u_eqn[3 * n].i == M - 1)) {
951             _ZERO_ROWCOL_i(Ae, 3 * n);
952             _ZERO_ROW_i(Ge, 3 * n);
953             _ZERO_COL_i(De, 3 * n);
954           }
955 
956           if ((u_eqn[3 * n + 1].j == 0) || (u_eqn[3 * n + 1].j == N - 1)) {
957             _ZERO_ROWCOL_i(Ae, 3 * n + 1);
958             _ZERO_ROW_i(Ge, 3 * n + 1);
959             _ZERO_COL_i(De, 3 * n + 1);
960           }
961 
962           if ((u_eqn[3 * n + 2].k == 0) || (u_eqn[3 * n + 2].k == P - 1)) {
963             _ZERO_ROWCOL_i(Ae, 3 * n + 2);
964             _ZERO_ROW_i(Ge, 3 * n + 2);
965             _ZERO_COL_i(De, 3 * n + 2);
966           }
967         }
968         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * U_DOFS, u_eqn, NODES_PER_EL * U_DOFS, u_eqn, Ae, ADD_VALUES));
969         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * U_DOFS, u_eqn, NODES_PER_EL * P_DOFS, p_eqn, Ge, ADD_VALUES));
970         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * P_DOFS, p_eqn, NODES_PER_EL * U_DOFS, u_eqn, De, ADD_VALUES));
971         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * P_DOFS, p_eqn, NODES_PER_EL * P_DOFS, p_eqn, Ce, ADD_VALUES));
972       }
973     }
974   }
975   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
976   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
977 
978   PetscCall(DMDAVecRestoreArray(cda, coords, &_coords));
979   PetscFunctionReturn(PETSC_SUCCESS);
980 }
981 
AssembleA_PCStokes(Mat A,DM stokes_da,CellProperties cell_properties)982 static PetscErrorCode AssembleA_PCStokes(Mat A, DM stokes_da, CellProperties cell_properties)
983 {
984   DM                      cda;
985   Vec                     coords;
986   DMDACoor3d           ***_coords;
987   MatStencil              u_eqn[NODES_PER_EL * U_DOFS];
988   MatStencil              p_eqn[NODES_PER_EL * P_DOFS];
989   PetscInt                sex, sey, sez, mx, my, mz;
990   PetscInt                ei, ej, ek;
991   PetscScalar             Ae[NODES_PER_EL * U_DOFS * NODES_PER_EL * U_DOFS];
992   PetscScalar             Ge[NODES_PER_EL * U_DOFS * NODES_PER_EL * P_DOFS];
993   PetscScalar             De[NODES_PER_EL * P_DOFS * NODES_PER_EL * U_DOFS];
994   PetscScalar             Ce[NODES_PER_EL * P_DOFS * NODES_PER_EL * P_DOFS];
995   PetscScalar             el_coords[NODES_PER_EL * NSD];
996   GaussPointCoefficients *props;
997   PetscScalar            *prop_eta;
998   PetscInt                n, M, N, P;
999 
1000   PetscFunctionBeginUser;
1001   PetscCall(DMDAGetInfo(stokes_da, 0, &M, &N, &P, 0, 0, 0, 0, 0, 0, 0, 0, 0));
1002   /* setup for coords */
1003   PetscCall(DMGetCoordinateDM(stokes_da, &cda));
1004   PetscCall(DMGetCoordinatesLocal(stokes_da, &coords));
1005   PetscCall(DMDAVecGetArray(cda, coords, &_coords));
1006 
1007   PetscCall(DMDAGetElementsCorners(stokes_da, &sex, &sey, &sez));
1008   PetscCall(DMDAGetElementsSizes(stokes_da, &mx, &my, &mz));
1009   for (ek = sez; ek < sez + mz; ek++) {
1010     for (ej = sey; ej < sey + my; ej++) {
1011       for (ei = sex; ei < sex + mx; ei++) {
1012         /* get coords for the element */
1013         PetscCall(GetElementCoords3D(_coords, ei, ej, ek, el_coords));
1014         /* get cell properties */
1015         PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &props));
1016         /* get coefficients for the element */
1017         prop_eta = props->eta;
1018 
1019         /* initialise element stiffness matrix */
1020         PetscCall(PetscMemzero(Ae, sizeof(Ae)));
1021         PetscCall(PetscMemzero(Ge, sizeof(Ge)));
1022         PetscCall(PetscMemzero(De, sizeof(De)));
1023         PetscCall(PetscMemzero(Ce, sizeof(Ce)));
1024 
1025         /* form element stiffness matrix */
1026         FormStressOperatorQ13D(Ae, el_coords, prop_eta);
1027         FormGradientOperatorQ13D(Ge, el_coords);
1028         /* FormDivergenceOperatorQ13D(De,el_coords); */
1029         FormScaledMassMatrixOperatorQ13D(Ce, el_coords, prop_eta);
1030 
1031         /* insert element matrix into global matrix */
1032         PetscCall(DMDAGetElementEqnums3D_up(u_eqn, p_eqn, ei, ej, ek));
1033 
1034         for (n = 0; n < NODES_PER_EL; n++) {
1035           if ((u_eqn[3 * n].i == 0) || (u_eqn[3 * n].i == M - 1)) {
1036             _ZERO_ROWCOL_i(Ae, 3 * n);
1037             _ZERO_ROW_i(Ge, 3 * n);
1038             _ZERO_COL_i(De, 3 * n);
1039           }
1040 
1041           if ((u_eqn[3 * n + 1].j == 0) || (u_eqn[3 * n + 1].j == N - 1)) {
1042             _ZERO_ROWCOL_i(Ae, 3 * n + 1);
1043             _ZERO_ROW_i(Ge, 3 * n + 1);
1044             _ZERO_COL_i(De, 3 * n + 1);
1045           }
1046 
1047           if ((u_eqn[3 * n + 2].k == 0) || (u_eqn[3 * n + 2].k == P - 1)) {
1048             _ZERO_ROWCOL_i(Ae, 3 * n + 2);
1049             _ZERO_ROW_i(Ge, 3 * n + 2);
1050             _ZERO_COL_i(De, 3 * n + 2);
1051           }
1052         }
1053         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * U_DOFS, u_eqn, NODES_PER_EL * U_DOFS, u_eqn, Ae, ADD_VALUES));
1054         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * U_DOFS, u_eqn, NODES_PER_EL * P_DOFS, p_eqn, Ge, ADD_VALUES));
1055         /*PetscCall(MatSetValuesStencil(A,NODES_PER_EL*P_DOFS,p_eqn,NODES_PER_EL*U_DOFS,u_eqn,De,ADD_VALUES));*/
1056         PetscCall(MatSetValuesStencil(A, NODES_PER_EL * P_DOFS, p_eqn, NODES_PER_EL * P_DOFS, p_eqn, Ce, ADD_VALUES));
1057       }
1058     }
1059   }
1060   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1061   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1062 
1063   PetscCall(DMDAVecRestoreArray(cda, coords, &_coords));
1064   PetscFunctionReturn(PETSC_SUCCESS);
1065 }
1066 
AssembleF_Stokes(Vec F,DM stokes_da,CellProperties cell_properties)1067 static PetscErrorCode AssembleF_Stokes(Vec F, DM stokes_da, CellProperties cell_properties)
1068 {
1069   DM                      cda;
1070   Vec                     coords;
1071   DMDACoor3d           ***_coords;
1072   MatStencil              u_eqn[NODES_PER_EL * U_DOFS];
1073   MatStencil              p_eqn[NODES_PER_EL * P_DOFS];
1074   PetscInt                sex, sey, sez, mx, my, mz;
1075   PetscInt                ei, ej, ek;
1076   PetscScalar             Fe[NODES_PER_EL * U_DOFS];
1077   PetscScalar             He[NODES_PER_EL * P_DOFS];
1078   PetscScalar             el_coords[NODES_PER_EL * NSD];
1079   GaussPointCoefficients *props;
1080   PetscScalar            *prop_fx, *prop_fy, *prop_fz, *prop_hc;
1081   Vec                     local_F;
1082   StokesDOF            ***ff;
1083   PetscInt                n, M, N, P;
1084 
1085   PetscFunctionBeginUser;
1086   PetscCall(DMDAGetInfo(stokes_da, 0, &M, &N, &P, 0, 0, 0, 0, 0, 0, 0, 0, 0));
1087   /* setup for coords */
1088   PetscCall(DMGetCoordinateDM(stokes_da, &cda));
1089   PetscCall(DMGetCoordinatesLocal(stokes_da, &coords));
1090   PetscCall(DMDAVecGetArray(cda, coords, &_coords));
1091 
1092   /* get access to the vector */
1093   PetscCall(DMGetLocalVector(stokes_da, &local_F));
1094   PetscCall(VecZeroEntries(local_F));
1095   PetscCall(DMDAVecGetArray(stokes_da, local_F, &ff));
1096   PetscCall(DMDAGetElementsCorners(stokes_da, &sex, &sey, &sez));
1097   PetscCall(DMDAGetElementsSizes(stokes_da, &mx, &my, &mz));
1098   for (ek = sez; ek < sez + mz; ek++) {
1099     for (ej = sey; ej < sey + my; ej++) {
1100       for (ei = sex; ei < sex + mx; ei++) {
1101         /* get coords for the element */
1102         PetscCall(GetElementCoords3D(_coords, ei, ej, ek, el_coords));
1103         /* get cell properties */
1104         PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &props));
1105         /* get coefficients for the element */
1106         prop_fx = props->fx;
1107         prop_fy = props->fy;
1108         prop_fz = props->fz;
1109         prop_hc = props->hc;
1110 
1111         /* initialise element stiffness matrix */
1112         PetscCall(PetscMemzero(Fe, sizeof(Fe)));
1113         PetscCall(PetscMemzero(He, sizeof(He)));
1114 
1115         /* form element stiffness matrix */
1116         FormMomentumRhsQ13D(Fe, el_coords, prop_fx, prop_fy, prop_fz);
1117         FormContinuityRhsQ13D(He, el_coords, prop_hc);
1118 
1119         /* insert element matrix into global matrix */
1120         PetscCall(DMDAGetElementEqnums3D_up(u_eqn, p_eqn, ei, ej, ek));
1121 
1122         for (n = 0; n < NODES_PER_EL; n++) {
1123           if ((u_eqn[3 * n].i == 0) || (u_eqn[3 * n].i == M - 1)) Fe[3 * n] = 0.0;
1124 
1125           if ((u_eqn[3 * n + 1].j == 0) || (u_eqn[3 * n + 1].j == N - 1)) Fe[3 * n + 1] = 0.0;
1126 
1127           if ((u_eqn[3 * n + 2].k == 0) || (u_eqn[3 * n + 2].k == P - 1)) Fe[3 * n + 2] = 0.0;
1128         }
1129 
1130         PetscCall(DMDASetValuesLocalStencil3D_ADD_VALUES(ff, u_eqn, p_eqn, Fe, He));
1131       }
1132     }
1133   }
1134   PetscCall(DMDAVecRestoreArray(stokes_da, local_F, &ff));
1135   PetscCall(DMLocalToGlobalBegin(stokes_da, local_F, ADD_VALUES, F));
1136   PetscCall(DMLocalToGlobalEnd(stokes_da, local_F, ADD_VALUES, F));
1137   PetscCall(DMRestoreLocalVector(stokes_da, &local_F));
1138 
1139   PetscCall(DMDAVecRestoreArray(cda, coords, &_coords));
1140   PetscFunctionReturn(PETSC_SUCCESS);
1141 }
1142 
evaluate_MS_FrankKamentski_constants(PetscReal * theta,PetscReal * MX,PetscReal * MY,PetscReal * MZ)1143 static void evaluate_MS_FrankKamentski_constants(PetscReal *theta, PetscReal *MX, PetscReal *MY, PetscReal *MZ)
1144 {
1145   *theta = 0.0;
1146   *MX    = 2.0 * PETSC_PI;
1147   *MY    = 2.0 * PETSC_PI;
1148   *MZ    = 2.0 * PETSC_PI;
1149 }
evaluate_MS_FrankKamentski(PetscReal pos[],PetscReal v[],PetscReal * p,PetscReal * eta,PetscReal Fm[],PetscReal * Fc)1150 static void evaluate_MS_FrankKamentski(PetscReal pos[], PetscReal v[], PetscReal *p, PetscReal *eta, PetscReal Fm[], PetscReal *Fc)
1151 {
1152   PetscReal x, y, z;
1153   PetscReal theta, MX, MY, MZ;
1154 
1155   evaluate_MS_FrankKamentski_constants(&theta, &MX, &MY, &MZ);
1156   x = pos[0];
1157   y = pos[1];
1158   z = pos[2];
1159   if (v) {
1160     /*
1161      v[0] = PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x);
1162      v[1] = z*cos(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y);
1163      v[2] = -(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscSinReal(2.0*PETSC_PI*z);
1164      */
1165     /*
1166      v[0] = PetscSinReal(PETSC_PI*x);
1167      v[1] = PetscSinReal(PETSC_PI*y);
1168      v[2] = PetscSinReal(PETSC_PI*z);
1169      */
1170     v[0] = PetscPowRealInt(z, 3) * PetscExpReal(y) * PetscSinReal(PETSC_PI * x);
1171     v[1] = z * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y);
1172     v[2] = PetscPowRealInt(z, 2) * (PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) / 2 - PETSC_PI * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) / 2) - PETSC_PI * PetscPowRealInt(z, 4) * PetscCosReal(PETSC_PI * x) * PetscExpReal(y) / 4;
1173   }
1174   if (p) *p = PetscPowRealInt(x, 2) + PetscPowRealInt(y, 2) + PetscPowRealInt(z, 2);
1175   if (eta) {
1176     /* eta = PetscExpReal(-theta*(1.0 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)));*/
1177     *eta = 1.0;
1178   }
1179   if (Fm) {
1180     /*
1181      Fm[0] = -2*x - 2.0*PetscPowRealInt(PETSC_PI,2)*PetscPowRealInt(z,3)*PetscExpReal(y)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(PETSC_PI*x) - 0.2*MZ*theta*(-1.5*PetscPowRealInt(x,2)*PetscSinReal(2.0*PETSC_PI*z) + 1.5*PetscPowRealInt(z,2)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x))*PetscCosReal(MX*x)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MY*y)*PetscSinReal(MZ*z) - 0.2*PETSC_PI*MX*theta*PetscPowRealInt(z,3)*PetscCosReal(PETSC_PI*x)*PetscCosReal(MZ*z)*PetscExpReal(y)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MX*x)*PetscSinReal(MY*y) + 2.0*(3.0*z*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) - 3.0*PETSC_PI*PetscPowRealInt(x,2)*PetscCosReal(2.0*PETSC_PI*z))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*(0.5*PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) + PETSC_PI*z*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y)*PetscSinReal(2.0*PETSC_PI*x) - 1.0*z*PetscPowRealInt(PETSC_PI,2)*PetscCosReal(PETSC_PI*y)*PetscExpReal(-y)*PetscSinReal(2.0*PETSC_PI*x))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*theta*(1 + 0.1*MY*PetscCosReal(MX*x)*PetscCosReal(MY*y)*PetscCosReal(MZ*z))*(0.5*PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) - 1.0*PETSC_PI*z*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y)*PetscSinReal(2.0*PETSC_PI*x))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) ;
1182      Fm[1] = -2*y - 0.2*MX*theta*(0.5*PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) - 1.0*PETSC_PI*z*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y)*PetscSinReal(2.0*PETSC_PI*x))*PetscCosReal(MZ*z)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MX*x)*PetscSinReal(MY*y) - 0.2*MZ*theta*(-1.5*PetscPowRealInt(y,2)*PetscSinReal(2.0*PETSC_PI*z) + 0.5*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y))*PetscCosReal(MX*x)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MY*y)*PetscSinReal(MZ*z) + 2.0*(-2.0*z*PetscPowRealInt(PETSC_PI,2)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + 0.5*PETSC_PI*PetscPowRealInt(z,3)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*(z*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) - z*PetscPowRealInt(PETSC_PI,2)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) - 2*PETSC_PI*z*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*theta*(1 + 0.1*MY*PetscCosReal(MX*x)*PetscCosReal(MY*y)*PetscCosReal(MZ*z))*(-z*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + PETSC_PI*z*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) - 6.0*PETSC_PI*PetscPowRealInt(y,2)*PetscCosReal(2.0*PETSC_PI*z)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)));
1183      Fm[2] = -2*z + 8.0*PetscPowRealInt(PETSC_PI,2)*(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(2.0*PETSC_PI*z) - 0.2*MX*theta*(-1.5*PetscPowRealInt(x,2)*PetscSinReal(2.0*PETSC_PI*z) + 1.5*PetscPowRealInt(z,2)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x))*PetscCosReal(MZ*z)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MX*x)*PetscSinReal(MY*y) + 0.4*PETSC_PI*MZ*theta*(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscCosReal(MX*x)*PetscCosReal(2.0*PETSC_PI*z)*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))*PetscSinReal(MY*y)*PetscSinReal(MZ*z) + 2.0*(-3.0*x*PetscSinReal(2.0*PETSC_PI*z) + 1.5*PETSC_PI*PetscPowRealInt(z,2)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*(-3.0*y*PetscSinReal(2.0*PETSC_PI*z) - 0.5*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + 0.5*PETSC_PI*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y))) + 2.0*theta*(1 + 0.1*MY*PetscCosReal(MX*x)*PetscCosReal(MY*y)*PetscCosReal(MZ*z))*(-1.5*PetscPowRealInt(y,2)*PetscSinReal(2.0*PETSC_PI*z) + 0.5*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y))*PetscExpReal(-theta*(1 - y - 0.1*PetscCosReal(MX*x)*PetscCosReal(MZ*z)*PetscSinReal(MY*y)))  ;
1184      */
1185     /*
1186      Fm[0]=-2*x - 2.0*PetscPowRealInt(PETSC_PI,2)*PetscSinReal(PETSC_PI*x);
1187      Fm[1]=-2*y - 2.0*PetscPowRealInt(PETSC_PI,2)*PetscSinReal(PETSC_PI*y);
1188      Fm[2]=-2*z - 2.0*PetscPowRealInt(PETSC_PI,2)*PetscSinReal(PETSC_PI*z);
1189      */
1190     /*
1191      Fm[0] = -2*x + PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) + 6.0*z*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) - 6.0*PETSC_PI*PetscPowRealInt(x,2)*PetscCosReal(2.0*PETSC_PI*z) - 2.0*PetscPowRealInt(PETSC_PI,2)*PetscPowRealInt(z,3)*PetscExpReal(y)*PetscSinReal(PETSC_PI*x) + 2.0*PETSC_PI*z*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y)*PetscSinReal(2.0*PETSC_PI*x) - 2.0*z*PetscPowRealInt(PETSC_PI,2)*PetscCosReal(PETSC_PI*y)*PetscExpReal(-y)*PetscSinReal(2.0*PETSC_PI*x) ;
1192      Fm[1] = -2*y - 6.0*PETSC_PI*PetscPowRealInt(y,2)*PetscCosReal(2.0*PETSC_PI*z) + 2.0*z*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) - 6.0*z*PetscPowRealInt(PETSC_PI,2)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + PETSC_PI*PetscPowRealInt(z,3)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y) - 4.0*PETSC_PI*z*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y);
1193      Fm[2] = -2*z - 6.0*x*PetscSinReal(2.0*PETSC_PI*z) - 6.0*y*PetscSinReal(2.0*PETSC_PI*z) - PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + 8.0*PetscPowRealInt(PETSC_PI,2)*(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscSinReal(2.0*PETSC_PI*z) + 3.0*PETSC_PI*PetscPowRealInt(z,2)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y) + PETSC_PI*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y) ;
1194      */
1195     Fm[0] = -2 * x + 2 * z * (PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(PETSC_PI * y) * PetscExpReal(-y) * PetscSinReal(2.0 * PETSC_PI * x) - 1.0 * PETSC_PI * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) * PetscSinReal(2.0 * PETSC_PI * x)) + PetscPowRealInt(z, 3) * PetscExpReal(y) * PetscSinReal(PETSC_PI * x) + 6.0 * z * PetscExpReal(y) * PetscSinReal(PETSC_PI * x) - 1.0 * PetscPowRealInt(PETSC_PI, 2) * PetscPowRealInt(z, 3) * PetscExpReal(y) * PetscSinReal(PETSC_PI * x) + 2.0 * PETSC_PI * z * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) * PetscSinReal(2.0 * PETSC_PI * x) - 2.0 * z * PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(PETSC_PI * y) * PetscExpReal(-y) * PetscSinReal(2.0 * PETSC_PI * x);
1196     Fm[1] = -2 * y + 2 * z * (-PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) / 2 + PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) / 2 + PETSC_PI * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y)) + 2.0 * z * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) - 6.0 * z * PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) - 4.0 * PETSC_PI * z * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y);
1197     Fm[2] = -2 * z + PetscPowRealInt(z, 2) * (-2.0 * PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) + 2.0 * PetscPowRealInt(PETSC_PI, 3) * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y)) + PetscPowRealInt(z, 2) * (PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) / 2 - 3 * PetscPowRealInt(PETSC_PI, 2) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) / 2 + PetscPowRealInt(PETSC_PI, 3) * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) / 2 - 3 * PETSC_PI * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) / 2) + 1.0 * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y) * PetscSinReal(PETSC_PI * y) + 0.25 * PetscPowRealInt(PETSC_PI, 3) * PetscPowRealInt(z, 4) * PetscCosReal(PETSC_PI * x) * PetscExpReal(y) - 0.25 * PETSC_PI * PetscPowRealInt(z, 4) * PetscCosReal(PETSC_PI * x) * PetscExpReal(y) - 3.0 * PETSC_PI * PetscPowRealInt(z, 2) * PetscCosReal(PETSC_PI * x) * PetscExpReal(y) - 1.0 * PETSC_PI * PetscCosReal(PETSC_PI * y) * PetscCosReal(2.0 * PETSC_PI * x) * PetscExpReal(-y);
1198   }
1199   if (Fc) {
1200     /* Fc = -2.0*PETSC_PI*(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscCosReal(2.0*PETSC_PI*z) - z*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + PETSC_PI*PetscPowRealInt(z,3)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y) + PETSC_PI*z*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y) ;*/
1201     /* Fc = PETSC_PI*PetscCosReal(PETSC_PI*x) + PETSC_PI*PetscCosReal(PETSC_PI*y) + PETSC_PI*PetscCosReal(PETSC_PI*z);*/
1202     /* Fc = -2.0*PETSC_PI*(PetscPowRealInt(x,3) + PetscPowRealInt(y,3))*PetscCosReal(2.0*PETSC_PI*z) - z*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y)*PetscSinReal(PETSC_PI*y) + PETSC_PI*PetscPowRealInt(z,3)*PetscCosReal(PETSC_PI*x)*PetscExpReal(y) + PETSC_PI*z*PetscCosReal(PETSC_PI*y)*PetscCosReal(2.0*PETSC_PI*x)*PetscExpReal(-y);*/
1203     *Fc = 0.0;
1204   }
1205 }
1206 
DMDACreateManufacturedSolution(PetscInt mx,PetscInt my,PetscInt mz,DM * _da,Vec * _X)1207 static PetscErrorCode DMDACreateManufacturedSolution(PetscInt mx, PetscInt my, PetscInt mz, DM *_da, Vec *_X)
1208 {
1209   DM            da, cda;
1210   Vec           X;
1211   StokesDOF  ***_stokes;
1212   Vec           coords;
1213   DMDACoor3d ***_coords;
1214   PetscInt      si, sj, sk, ei, ej, ek, i, j, k;
1215 
1216   PetscFunctionBeginUser;
1217   PetscCall(DMDACreate3d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, mx + 1, my + 1, mz + 1, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE, 4, 1, NULL, NULL, NULL, &da));
1218   PetscCall(DMSetFromOptions(da));
1219   PetscCall(DMSetUp(da));
1220   PetscCall(DMDASetFieldName(da, 0, "anlytic_Vx"));
1221   PetscCall(DMDASetFieldName(da, 1, "anlytic_Vy"));
1222   PetscCall(DMDASetFieldName(da, 2, "anlytic_Vz"));
1223   PetscCall(DMDASetFieldName(da, 3, "analytic_P"));
1224 
1225   PetscCall(DMDASetUniformCoordinates(da, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
1226 
1227   PetscCall(DMGetCoordinatesLocal(da, &coords));
1228   PetscCall(DMGetCoordinateDM(da, &cda));
1229   PetscCall(DMDAVecGetArray(cda, coords, &_coords));
1230 
1231   PetscCall(DMCreateGlobalVector(da, &X));
1232   PetscCall(DMDAVecGetArray(da, X, &_stokes));
1233 
1234   PetscCall(DMDAGetCorners(da, &si, &sj, &sk, &ei, &ej, &ek));
1235   for (k = sk; k < sk + ek; k++) {
1236     for (j = sj; j < sj + ej; j++) {
1237       for (i = si; i < si + ei; i++) {
1238         PetscReal pos[NSD], pressure, vel[NSD];
1239 
1240         pos[0] = PetscRealPart(_coords[k][j][i].x);
1241         pos[1] = PetscRealPart(_coords[k][j][i].y);
1242         pos[2] = PetscRealPart(_coords[k][j][i].z);
1243 
1244         evaluate_MS_FrankKamentski(pos, vel, &pressure, NULL, NULL, NULL);
1245 
1246         _stokes[k][j][i].u_dof = vel[0];
1247         _stokes[k][j][i].v_dof = vel[1];
1248         _stokes[k][j][i].w_dof = vel[2];
1249         _stokes[k][j][i].p_dof = pressure;
1250       }
1251     }
1252   }
1253   PetscCall(DMDAVecRestoreArray(da, X, &_stokes));
1254   PetscCall(DMDAVecRestoreArray(cda, coords, &_coords));
1255 
1256   *_da = da;
1257   *_X  = X;
1258   PetscFunctionReturn(PETSC_SUCCESS);
1259 }
1260 
DMDAIntegrateErrors3D(DM stokes_da,Vec X,Vec X_analytic)1261 static PetscErrorCode DMDAIntegrateErrors3D(DM stokes_da, Vec X, Vec X_analytic)
1262 {
1263   DM            cda;
1264   Vec           coords, X_analytic_local, X_local;
1265   DMDACoor3d ***_coords;
1266   PetscInt      sex, sey, sez, mx, my, mz;
1267   PetscInt      ei, ej, ek;
1268   PetscScalar   el_coords[NODES_PER_EL * NSD];
1269   StokesDOF  ***stokes_analytic, ***stokes;
1270   StokesDOF     stokes_analytic_e[NODES_PER_EL], stokes_e[NODES_PER_EL];
1271 
1272   PetscScalar GNi_p[NSD][NODES_PER_EL], GNx_p[NSD][NODES_PER_EL];
1273   PetscScalar Ni_p[NODES_PER_EL];
1274   PetscInt    ngp;
1275   PetscScalar gp_xi[GAUSS_POINTS][NSD];
1276   PetscScalar gp_weight[GAUSS_POINTS];
1277   PetscInt    p, i;
1278   PetscScalar J_p, fac;
1279   PetscScalar h, p_e_L2, u_e_L2, u_e_H1, p_L2, u_L2, u_H1, tp_L2, tu_L2, tu_H1;
1280   PetscScalar tint_p_ms, tint_p, int_p_ms, int_p;
1281   PetscInt    M;
1282   PetscReal   xymin[NSD], xymax[NSD];
1283 
1284   PetscFunctionBeginUser;
1285   /* define quadrature rule */
1286   ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
1287 
1288   /* setup for coords */
1289   PetscCall(DMGetCoordinateDM(stokes_da, &cda));
1290   PetscCall(DMGetCoordinatesLocal(stokes_da, &coords));
1291   PetscCall(DMDAVecGetArray(cda, coords, &_coords));
1292 
1293   /* setup for analytic */
1294   PetscCall(DMCreateLocalVector(stokes_da, &X_analytic_local));
1295   PetscCall(DMGlobalToLocalBegin(stokes_da, X_analytic, INSERT_VALUES, X_analytic_local));
1296   PetscCall(DMGlobalToLocalEnd(stokes_da, X_analytic, INSERT_VALUES, X_analytic_local));
1297   PetscCall(DMDAVecGetArray(stokes_da, X_analytic_local, &stokes_analytic));
1298 
1299   /* setup for solution */
1300   PetscCall(DMCreateLocalVector(stokes_da, &X_local));
1301   PetscCall(DMGlobalToLocalBegin(stokes_da, X, INSERT_VALUES, X_local));
1302   PetscCall(DMGlobalToLocalEnd(stokes_da, X, INSERT_VALUES, X_local));
1303   PetscCall(DMDAVecGetArray(stokes_da, X_local, &stokes));
1304 
1305   PetscCall(DMDAGetInfo(stokes_da, 0, &M, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
1306   PetscCall(DMGetBoundingBox(stokes_da, xymin, xymax));
1307 
1308   h = (xymax[0] - xymin[0]) / ((PetscReal)(M - 1));
1309 
1310   tp_L2 = tu_L2 = tu_H1 = 0.0;
1311   tint_p_ms = tint_p = 0.0;
1312 
1313   PetscCall(DMDAGetElementsCorners(stokes_da, &sex, &sey, &sez));
1314   PetscCall(DMDAGetElementsSizes(stokes_da, &mx, &my, &mz));
1315   for (ek = sez; ek < sez + mz; ek++) {
1316     for (ej = sey; ej < sey + my; ej++) {
1317       for (ei = sex; ei < sex + mx; ei++) {
1318         /* get coords for the element */
1319         PetscCall(GetElementCoords3D(_coords, ei, ej, ek, el_coords));
1320         PetscCall(StokesDAGetNodalFields3D(stokes, ei, ej, ek, stokes_e));
1321         PetscCall(StokesDAGetNodalFields3D(stokes_analytic, ei, ej, ek, stokes_analytic_e));
1322 
1323         /* evaluate integral */
1324         for (p = 0; p < ngp; p++) {
1325           ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
1326           ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
1327           ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, el_coords, &J_p);
1328           fac = gp_weight[p] * J_p;
1329 
1330           for (i = 0; i < NODES_PER_EL; i++) {
1331             tint_p_ms = tint_p_ms + fac * Ni_p[i] * stokes_analytic_e[i].p_dof;
1332             tint_p    = tint_p + fac * Ni_p[i] * stokes_e[i].p_dof;
1333           }
1334         }
1335       }
1336     }
1337   }
1338   PetscCallMPI(MPIU_Allreduce(&tint_p_ms, &int_p_ms, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
1339   PetscCallMPI(MPIU_Allreduce(&tint_p, &int_p, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
1340 
1341   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\\int P dv %1.4e (h)  %1.4e (ms)\n", (double)PetscRealPart(int_p), (double)PetscRealPart(int_p_ms)));
1342 
1343   /* remove mine and add manufacture one */
1344   PetscCall(DMDAVecRestoreArray(stokes_da, X_analytic_local, &stokes_analytic));
1345   PetscCall(DMDAVecRestoreArray(stokes_da, X_local, &stokes));
1346 
1347   {
1348     PetscInt     k, L, dof;
1349     PetscScalar *fields;
1350     PetscCall(DMDAGetInfo(stokes_da, 0, 0, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
1351 
1352     PetscCall(VecGetLocalSize(X_local, &L));
1353     PetscCall(VecGetArray(X_local, &fields));
1354     for (k = 0; k < L / dof; k++) fields[dof * k + 3] = fields[dof * k + 3] - int_p + int_p_ms;
1355     PetscCall(VecRestoreArray(X_local, &fields));
1356 
1357     PetscCall(VecGetLocalSize(X, &L));
1358     PetscCall(VecGetArray(X, &fields));
1359     for (k = 0; k < L / dof; k++) fields[dof * k + 3] = fields[dof * k + 3] - int_p + int_p_ms;
1360     PetscCall(VecRestoreArray(X, &fields));
1361   }
1362 
1363   PetscCall(DMDAVecGetArray(stokes_da, X_local, &stokes));
1364   PetscCall(DMDAVecGetArray(stokes_da, X_analytic_local, &stokes_analytic));
1365 
1366   for (ek = sez; ek < sez + mz; ek++) {
1367     for (ej = sey; ej < sey + my; ej++) {
1368       for (ei = sex; ei < sex + mx; ei++) {
1369         /* get coords for the element */
1370         PetscCall(GetElementCoords3D(_coords, ei, ej, ek, el_coords));
1371         PetscCall(StokesDAGetNodalFields3D(stokes, ei, ej, ek, stokes_e));
1372         PetscCall(StokesDAGetNodalFields3D(stokes_analytic, ei, ej, ek, stokes_analytic_e));
1373 
1374         /* evaluate integral */
1375         p_e_L2 = 0.0;
1376         u_e_L2 = 0.0;
1377         u_e_H1 = 0.0;
1378         for (p = 0; p < ngp; p++) {
1379           ShapeFunctionQ13D_Evaluate(gp_xi[p], Ni_p);
1380           ShapeFunctionQ13D_Evaluate_dxi(gp_xi[p], GNi_p);
1381           ShapeFunctionQ13D_Evaluate_dx(GNi_p, GNx_p, el_coords, &J_p);
1382           fac = gp_weight[p] * J_p;
1383 
1384           for (i = 0; i < NODES_PER_EL; i++) {
1385             PetscScalar u_error, v_error, w_error;
1386 
1387             p_e_L2 = p_e_L2 + fac * Ni_p[i] * (stokes_e[i].p_dof - stokes_analytic_e[i].p_dof) * (stokes_e[i].p_dof - stokes_analytic_e[i].p_dof);
1388 
1389             u_error = stokes_e[i].u_dof - stokes_analytic_e[i].u_dof;
1390             v_error = stokes_e[i].v_dof - stokes_analytic_e[i].v_dof;
1391             w_error = stokes_e[i].w_dof - stokes_analytic_e[i].w_dof;
1392             u_e_L2 += fac * Ni_p[i] * (u_error * u_error + v_error * v_error + w_error * w_error);
1393 
1394             u_e_H1 = u_e_H1 + fac * (GNx_p[0][i] * u_error * GNx_p[0][i] * u_error                                                                                                   /* du/dx */
1395                                      + GNx_p[1][i] * u_error * GNx_p[1][i] * u_error + GNx_p[2][i] * u_error * GNx_p[2][i] * u_error + GNx_p[0][i] * v_error * GNx_p[0][i] * v_error /* dv/dx */
1396                                      + GNx_p[1][i] * v_error * GNx_p[1][i] * v_error + GNx_p[2][i] * v_error * GNx_p[2][i] * v_error + GNx_p[0][i] * w_error * GNx_p[0][i] * w_error /* dw/dx */
1397                                      + GNx_p[1][i] * w_error * GNx_p[1][i] * w_error + GNx_p[2][i] * w_error * GNx_p[2][i] * w_error);
1398           }
1399         }
1400 
1401         tp_L2 += p_e_L2;
1402         tu_L2 += u_e_L2;
1403         tu_H1 += u_e_H1;
1404       }
1405     }
1406   }
1407   PetscCallMPI(MPIU_Allreduce(&tp_L2, &p_L2, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
1408   PetscCallMPI(MPIU_Allreduce(&tu_L2, &u_L2, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
1409   PetscCallMPI(MPIU_Allreduce(&tu_H1, &u_H1, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
1410   p_L2 = PetscSqrtScalar(p_L2);
1411   u_L2 = PetscSqrtScalar(u_L2);
1412   u_H1 = PetscSqrtScalar(u_H1);
1413 
1414   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%1.4e   %1.4e   %1.4e   %1.4e \n", (double)PetscRealPart(h), (double)PetscRealPart(p_L2), (double)PetscRealPart(u_L2), (double)PetscRealPart(u_H1)));
1415 
1416   PetscCall(DMDAVecRestoreArray(cda, coords, &_coords));
1417 
1418   PetscCall(DMDAVecRestoreArray(stokes_da, X_analytic_local, &stokes_analytic));
1419   PetscCall(VecDestroy(&X_analytic_local));
1420   PetscCall(DMDAVecRestoreArray(stokes_da, X_local, &stokes));
1421   PetscCall(VecDestroy(&X_local));
1422   PetscFunctionReturn(PETSC_SUCCESS);
1423 }
1424 
DAView_3DVTK_StructuredGrid_appended(DM da,Vec FIELD,const char file_prefix[])1425 PetscErrorCode DAView_3DVTK_StructuredGrid_appended(DM da, Vec FIELD, const char file_prefix[])
1426 {
1427   char         vtk_filename[PETSC_MAX_PATH_LEN];
1428   PetscMPIInt  rank;
1429   MPI_Comm     comm;
1430   FILE        *vtk_fp     = NULL;
1431   const char  *byte_order = PetscBinaryBigEndian() ? "BigEndian" : "LittleEndian";
1432   PetscInt     si, sj, sk, nx, ny, nz, i;
1433   PetscInt     f, n_fields, N;
1434   DM           cda;
1435   Vec          coords;
1436   Vec          l_FIELD;
1437   PetscScalar *_L_FIELD;
1438   PetscInt     memory_offset;
1439   PetscScalar *buffer;
1440 
1441   PetscFunctionBeginUser;
1442   /* create file name */
1443   PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
1444   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1445   PetscCall(PetscSNPrintf(vtk_filename, sizeof(vtk_filename), "subdomain-%s-p%1.4d.vts", file_prefix, rank));
1446 
1447   /* open file and write header */
1448   vtk_fp = fopen(vtk_filename, "w");
1449   PetscCheck(vtk_fp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Cannot open file = %s ", vtk_filename);
1450 
1451   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "<?xml version=\"1.0\"?>\n"));
1452 
1453   /* coords */
1454   PetscCall(DMDAGetGhostCorners(da, &si, &sj, &sk, &nx, &ny, &nz));
1455   N = nx * ny * nz;
1456 
1457   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "<VTKFile type=\"StructuredGrid\" version=\"0.1\" byte_order=\"%s\">\n", byte_order));
1458   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  <StructuredGrid WholeExtent=\"%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\">\n", si, si + nx - 1, sj, sj + ny - 1, sk, sk + nz - 1));
1459   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    <Piece Extent=\"%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\">\n", si, si + nx - 1, sj, sj + ny - 1, sk, sk + nz - 1));
1460 
1461   memory_offset = 0;
1462 
1463   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      <CellData></CellData>\n"));
1464 
1465   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      <Points>\n"));
1466 
1467   /* copy coordinates */
1468   PetscCall(DMGetCoordinateDM(da, &cda));
1469   PetscCall(DMGetCoordinatesLocal(da, &coords));
1470   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "        <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n", memory_offset));
1471   memory_offset = memory_offset + sizeof(PetscInt) + sizeof(PetscScalar) * N * 3;
1472 
1473   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      </Points>\n"));
1474 
1475   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      <PointData Scalars=\" "));
1476   PetscCall(DMDAGetInfo(da, 0, 0, 0, 0, 0, 0, 0, &n_fields, 0, 0, 0, 0, 0));
1477   for (f = 0; f < n_fields; f++) {
1478     const char *field_name;
1479     PetscCall(DMDAGetFieldName(da, f, &field_name));
1480     PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "%s ", field_name));
1481   }
1482   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "\">\n"));
1483 
1484   for (f = 0; f < n_fields; f++) {
1485     const char *field_name;
1486 
1487     PetscCall(DMDAGetFieldName(da, f, &field_name));
1488     PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "        <DataArray type=\"Float64\" Name=\"%s\" format=\"appended\" offset=\"%" PetscInt_FMT "\"/>\n", field_name, memory_offset));
1489     memory_offset = memory_offset + sizeof(PetscInt) + sizeof(PetscScalar) * N;
1490   }
1491 
1492   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      </PointData>\n"));
1493   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    </Piece>\n"));
1494   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  </StructuredGrid>\n"));
1495 
1496   PetscCall(PetscMalloc1(N, &buffer));
1497   PetscCall(DMGetLocalVector(da, &l_FIELD));
1498   PetscCall(DMGlobalToLocalBegin(da, FIELD, INSERT_VALUES, l_FIELD));
1499   PetscCall(DMGlobalToLocalEnd(da, FIELD, INSERT_VALUES, l_FIELD));
1500   PetscCall(VecGetArray(l_FIELD, &_L_FIELD));
1501 
1502   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  <AppendedData encoding=\"raw\">\n"));
1503   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "_"));
1504 
1505   /* write coordinates */
1506   {
1507     int          length = (int)(sizeof(PetscScalar) * N * 3);
1508     PetscScalar *allcoords;
1509 
1510     fwrite(&length, sizeof(int), 1, vtk_fp);
1511     PetscCall(VecGetArray(coords, &allcoords));
1512     fwrite(allcoords, sizeof(PetscScalar), 3 * N, vtk_fp);
1513     PetscCall(VecRestoreArray(coords, &allcoords));
1514   }
1515   /* write fields */
1516   for (f = 0; f < n_fields; f++) {
1517     int length = (int)(sizeof(PetscScalar) * N);
1518     fwrite(&length, sizeof(int), 1, vtk_fp);
1519     /* load */
1520     for (i = 0; i < N; i++) buffer[i] = _L_FIELD[n_fields * i + f];
1521 
1522     /* write */
1523     fwrite(buffer, sizeof(PetscScalar), N, vtk_fp);
1524   }
1525   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "\n  </AppendedData>\n"));
1526 
1527   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "</VTKFile>\n"));
1528 
1529   PetscCall(PetscFree(buffer));
1530   PetscCall(VecRestoreArray(l_FIELD, &_L_FIELD));
1531   PetscCall(DMRestoreLocalVector(da, &l_FIELD));
1532 
1533   if (vtk_fp) {
1534     fclose(vtk_fp);
1535     vtk_fp = NULL;
1536   }
1537   PetscFunctionReturn(PETSC_SUCCESS);
1538 }
1539 
DAViewVTK_write_PieceExtend(FILE * vtk_fp,PetscInt indent_level,DM da,const char local_file_prefix[])1540 PetscErrorCode DAViewVTK_write_PieceExtend(FILE *vtk_fp, PetscInt indent_level, DM da, const char local_file_prefix[])
1541 {
1542   PetscMPIInt     size, rank;
1543   MPI_Comm        comm;
1544   const PetscInt *lx, *ly, *lz;
1545   PetscInt        M, N, P, pM, pN, pP, sum, *olx, *oly, *olz;
1546   PetscInt       *osx, *osy, *osz, *oex, *oey, *oez;
1547   PetscInt        i, j, k, II, stencil;
1548 
1549   PetscFunctionBeginUser;
1550   /* create file name */
1551   PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
1552   PetscCallMPI(MPI_Comm_size(comm, &size));
1553   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1554 
1555   PetscCall(DMDAGetInfo(da, 0, &M, &N, &P, &pM, &pN, &pP, 0, &stencil, 0, 0, 0, 0));
1556   PetscCall(DMDAGetOwnershipRanges(da, &lx, &ly, &lz));
1557 
1558   /* generate start,end list */
1559   PetscCall(PetscMalloc1(pM + 1, &olx));
1560   PetscCall(PetscMalloc1(pN + 1, &oly));
1561   PetscCall(PetscMalloc1(pP + 1, &olz));
1562   sum = 0;
1563   for (i = 0; i < pM; i++) {
1564     olx[i] = sum;
1565     sum    = sum + lx[i];
1566   }
1567   olx[pM] = sum;
1568   sum     = 0;
1569   for (i = 0; i < pN; i++) {
1570     oly[i] = sum;
1571     sum    = sum + ly[i];
1572   }
1573   oly[pN] = sum;
1574   sum     = 0;
1575   for (i = 0; i < pP; i++) {
1576     olz[i] = sum;
1577     sum    = sum + lz[i];
1578   }
1579   olz[pP] = sum;
1580 
1581   PetscCall(PetscMalloc1(pM, &osx));
1582   PetscCall(PetscMalloc1(pN, &osy));
1583   PetscCall(PetscMalloc1(pP, &osz));
1584   PetscCall(PetscMalloc1(pM, &oex));
1585   PetscCall(PetscMalloc1(pN, &oey));
1586   PetscCall(PetscMalloc1(pP, &oez));
1587   for (i = 0; i < pM; i++) {
1588     osx[i] = olx[i] - stencil;
1589     oex[i] = olx[i] + lx[i] + stencil;
1590     if (osx[i] < 0) osx[i] = 0;
1591     if (oex[i] > M) oex[i] = M;
1592   }
1593 
1594   for (i = 0; i < pN; i++) {
1595     osy[i] = oly[i] - stencil;
1596     oey[i] = oly[i] + ly[i] + stencil;
1597     if (osy[i] < 0) osy[i] = 0;
1598     if (oey[i] > M) oey[i] = N;
1599   }
1600   for (i = 0; i < pP; i++) {
1601     osz[i] = olz[i] - stencil;
1602     oez[i] = olz[i] + lz[i] + stencil;
1603     if (osz[i] < 0) osz[i] = 0;
1604     if (oez[i] > P) oez[i] = P;
1605   }
1606 
1607   for (k = 0; k < pP; k++) {
1608     for (j = 0; j < pN; j++) {
1609       for (i = 0; i < pM; i++) {
1610         char     name[PETSC_MAX_PATH_LEN];
1611         PetscInt procid = i + j * pM + k * pM * pN; /* convert proc(i,j,k) to pid */
1612         PetscCall(PetscSNPrintf(name, sizeof(name), "subdomain-%s-p%1.4" PetscInt_FMT ".vts", local_file_prefix, procid));
1613         for (II = 0; II < indent_level; II++) PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  "));
1614 
1615         PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "<Piece Extent=\"%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\"      Source=\"%s\"/>\n", osx[i], oex[i] - 1, osy[j], oey[j] - 1, osz[k], oez[k] - 1, name));
1616       }
1617     }
1618   }
1619   PetscCall(PetscFree(olx));
1620   PetscCall(PetscFree(oly));
1621   PetscCall(PetscFree(olz));
1622   PetscCall(PetscFree(osx));
1623   PetscCall(PetscFree(osy));
1624   PetscCall(PetscFree(osz));
1625   PetscCall(PetscFree(oex));
1626   PetscCall(PetscFree(oey));
1627   PetscCall(PetscFree(oez));
1628   PetscFunctionReturn(PETSC_SUCCESS);
1629 }
1630 
DAView_3DVTK_PStructuredGrid(DM da,const char file_prefix[],const char local_file_prefix[])1631 PetscErrorCode DAView_3DVTK_PStructuredGrid(DM da, const char file_prefix[], const char local_file_prefix[])
1632 {
1633   MPI_Comm    comm;
1634   PetscMPIInt size, rank;
1635   char        vtk_filename[PETSC_MAX_PATH_LEN];
1636   FILE       *vtk_fp     = NULL;
1637   const char *byte_order = PetscBinaryBigEndian() ? "BigEndian" : "LittleEndian";
1638   PetscInt    M, N, P, si, sj, sk, nx, ny, nz;
1639   PetscInt    i, dofs;
1640 
1641   PetscFunctionBeginUser;
1642   /* only rank-0 generates this file */
1643   PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
1644   PetscCallMPI(MPI_Comm_size(comm, &size));
1645   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1646 
1647   if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS);
1648 
1649   /* create file name */
1650   PetscCall(PetscSNPrintf(vtk_filename, sizeof(vtk_filename), "%s.pvts", file_prefix));
1651   vtk_fp = fopen(vtk_filename, "w");
1652   PetscCheck(vtk_fp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Cannot open file = %s ", vtk_filename);
1653 
1654   /* (VTK) generate pvts header */
1655   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "<?xml version=\"1.0\"?>\n"));
1656 
1657   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "<VTKFile type=\"PStructuredGrid\" version=\"0.1\" byte_order=\"%s\">\n", byte_order));
1658 
1659   /* define size of the nodal mesh based on the cell DM */
1660   PetscCall(DMDAGetInfo(da, 0, &M, &N, &P, 0, 0, 0, &dofs, 0, 0, 0, 0, 0));
1661   PetscCall(DMDAGetGhostCorners(da, &si, &sj, &sk, &nx, &ny, &nz));
1662   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  <PStructuredGrid GhostLevel=\"1\" WholeExtent=\"%d %" PetscInt_FMT " %d %" PetscInt_FMT " %d %" PetscInt_FMT "\">\n", 0, M - 1, 0, N - 1, 0, P - 1)); /* note overlap = 1 for Q1 */
1663 
1664   /* DUMP THE CELL REFERENCES */
1665   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    <PCellData>\n"));
1666   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    </PCellData>\n"));
1667 
1668   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    <PPoints>\n"));
1669   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      <PDataArray type=\"Float64\" Name=\"Points\" NumberOfComponents=\"%d\"/>\n", NSD));
1670   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    </PPoints>\n"));
1671 
1672   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    <PPointData>\n"));
1673   for (i = 0; i < dofs; i++) {
1674     const char *fieldname;
1675     PetscCall(DMDAGetFieldName(da, i, &fieldname));
1676     PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "      <PDataArray type=\"Float64\" Name=\"%s\" NumberOfComponents=\"1\"/>\n", fieldname));
1677   }
1678   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "    </PPointData>\n"));
1679 
1680   /* write out the parallel information */
1681   PetscCall(DAViewVTK_write_PieceExtend(vtk_fp, 2, da, local_file_prefix));
1682 
1683   /* close the file */
1684   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "  </PStructuredGrid>\n"));
1685   PetscCall(PetscFPrintf(PETSC_COMM_SELF, vtk_fp, "</VTKFile>\n"));
1686 
1687   if (vtk_fp) {
1688     fclose(vtk_fp);
1689     vtk_fp = NULL;
1690   }
1691   PetscFunctionReturn(PETSC_SUCCESS);
1692 }
1693 
DAView3DPVTS(DM da,Vec x,const char NAME[])1694 PetscErrorCode DAView3DPVTS(DM da, Vec x, const char NAME[])
1695 {
1696   char vts_filename[PETSC_MAX_PATH_LEN];
1697   char pvts_filename[PETSC_MAX_PATH_LEN];
1698 
1699   PetscFunctionBeginUser;
1700   PetscCall(PetscSNPrintf(vts_filename, sizeof(vts_filename), "%s-mesh", NAME));
1701   PetscCall(DAView_3DVTK_StructuredGrid_appended(da, x, vts_filename));
1702 
1703   PetscCall(PetscSNPrintf(pvts_filename, sizeof(pvts_filename), "%s-mesh", NAME));
1704   PetscCall(DAView_3DVTK_PStructuredGrid(da, pvts_filename, vts_filename));
1705   PetscFunctionReturn(PETSC_SUCCESS);
1706 }
1707 
KSPMonitorStokesBlocks(KSP ksp,PetscInt n,PetscReal rnorm,void * unused)1708 PetscErrorCode KSPMonitorStokesBlocks(KSP ksp, PetscInt n, PetscReal rnorm, void *unused)
1709 {
1710   PetscReal norms[4];
1711   Vec       Br, v, w;
1712   Mat       A;
1713 
1714   PetscFunctionBeginUser;
1715   PetscCall(KSPGetOperators(ksp, &A, NULL));
1716   PetscCall(MatCreateVecs(A, &w, &v));
1717 
1718   PetscCall(KSPBuildResidual(ksp, v, w, &Br));
1719 
1720   PetscCall(VecStrideNorm(Br, 0, NORM_2, &norms[0]));
1721   PetscCall(VecStrideNorm(Br, 1, NORM_2, &norms[1]));
1722   PetscCall(VecStrideNorm(Br, 2, NORM_2, &norms[2]));
1723   PetscCall(VecStrideNorm(Br, 3, NORM_2, &norms[3]));
1724 
1725   PetscCall(VecDestroy(&v));
1726   PetscCall(VecDestroy(&w));
1727 
1728   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%3" PetscInt_FMT " KSP Component U,V,W,P residual norm [ %1.12e, %1.12e, %1.12e, %1.12e ]\n", n, (double)norms[0], (double)norms[1], (double)norms[2], (double)norms[3]));
1729   PetscFunctionReturn(PETSC_SUCCESS);
1730 }
1731 
PCMGSetupViaCoarsen(PC pc,DM da_fine)1732 static PetscErrorCode PCMGSetupViaCoarsen(PC pc, DM da_fine)
1733 {
1734   PetscInt              nlevels, k;
1735   PETSC_UNUSED PetscInt finest;
1736   DM                   *da_list, *daclist;
1737   Mat                   R;
1738 
1739   PetscFunctionBeginUser;
1740   nlevels = 1;
1741   PetscCall(PetscOptionsGetInt(NULL, NULL, "-levels", &nlevels, 0));
1742 
1743   PetscCall(PetscMalloc1(nlevels, &da_list));
1744   for (k = 0; k < nlevels; k++) da_list[k] = NULL;
1745   PetscCall(PetscMalloc1(nlevels, &daclist));
1746   for (k = 0; k < nlevels; k++) daclist[k] = NULL;
1747 
1748   /* finest grid is nlevels - 1 */
1749   finest     = nlevels - 1;
1750   daclist[0] = da_fine;
1751   PetscCall(PetscObjectReference((PetscObject)da_fine));
1752   PetscCall(DMCoarsenHierarchy(da_fine, nlevels - 1, &daclist[1]));
1753   for (k = 0; k < nlevels; k++) {
1754     da_list[k] = daclist[nlevels - 1 - k];
1755     PetscCall(DMDASetUniformCoordinates(da_list[k], 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
1756   }
1757 
1758   PetscCall(PCMGSetLevels(pc, nlevels, NULL));
1759   PetscCall(PCMGSetType(pc, PC_MG_MULTIPLICATIVE));
1760   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_PMAT));
1761 
1762   for (k = 1; k < nlevels; k++) {
1763     PetscCall(DMCreateInterpolation(da_list[k - 1], da_list[k], &R, NULL));
1764     PetscCall(PCMGSetInterpolation(pc, k, R));
1765     PetscCall(MatDestroy(&R));
1766   }
1767 
1768   /* tidy up */
1769   for (k = 0; k < nlevels; k++) PetscCall(DMDestroy(&da_list[k]));
1770   PetscCall(PetscFree(da_list));
1771   PetscCall(PetscFree(daclist));
1772   PetscFunctionReturn(PETSC_SUCCESS);
1773 }
1774 
solve_stokes_3d_coupled(PetscInt mx,PetscInt my,PetscInt mz)1775 static PetscErrorCode solve_stokes_3d_coupled(PetscInt mx, PetscInt my, PetscInt mz)
1776 {
1777   DM             da_Stokes;
1778   PetscInt       u_dof, p_dof, dof, stencil_width;
1779   Mat            A, B;
1780   DM             vel_cda;
1781   Vec            vel_coords;
1782   PetscInt       p;
1783   Vec            f, X, X1;
1784   DMDACoor3d  ***_vel_coords;
1785   PetscInt       its;
1786   KSP            ksp_S;
1787   PetscInt       model_definition = 0;
1788   PetscInt       ei, ej, ek, sex, sey, sez, Imx, Jmy, Kmz;
1789   CellProperties cell_properties;
1790   PetscBool      write_output = PETSC_FALSE, resolve = PETSC_FALSE;
1791 
1792   PetscFunctionBeginUser;
1793   PetscCall(PetscOptionsGetBool(NULL, NULL, "-resolve", &resolve, NULL));
1794   /* Generate the da for velocity and pressure */
1795   /* Num nodes in each direction is mx+1, my+1, mz+1 */
1796   u_dof         = U_DOFS; /* Vx, Vy - velocities */
1797   p_dof         = P_DOFS; /* p - pressure */
1798   dof           = u_dof + p_dof;
1799   stencil_width = 1;
1800   PetscCall(DMDACreate3d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, mx + 1, my + 1, mz + 1, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE, dof, stencil_width, NULL, NULL, NULL, &da_Stokes));
1801   PetscCall(DMSetMatType(da_Stokes, MATAIJ));
1802   PetscCall(DMSetFromOptions(da_Stokes));
1803   PetscCall(DMSetUp(da_Stokes));
1804   PetscCall(DMDASetFieldName(da_Stokes, 0, "Vx"));
1805   PetscCall(DMDASetFieldName(da_Stokes, 1, "Vy"));
1806   PetscCall(DMDASetFieldName(da_Stokes, 2, "Vz"));
1807   PetscCall(DMDASetFieldName(da_Stokes, 3, "P"));
1808 
1809   /* unit box [0,1] x [0,1] x [0,1] */
1810   PetscCall(DMDASetUniformCoordinates(da_Stokes, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
1811 
1812   /* create quadrature point info for PDE coefficients */
1813   PetscCall(CellPropertiesCreate(da_Stokes, &cell_properties));
1814 
1815   /* interpolate the coordinates to quadrature points */
1816   PetscCall(DMGetCoordinateDM(da_Stokes, &vel_cda));
1817   PetscCall(DMGetCoordinatesLocal(da_Stokes, &vel_coords));
1818   PetscCall(DMDAVecGetArray(vel_cda, vel_coords, &_vel_coords));
1819   PetscCall(DMDAGetElementsCorners(da_Stokes, &sex, &sey, &sez));
1820   PetscCall(DMDAGetElementsSizes(da_Stokes, &Imx, &Jmy, &Kmz));
1821   for (ek = sez; ek < sez + Kmz; ek++) {
1822     for (ej = sey; ej < sey + Jmy; ej++) {
1823       for (ei = sex; ei < sex + Imx; ei++) {
1824         /* get coords for the element */
1825         PetscInt                ngp;
1826         PetscScalar             gp_xi[GAUSS_POINTS][NSD], gp_weight[GAUSS_POINTS];
1827         PetscScalar             el_coords[NSD * NODES_PER_EL];
1828         GaussPointCoefficients *cell;
1829 
1830         PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1831         PetscCall(GetElementCoords3D(_vel_coords, ei, ej, ek, el_coords));
1832         ConstructGaussQuadrature3D(&ngp, gp_xi, gp_weight);
1833 
1834         for (p = 0; p < GAUSS_POINTS; p++) {
1835           PetscScalar xi_p[NSD], Ni_p[NODES_PER_EL];
1836           PetscScalar gp_x, gp_y, gp_z;
1837           PetscInt    n;
1838 
1839           xi_p[0] = gp_xi[p][0];
1840           xi_p[1] = gp_xi[p][1];
1841           xi_p[2] = gp_xi[p][2];
1842           ShapeFunctionQ13D_Evaluate(xi_p, Ni_p);
1843 
1844           gp_x = gp_y = gp_z = 0.0;
1845           for (n = 0; n < NODES_PER_EL; n++) {
1846             gp_x = gp_x + Ni_p[n] * el_coords[NSD * n];
1847             gp_y = gp_y + Ni_p[n] * el_coords[NSD * n + 1];
1848             gp_z = gp_z + Ni_p[n] * el_coords[NSD * n + 2];
1849           }
1850           cell->gp_coords[NSD * p]     = gp_x;
1851           cell->gp_coords[NSD * p + 1] = gp_y;
1852           cell->gp_coords[NSD * p + 2] = gp_z;
1853         }
1854       }
1855     }
1856   }
1857 
1858   PetscCall(PetscOptionsGetInt(NULL, NULL, "-model", &model_definition, NULL));
1859 
1860   switch (model_definition) {
1861   case 0: /* isoviscous */
1862     for (ek = sez; ek < sez + Kmz; ek++) {
1863       for (ej = sey; ej < sey + Jmy; ej++) {
1864         for (ei = sex; ei < sex + Imx; ei++) {
1865           GaussPointCoefficients *cell;
1866 
1867           PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1868           for (p = 0; p < GAUSS_POINTS; p++) {
1869             PetscReal coord_x = PetscRealPart(cell->gp_coords[NSD * p]);
1870             PetscReal coord_y = PetscRealPart(cell->gp_coords[NSD * p + 1]);
1871             PetscReal coord_z = PetscRealPart(cell->gp_coords[NSD * p + 2]);
1872 
1873             cell->eta[p] = 1.0;
1874 
1875             cell->fx[p] = 0.0 * coord_x;
1876             cell->fy[p] = -PetscSinReal(2.2 * PETSC_PI * coord_y) * PetscCosReal(1.0 * PETSC_PI * coord_x);
1877             cell->fz[p] = 0.0 * coord_z;
1878             cell->hc[p] = 0.0;
1879           }
1880         }
1881       }
1882     }
1883     break;
1884 
1885   case 1: /* manufactured */
1886     for (ek = sez; ek < sez + Kmz; ek++) {
1887       for (ej = sey; ej < sey + Jmy; ej++) {
1888         for (ei = sex; ei < sex + Imx; ei++) {
1889           PetscReal               eta, Fm[NSD], Fc, pos[NSD];
1890           GaussPointCoefficients *cell;
1891 
1892           PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1893           for (p = 0; p < GAUSS_POINTS; p++) {
1894             PetscReal coord_x = PetscRealPart(cell->gp_coords[NSD * p]);
1895             PetscReal coord_y = PetscRealPart(cell->gp_coords[NSD * p + 1]);
1896             PetscReal coord_z = PetscRealPart(cell->gp_coords[NSD * p + 2]);
1897 
1898             pos[0] = coord_x;
1899             pos[1] = coord_y;
1900             pos[2] = coord_z;
1901 
1902             evaluate_MS_FrankKamentski(pos, NULL, NULL, &eta, Fm, &Fc);
1903             cell->eta[p] = eta;
1904 
1905             cell->fx[p] = Fm[0];
1906             cell->fy[p] = Fm[1];
1907             cell->fz[p] = Fm[2];
1908             cell->hc[p] = Fc;
1909           }
1910         }
1911       }
1912     }
1913     break;
1914 
1915   case 2: /* solcx */
1916     for (ek = sez; ek < sez + Kmz; ek++) {
1917       for (ej = sey; ej < sey + Jmy; ej++) {
1918         for (ei = sex; ei < sex + Imx; ei++) {
1919           GaussPointCoefficients *cell;
1920 
1921           PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1922           for (p = 0; p < GAUSS_POINTS; p++) {
1923             PetscReal coord_x = PetscRealPart(cell->gp_coords[NSD * p]);
1924             PetscReal coord_y = PetscRealPart(cell->gp_coords[NSD * p + 1]);
1925             PetscReal coord_z = PetscRealPart(cell->gp_coords[NSD * p + 2]);
1926 
1927             cell->eta[p] = 1.0;
1928 
1929             cell->fx[p] = 0.0;
1930             cell->fy[p] = -PetscSinReal(3.0 * PETSC_PI * coord_y) * PetscCosReal(1.0 * PETSC_PI * coord_x);
1931             cell->fz[p] = 0.0 * coord_z;
1932             cell->hc[p] = 0.0;
1933           }
1934         }
1935       }
1936     }
1937     break;
1938 
1939   case 3: /* sinker */
1940     for (ek = sez; ek < sez + Kmz; ek++) {
1941       for (ej = sey; ej < sey + Jmy; ej++) {
1942         for (ei = sex; ei < sex + Imx; ei++) {
1943           GaussPointCoefficients *cell;
1944 
1945           PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1946           for (p = 0; p < GAUSS_POINTS; p++) {
1947             PetscReal xp = PetscRealPart(cell->gp_coords[NSD * p]);
1948             PetscReal yp = PetscRealPart(cell->gp_coords[NSD * p + 1]);
1949             PetscReal zp = PetscRealPart(cell->gp_coords[NSD * p + 2]);
1950 
1951             cell->eta[p] = 1.0e-2;
1952             cell->fx[p]  = 0.0;
1953             cell->fy[p]  = 0.0;
1954             cell->fz[p]  = 0.0;
1955             cell->hc[p]  = 0.0;
1956 
1957             if ((PetscAbs(xp - 0.5) < 0.2) && (PetscAbs(yp - 0.5) < 0.2) && (PetscAbs(zp - 0.5) < 0.2)) {
1958               cell->eta[p] = 1.0;
1959               cell->fz[p]  = 1.0;
1960             }
1961           }
1962         }
1963       }
1964     }
1965     break;
1966 
1967   case 4: /* subdomain jumps */
1968     for (ek = sez; ek < sez + Kmz; ek++) {
1969       for (ej = sey; ej < sey + Jmy; ej++) {
1970         for (ei = sex; ei < sex + Imx; ei++) {
1971           PetscReal               opts_mag, opts_eta0;
1972           PetscInt                px, py, pz;
1973           PetscBool               jump;
1974           PetscMPIInt             rr;
1975           GaussPointCoefficients *cell;
1976 
1977           opts_mag  = 1.0;
1978           opts_eta0 = 1.e-2;
1979 
1980           PetscCall(PetscOptionsGetReal(NULL, NULL, "-jump_eta0", &opts_eta0, NULL));
1981           PetscCall(PetscOptionsGetReal(NULL, NULL, "-jump_magnitude", &opts_mag, NULL));
1982           PetscCall(DMDAGetInfo(da_Stokes, NULL, NULL, NULL, NULL, &px, &py, &pz, NULL, NULL, NULL, NULL, NULL, NULL));
1983           rr = PetscGlobalRank % (px * py);
1984           if (px % 2) jump = (PetscBool)(rr % 2);
1985           else jump = (PetscBool)((rr / px) % 2 ? rr % 2 : !(rr % 2));
1986           rr = PetscGlobalRank / (px * py);
1987           if (rr % 2) jump = (PetscBool)!jump;
1988           PetscCall(CellPropertiesGetCell(cell_properties, ei, ej, ek, &cell));
1989           for (p = 0; p < GAUSS_POINTS; p++) {
1990             PetscReal xp = PetscRealPart(cell->gp_coords[NSD * p]);
1991             PetscReal yp = PetscRealPart(cell->gp_coords[NSD * p + 1]);
1992 
1993             cell->eta[p] = jump ? PetscPowReal(10.0, opts_mag) : opts_eta0;
1994             cell->fx[p]  = 0.0;
1995             cell->fy[p]  = -PetscSinReal(2.2 * PETSC_PI * yp) * PetscCosReal(1.0 * PETSC_PI * xp);
1996             cell->fz[p]  = 0.0;
1997             cell->hc[p]  = 0.0;
1998           }
1999         }
2000       }
2001     }
2002     break;
2003   default:
2004     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "No default model is supported. Choose either -model {0,1,2,3}");
2005   }
2006 
2007   PetscCall(DMDAVecRestoreArray(vel_cda, vel_coords, &_vel_coords));
2008 
2009   /* Generate a matrix with the correct non-zero pattern of type AIJ. This will work in parallel and serial */
2010   PetscCall(DMCreateMatrix(da_Stokes, &A));
2011   PetscCall(DMCreateMatrix(da_Stokes, &B));
2012   PetscCall(DMCreateGlobalVector(da_Stokes, &X));
2013   PetscCall(DMCreateGlobalVector(da_Stokes, &f));
2014 
2015   /* assemble A11 */
2016   PetscCall(MatZeroEntries(A));
2017   PetscCall(MatZeroEntries(B));
2018   PetscCall(VecZeroEntries(f));
2019 
2020   PetscCall(AssembleA_Stokes(A, da_Stokes, cell_properties));
2021   PetscCall(MatViewFromOptions(A, NULL, "-amat_view"));
2022   PetscCall(AssembleA_PCStokes(B, da_Stokes, cell_properties));
2023   PetscCall(MatViewFromOptions(B, NULL, "-bmat_view"));
2024   /* build force vector */
2025   PetscCall(AssembleF_Stokes(f, da_Stokes, cell_properties));
2026 
2027   /* SOLVE */
2028   PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp_S));
2029   PetscCall(KSPSetOptionsPrefix(ksp_S, "stokes_"));
2030   PetscCall(KSPSetOperators(ksp_S, A, B));
2031   PetscCall(KSPSetFromOptions(ksp_S));
2032 
2033   {
2034     PC             pc;
2035     const PetscInt ufields[] = {0, 1, 2}, pfields[] = {3};
2036     PetscCall(KSPGetPC(ksp_S, &pc));
2037     PetscCall(PCFieldSplitSetBlockSize(pc, 4));
2038     PetscCall(PCFieldSplitSetFields(pc, "u", 3, ufields, ufields));
2039     PetscCall(PCFieldSplitSetFields(pc, "p", 1, pfields, pfields));
2040   }
2041 
2042   {
2043     PC        pc;
2044     PetscBool same = PETSC_FALSE;
2045     PetscCall(KSPGetPC(ksp_S, &pc));
2046     PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCMG, &same));
2047     if (same) PetscCall(PCMGSetupViaCoarsen(pc, da_Stokes));
2048   }
2049 
2050   {
2051     PC        pc;
2052     PetscBool same = PETSC_FALSE;
2053     PetscCall(KSPGetPC(ksp_S, &pc));
2054     PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCBDDC, &same));
2055     if (same) PetscCall(KSPSetOperators(ksp_S, A, A));
2056   }
2057 
2058   {
2059     PetscBool stokes_monitor = PETSC_FALSE;
2060     PetscCall(PetscOptionsGetBool(NULL, NULL, "-stokes_ksp_monitor_blocks", &stokes_monitor, 0));
2061     if (stokes_monitor) PetscCall(KSPMonitorSet(ksp_S, KSPMonitorStokesBlocks, NULL, NULL));
2062   }
2063 
2064   if (resolve) {
2065     /* Test changing matrix data structure and resolve */
2066     PetscCall(VecDuplicate(X, &X1));
2067   }
2068 
2069   PetscCall(KSPSolve(ksp_S, f, X));
2070   if (resolve) {
2071     Mat C;
2072     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &C));
2073     PetscCall(KSPSetOperators(ksp_S, C, C));
2074     PetscCall(KSPSolve(ksp_S, f, X1));
2075     PetscCall(MatDestroy(&C));
2076     PetscCall(VecDestroy(&X1));
2077   }
2078 
2079   PetscCall(PetscOptionsGetBool(NULL, NULL, "-write_pvts", &write_output, NULL));
2080   if (write_output) PetscCall(DAView3DPVTS(da_Stokes, X, "up"));
2081   {
2082     PetscBool flg = PETSC_FALSE;
2083     char      filename[PETSC_MAX_PATH_LEN];
2084     PetscCall(PetscOptionsGetString(NULL, NULL, "-write_binary", filename, sizeof(filename), &flg));
2085     if (flg) {
2086       PetscViewer viewer;
2087       /* PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename[0]?filename:"ex42-binaryoutput",FILE_MODE_WRITE,&viewer)); */
2088       PetscCall(PetscViewerVTKOpen(PETSC_COMM_WORLD, "ex42.vts", FILE_MODE_WRITE, &viewer));
2089       PetscCall(VecView(X, viewer));
2090       PetscCall(PetscViewerDestroy(&viewer));
2091     }
2092   }
2093   PetscCall(KSPGetIterationNumber(ksp_S, &its));
2094 
2095   /* verify */
2096   if (model_definition == 1) {
2097     DM  da_Stokes_analytic;
2098     Vec X_analytic;
2099 
2100     PetscCall(DMDACreateManufacturedSolution(mx, my, mz, &da_Stokes_analytic, &X_analytic));
2101     if (write_output) PetscCall(DAView3DPVTS(da_Stokes_analytic, X_analytic, "ms"));
2102     PetscCall(DMDAIntegrateErrors3D(da_Stokes_analytic, X, X_analytic));
2103     if (write_output) PetscCall(DAView3DPVTS(da_Stokes, X, "up2"));
2104     PetscCall(DMDestroy(&da_Stokes_analytic));
2105     PetscCall(VecDestroy(&X_analytic));
2106   }
2107 
2108   PetscCall(KSPDestroy(&ksp_S));
2109   PetscCall(VecDestroy(&X));
2110   PetscCall(VecDestroy(&f));
2111   PetscCall(MatDestroy(&A));
2112   PetscCall(MatDestroy(&B));
2113 
2114   PetscCall(CellPropertiesDestroy(&cell_properties));
2115   PetscCall(DMDestroy(&da_Stokes));
2116   PetscFunctionReturn(PETSC_SUCCESS);
2117 }
2118 
main(int argc,char ** args)2119 int main(int argc, char **args)
2120 {
2121   PetscInt mx, my, mz;
2122 
2123   PetscFunctionBeginUser;
2124   PetscCall(PetscInitialize(&argc, &args, NULL, help));
2125   mx = my = mz = 10;
2126   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mx", &mx, NULL));
2127   my = mx;
2128   mz = mx;
2129   PetscCall(PetscOptionsGetInt(NULL, NULL, "-my", &my, NULL));
2130   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mz", &mz, NULL));
2131   PetscCall(solve_stokes_3d_coupled(mx, my, mz));
2132   PetscCall(PetscFinalize());
2133   return 0;
2134 }
2135 
2136 /*TEST
2137 
2138    test:
2139       args: -stokes_ksp_monitor_short -stokes_ksp_converged_reason -stokes_pc_type lu
2140 
2141    test:
2142       suffix: 2
2143       nsize: 3
2144       args: -stokes_ksp_monitor_short -stokes_ksp_converged_reason -stokes_pc_type redundant -stokes_redundant_pc_type lu
2145 
2146    test:
2147       suffix: bddc_stokes
2148       nsize: 6
2149       args: -mx 5 -my 4 -mz 3 -stokes_ksp_monitor_short -stokes_ksp_converged_reason -stokes_pc_type bddc -dm_mat_type is -stokes_pc_bddc_dirichlet_pc_type svd -stokes_pc_bddc_neumann_pc_type svd -stokes_pc_bddc_coarse_redundant_pc_type svd
2150 
2151    test:
2152       suffix: bddc_stokes_deluxe
2153       nsize: 6
2154       args: -mx 5 -my 4 -mz 3 -stokes_ksp_monitor_short -stokes_ksp_converged_reason -stokes_pc_type bddc -dm_mat_type is -stokes_pc_bddc_dirichlet_pc_type svd -stokes_pc_bddc_neumann_pc_type svd -stokes_pc_bddc_coarse_redundant_pc_type svd -stokes_pc_bddc_use_deluxe_scaling -stokes_sub_schurs_posdef 0 -stokes_sub_schurs_symmetric -stokes_sub_schurs_mat_solver_type petsc
2155 
2156    test:
2157       requires: !single
2158       suffix: bddc_stokes_subdomainjump_deluxe
2159       nsize: 9
2160       args: -model 4 -jump_magnitude 4 -mx 6 -my 6 -mz 2 -stokes_ksp_monitor_short -stokes_ksp_converged_reason -stokes_pc_type bddc -dm_mat_type is -stokes_pc_bddc_use_deluxe_scaling -stokes_sub_schurs_posdef 0 -stokes_sub_schurs_symmetric -stokes_sub_schurs_mat_solver_type petsc -stokes_pc_bddc_schur_layers 1
2161 
2162    test:
2163       requires: !single
2164       suffix: 3
2165       args: -stokes_ksp_converged_reason -stokes_pc_type fieldsplit -resolve
2166 
2167    test:
2168       suffix: tut_1
2169       nsize: 4
2170       requires: !single
2171       args: -stokes_ksp_monitor
2172 
2173    test:
2174       suffix: tut_2
2175       nsize: 4
2176       requires: !single
2177       args: -stokes_ksp_monitor -stokes_pc_type fieldsplit -stokes_pc_fieldsplit_type schur
2178 
2179    test:
2180       suffix: tut_3
2181       nsize: 4
2182       requires: !single
2183       args: -mx 20 -stokes_ksp_monitor -stokes_pc_type fieldsplit -stokes_pc_fieldsplit_type schur
2184 
2185 TEST*/
2186