xref: /petsc/src/dm/impls/plex/tests/ex5.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1 static char help[] = "Tests for creation of hybrid meshes\n\n";
2 
3 /* TODO
4  - Propagate hybridSize with distribution
5  - Test with multiple fault segments
6  - Test with embedded fault
7  - Test with multiple faults
8  - Move over all PyLith tests?
9 */
10 
11 #include <petscdmplex.h>
12 #include <petscds.h>
13 #include <petsc/private/dmpleximpl.h>
14 /* List of test meshes
15 
16 Triangle
17 --------
18 Test 0:
19 Two triangles sharing a face
20 
21         4
22       / | \
23      8  |  9
24     /   |   \
25    2  0 7 1  5
26     \   |   /
27      6  |  10
28       \ | /
29         3
30 
31 should become two triangles separated by a zero-volume cell with 4 vertices
32 
33         5--16--8              4--12--6 3
34       / |      | \          / |      | | \
35     11  |      |  12       9  |      | |  4
36     /   |      |   \      /   |      | |   \
37    3  0 10  2 14 1  6    2  0 8  1  10 6 0  1
38     \   |      |   /      \   |      | |   /
39      9  |      |  13       7  |      | |  5
40       \ |      | /          \ |      | | /
41         4--15--7              3--11--5 2
42 
43 Test 1:
44 Four triangles sharing two faces which are oriented against each other
45 
46           9
47          / \
48         /   \
49       17  2  16
50       /       \
51      /         \
52     8-----15----5
53      \         /|\
54       \       / | \
55       18  3  12 |  14
56         \   /   |   \
57          \ /    |    \
58           4  0 11  1  7
59            \    |    /
60             \   |   /
61             10  |  13
62               \ | /
63                \|/
64                 6
65 
66 Fault mesh
67 
68 0 --> 0
69 1 --> 1
70 2 --> 2
71 3 --> 3
72 4 --> 5
73 5 --> 6
74 6 --> 8
75 7 --> 11
76 8 --> 15
77 
78        2
79        |
80   6----8----4
81        |    |
82        3    |
83           0-7-1
84             |
85             |
86             5
87 
88 should become four triangles separated by two zero-volume cells with 4 vertices
89 
90           11
91           / \
92          /   \
93         /     \
94       22   2   21
95       /         \
96      /           \
97    10-----20------7
98 28  |     5    26/ \
99    14----25----12   \
100      \         /|   |\
101       \       / |   | \
102       23  3  17 |   |  19
103         \   /   |   |   \
104          \ /    |   |    \
105           6  0 24 4 16 1  9
106            \    |   |    /
107             \   |   |   /
108             15  |   |  18
109               \ |   | /
110                \|   |/
111                13---8
112                  27
113 
114 Test 2:
115 Six triangles sharing one face
116 
117 11-----12------13
118  |     /|\     |
119  | 1  / | \ 4  |
120  |   /  |  \   |
121  |  /   |   \  |
122  | /    |    \ |
123  |/     |     \|
124  9  2   |   5  10
125  |\     |     /|
126  | \    |    / |
127  |  \   |   /  |
128  |   \  |  /   |
129  | 0  \ | / 3  |
130  |     \|/     |
131  6------7------8
132 
133 Test 3:
134 This is Test 2 on two processes. After the fault, we have
135 
136  6--12--7    7--20-10--16-8
137  |     /|    |     |\     |
138  | 1  / |    |     | \  1 |
139 13  11  |    |     |  17  15
140  |  /   |    |     |   \  |
141  | /    |    |     |    \ |
142  |/     |    |     |     \|
143  5   2  14  11  3 18  2   6
144  |\     |    |     |     /|
145  | \    |    |     |    / |
146  |  \   |    |     |   /  |
147 10   9  |    |     |  14  13
148  | 0  \ |    |     | /  0 |
149  |     \|    |     |/     |
150  3---8--4    4--19-9--12--5
151 
152 Test 4:
153 This is Test 2 on six processes. After the fault, we have
154 
155 Test 5:
156 
157   Fault only on points 2 and 5:
158 
159         6
160       / | \
161     13  |  17
162     /  15   \
163    7  0 | 1  9
164    |\   |   /|
165    | 14 | 16 |
166    |  \ | /  |
167  18| 2  8  3 |21
168    |  / | \  |
169    | 19 | 20 |
170    |/   |   \|
171   10  4 | 5  12
172     \  23   /
173     22  |  24
174       \ | /
175        11
176 
177 Tetrahedron
178 -----------
179 Test 0:
180 Two tets sharing a face
181 
182  cell   5 _______    cell
183  0    / | \      \       1
184     16  |  18     22
185     /8 19 10\      \
186    2-15-|----4--21--6
187     \  9| 7 /      /
188     14  |  17     20
189       \ | /      /
190         3-------
191 
192 should become two tetrahedrons separated by a zero-volume cell with 3 faces/3 edges/6 vertices
193 
194  cell   6 ___36___10______    cell
195  0    / | \        |\      \     1
196     24  |  26      | 32     30
197     /12 27 14\    33  \      \
198    3-23-|----5--35-|---9--29--7
199     \ 13| 11/      |18 /      /
200     22  |  25      | 31     28
201       \ | /        |/      /
202         4----34----8------
203          cell 2
204 
205 In parallel,
206 
207  cell   5 ___28____8      4______    cell
208  0    / | \        |\     |\      \     0
209     19  |   21     | 24   | 13  6  11
210     /10 22 12\    25  \   |8 \      \
211    2-18-|----4--27-|---7  14  3--10--1
212     \ 11| 9 /      |13 /  |  /      /
213     17  |  20      | 23   | 12  5  9
214       \ | /        |/     |/      /
215         3----26----6      2------
216          cell 1
217 
218 Test 1:
219 Four tets sharing two faces
220 
221 Cells:    0-3,4-5
222 Vertices: 6-15
223 Faces:    16-29,30-34
224 Edges:    35-52,53-56
225 
226 Quadrilateral
227 -------------
228 Test 0:
229 Two quads sharing a face
230 
231    5--10---4--14---7
232    |       |       |
233   11   0   9   1  13
234    |       |       |
235    2---8---3--12---6
236 
237 should become two quads separated by a zero-volume cell with 4 vertices
238 
239    6--13---5-20-10--17---8    5--10---4-14--7  4---7---2
240    |       |     |       |    |       |     |  |       |
241   14   0  12  2 18   1  16   11   0   9  1 12  8   0   6
242    |       |     |       |    |       |     |  |       |
243    3--11---4-19--9--15---7    2---8---3-13--6  3---5---1
244 
245 Test 1:
246 
247 Original mesh with 9 cells,
248 
249   9-----10-----11-----12
250   |      |     ||      |
251   |      |     ||      |
252   |   0  |  1  ||  2   |
253   |      |     ||      |
254  13-----14-----15-----16
255   |      |     ||      |
256   |      |     ||      |
257   |  3   |  4  ||  5   |
258   |      |     ||      |
259  17-----18-----19=====20
260   |      |      |      |
261   |      |      |      |
262   |  6   |  7   |  8   |
263   |      |      |      |
264  21-----22-----23-----24
265 
266 After first fault,
267 
268  12 ----13 ----14-28 ----15
269   |      |      |  |      |
270   |  0   |  1   | 9|  2   |
271   |      |      |  |      |
272   |      |      |  |      |
273  16 ----17 ----18-29 ----19
274   |      |      |  |      |
275   |  3   |  4   |10|  5   |
276   |      |      |  |      |
277   |      |      |  |      |
278  20 ----21-----22-30 ----23
279   |      |      |  \--11- |
280   |  6   |  7   |     8   |
281   |      |      |         |
282   |      |      |         |
283  24 ----25 ----26--------27
284 
285 After second fault,
286 
287  14 ----15 ----16-30 ----17
288   |      |      |  |      |
289   |  0   |  1   | 9|  2   |
290   |      |      |  |      |
291   |      |      |  |      |
292  18 ----19 ----20-31 ----21
293   |      |      |  |      |
294   |  3   |  4   |10|  5   |
295   |      |      |  |      |
296   |      |      |  |      |
297  33 ----34-----24-32 ----25
298   |  12  | 13 / |  \-11-- |
299  22 ----23---/  |         |
300   |      |      |         |
301   |  6   |   7  |     8   |
302   |      |      |         |
303   |      |      |         |
304  26 ----27 ----28--------29
305 
306  Test 2:
307  Two quads sharing a face in parallel
308 
309     4---7---3  2---8---4
310     |       |  |       |
311     8   0   6  5   0   7
312     |       |  |       |
313     1---5---2  1---6---3
314 
315  should become two quads separated by a zero-volume cell with 4 vertices
316 
317      4---7---3  3-14--7--11---5
318      |       |  |     |       |
319      8   0   6  8  1  12  0   10
320      |       |  |     |       |
321      1---5---2  2-13--6---9---4
322 
323  Test 3:
324  Like Test 2, but with different partition
325 
326      5--10---4-14--7   2---8---4
327      |       |     |   |       |
328     11   0   9  1  12  5   0   7
329      |       |     |   |       |
330      2---8---3-13--6   1---6---3
331 
332 Hexahedron
333 ----------
334 Test 0:
335 Two hexes sharing a face
336 
337 cell   9-----31------8-----42------13 cell
338 0     /|            /|            /|     1
339     32 |   15      30|   21      41|
340     /  |          /  |          /  |
341    6-----29------7-----40------12  |
342    |   |     18  |   |     24  |   |
343    |  36         |  35         |   44
344    |19 |         |17 |         |23 |
345   33   |  16    34   |   22   43   |
346    |   5-----27--|---4-----39--|---11
347    |  /          |  /          |  /
348    | 28   14     | 26    20    | 38
349    |/            |/            |/
350    2-----25------3-----37------10
351 
352 should become two hexes separated by a zero-volume cell with 8 vertices
353 
354                          cell 2
355 cell  10-----41------9-----62------18----52------14 cell
356 0     /|            /|            /|            /|     1
357     42 |   20      40|  32       56|   26      51|
358     /  |          /  |          /  |          /  |
359    7-----39------8-----61------17--|-50------13  |
360    |   |     23  |   |         |   |     29  |   |
361    |  46         |  45         |   58        |   54
362    |24 |         |22 |         |30 |         |28 |
363   43   |  21    44   |        57   |   27   53   |
364    |   6-----37--|---5-----60--|---16----49--|---12
365    |  /          |  /          |  /          |  /
366    | 38   19     | 36   31     | 55    25    | 48
367    |/            |/            |/            |/
368    3-----35------4-----59------15----47------11
369 
370 In parallel,
371 
372                          cell 2
373 cell   9-----31------8-----44------13     8----20------4  cell
374 0     /|            /|            /|     /|           /|     1
375     32 |   15      30|  22       38|   24 |  10      19|
376     /  |          /  |          /  |   /  |         /  |
377    6-----29------7-----43------12  |  7----18------3   |
378    |   |     18  |   |         |   |  |   |    13  |   |
379    |  36         |  35         |   40 |  26        |   22
380    |19 |         |17 |         |20 |  |14 |        |12 |
381   33   |  16    34   |        39   |  25  |  11   21   |
382    |   5-----27--|---4-----42--|---11 |   6----17--|---2
383    |  /          |  /          |  /   |  /         |  /
384    | 28   14     | 26   21     | 37   |23     9    | 16
385    |/            |/            |/     |/           |/
386    2-----25------3-----41------10     5----15------1
387 
388 Test 1:
389 
390 */
391 
392 typedef struct {
393   PetscInt  debug;          /* The debugging level */
394   PetscInt  dim;            /* The topological mesh dimension */
395   PetscBool cellSimplex;    /* Use simplices or hexes */
396   PetscBool testPartition;  /* Use a fixed partitioning for testing */
397   PetscBool testAssembly;   // Flag for assembly test
398   PetscInt  testNum;        /* The particular mesh to test */
399   PetscInt  cohesiveFields; /* The number of cohesive fields */
400 } AppCtx;
401 
ProcessOptions(MPI_Comm comm,AppCtx * options)402 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
403 {
404   PetscFunctionBegin;
405   options->debug          = 0;
406   options->dim            = 2;
407   options->cellSimplex    = PETSC_TRUE;
408   options->testPartition  = PETSC_TRUE;
409   options->testAssembly   = PETSC_TRUE;
410   options->testNum        = 0;
411   options->cohesiveFields = 1;
412 
413   PetscOptionsBegin(comm, "", "Meshing Problem Options", "DMPLEX");
414   PetscCall(PetscOptionsBoundedInt("-debug", "The debugging level", "ex5.c", options->debug, &options->debug, NULL, 0));
415   PetscCall(PetscOptionsRangeInt("-dim", "The topological mesh dimension", "ex5.c", options->dim, &options->dim, NULL, 1, 3));
416   PetscCall(PetscOptionsBool("-cell_simplex", "Use simplices if true, otherwise hexes", "ex5.c", options->cellSimplex, &options->cellSimplex, NULL));
417   PetscCall(PetscOptionsBool("-test_partition", "Use a fixed partition for testing", "ex5.c", options->testPartition, &options->testPartition, NULL));
418   PetscCall(PetscOptionsBool("-test_assembly", "Run the assembly test", "ex5.c", options->testAssembly, &options->testAssembly, NULL));
419   PetscCall(PetscOptionsBoundedInt("-test_num", "The particular mesh to test", "ex5.c", options->testNum, &options->testNum, NULL, 0));
420   PetscCall(PetscOptionsBoundedInt("-cohesive_fields", "The number of cohesive fields", "ex5.c", options->cohesiveFields, &options->cohesiveFields, NULL, 0));
421   PetscOptionsEnd();
422   PetscFunctionReturn(PETSC_SUCCESS);
423 }
424 
CreateSimplex_2D(MPI_Comm comm,PetscInt testNum,DM * dm)425 static PetscErrorCode CreateSimplex_2D(MPI_Comm comm, PetscInt testNum, DM *dm)
426 {
427   DM          idm;
428   PetscInt    p;
429   PetscMPIInt rank;
430 
431   PetscFunctionBegin;
432   PetscCallMPI(MPI_Comm_rank(comm, &rank));
433   if (rank == 0) {
434     switch (testNum) {
435     case 0: {
436       PetscInt    numPoints[2]        = {4, 2};
437       PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
438       PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
439       PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
440       PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
441       PetscInt    markerPoints[8]     = {2, 1, 3, 1, 4, 1, 5, 1};
442       PetscInt    faultPoints[2]      = {3, 4};
443 
444       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
445       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
446       for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
447       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
448       PetscCall(DMSetLabelValue(*dm, "material", 1, 2));
449     } break;
450     case 1: {
451       PetscInt    numPoints[2]         = {6, 4};
452       PetscInt    coneSize[10]         = {3, 3, 3, 3, 0, 0, 0, 0, 0, 0};
453       PetscInt    cones[12]            = {4, 6, 5, 5, 6, 7, 8, 5, 9, 8, 4, 5};
454       PetscInt    coneOrientations[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
455       PetscScalar vertexCoords[12]     = {-1.0, 0.0, 0.0, 1.0, 0.0, -1.0, 1.0, 0.0, -2.0, 1.0, -1.0, 2.0};
456       PetscInt    markerPoints[6]      = {4, 1, 6, 1, 8, 1};
457       PetscInt    faultPoints[3]       = {5, 6, 8};
458 
459       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
460       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
461       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
462       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
463       PetscCall(DMSetLabelValue(*dm, "material", 3, 1));
464       PetscCall(DMSetLabelValue(*dm, "material", 1, 2));
465       PetscCall(DMSetLabelValue(*dm, "material", 2, 2));
466     } break;
467     case 2:
468     case 3:
469     case 4: {
470       PetscInt    numPoints[2]         = {8, 6};
471       PetscInt    coneSize[14]         = {3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0};
472       PetscInt    cones[18]            = {6, 7, 9, 9, 12, 11, 7, 12, 9, 7, 8, 10, 10, 13, 12, 7, 10, 12};
473       PetscInt    coneOrientations[18] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
474       PetscScalar vertexCoords[16]     = {
475         -1., -1., 0., -1., 1., -1., -1., 0., 1., 0., -1., 1., 0., 1., 1., 1.,
476       };
477       PetscInt markerPoints[16] = {6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1};
478       PetscInt faultPoints[2]   = {7, 12};
479 
480       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
481       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
482       PetscCall(DMSetLabelValue(*dm, "material", 1, 1));
483       PetscCall(DMSetLabelValue(*dm, "material", 2, 1));
484       PetscCall(DMSetLabelValue(*dm, "material", 3, 2));
485       PetscCall(DMSetLabelValue(*dm, "material", 4, 2));
486       PetscCall(DMSetLabelValue(*dm, "material", 5, 2));
487       for (p = 0; p < 8; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
488       if (testNum == 2)
489         for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
490       if (testNum == 3 || testNum == 4)
491         for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "pfault", faultPoints[p], 1));
492     } break;
493     case 5: {
494       PetscInt    numPoints[2]         = {7, 6};
495       PetscInt    coneSize[13]         = {3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0};
496       PetscInt    cones[18]            = {6, 7, 8, 8, 9, 6, 7, 10, 8, 9, 8, 12, 8, 10, 11, 11, 12, 8};
497       PetscInt    coneOrientations[18] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
498       PetscScalar vertexCoords[14]     = {0.0, 2.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, -2.0, 1.0, -1.0};
499       PetscInt    faultPoints[2]       = {8, 11};
500       PetscInt    faultBdPoints[1]     = {8};
501 
502       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
503       for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
504       for (p = 0; p < 1; ++p) PetscCall(DMSetLabelValue(*dm, "faultBd", faultBdPoints[p], 1));
505       PetscCall(DMSetLabelValue(*dm, "material", 0, 0));
506       PetscCall(DMSetLabelValue(*dm, "material", 2, 0));
507       PetscCall(DMSetLabelValue(*dm, "material", 4, 0));
508       PetscCall(DMSetLabelValue(*dm, "material", 1, 2));
509       PetscCall(DMSetLabelValue(*dm, "material", 3, 2));
510       PetscCall(DMSetLabelValue(*dm, "material", 5, 2));
511     } break;
512     default:
513       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
514     }
515   } else {
516     PetscInt numPoints[3] = {0, 0, 0};
517 
518     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
519     if (testNum == 3 || testNum == 4) PetscCall(DMCreateLabel(*dm, "pfault"));
520     else PetscCall(DMCreateLabel(*dm, "fault"));
521   }
522   PetscCall(DMPlexInterpolate(*dm, &idm));
523   PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
524   PetscCall(DMDestroy(dm));
525   *dm = idm;
526   PetscFunctionReturn(PETSC_SUCCESS);
527 }
528 
CreateSimplex_3D(MPI_Comm comm,AppCtx * user,DM dm)529 static PetscErrorCode CreateSimplex_3D(MPI_Comm comm, AppCtx *user, DM dm)
530 {
531   PetscInt    depth = 3, testNum = user->testNum, p;
532   PetscMPIInt rank;
533 
534   PetscFunctionBegin;
535   PetscCallMPI(MPI_Comm_rank(comm, &rank));
536   if (rank == 0) {
537     switch (testNum) {
538     case 0: {
539       PetscInt    numPoints[4]         = {5, 7, 9, 2};
540       PetscInt    coneSize[23]         = {4, 4, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2};
541       PetscInt    cones[47]            = {7, 8, 9, 10, 11, 10, 13, 12, 15, 17, 14, 16, 18, 15, 14, 19, 16, 17, 18, 19, 17, 21, 20, 18, 22, 21, 22, 19, 20, 2, 3, 2, 4, 2, 5, 3, 4, 4, 5, 5, 3, 3, 6, 4, 6, 5, 6};
542       PetscInt    coneOrientations[47] = {0, 0, 0, 0, 0, -2, 2, 2, 0, -1, -1, 0, -1, -1, 0, -1, -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
543       PetscScalar vertexCoords[15]     = {0.0, 0.0, -0.5, 0.0, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5};
544       PetscInt    markerPoints[20]     = {2, 1, 3, 1, 4, 1, 5, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1};
545       PetscInt    faultPoints[3]       = {3, 4, 5};
546 
547       PetscCall(DMPlexCreateFromDAG(dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
548       for (p = 0; p < 10; ++p) PetscCall(DMSetLabelValue(dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
549       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(dm, "fault", faultPoints[p], 1));
550       PetscCall(DMSetLabelValue(dm, "material", 0, 1));
551       PetscCall(DMSetLabelValue(dm, "material", 1, 2));
552     } break;
553     case 1: {
554       PetscInt    numPoints[4]         = {6, 13, 12, 4};
555       PetscInt    coneSize[35]         = {4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
556       PetscInt    cones[78]            = {10, 11, 12, 13, 10, 15, 16, 14, 17, 18, 14, 19, 20, 13, 19, 21, 22, 23, 24, 25, 26, 22, 24, 27, 25, 23, 26, 27, 28, 29, 23, 24, 30, 28, 22, 29, 30, 31, 32,
557                                           28, 29, 33, 31, 32, 33, 23, 26, 34, 33, 34, 27, 32, 6,  5,  5,  7,  7,  6,  6,  4,  4,  5,  7,  4,  7,  9,  9,  5,  6,  9,  9,  8,  8,  7,  5,  8,  4,  8};
558       PetscInt    coneOrientations[78] = {0, 0, 0, 0,  -2, 1,  0, 2,  0, 0,  -3, 0,  0,  -3, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0,
559                                           0, 0, 0, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0,  0,  0, 0, 0, 0, 0, 0, 0,  0,  0, 0,  0,  0,  0,  0, 0, 0, 0, 0, 0,  0, 0,  0,  0, 0};
560       PetscScalar vertexCoords[18]     = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0};
561       PetscInt    markerPoints[14]     = {5, 1, 6, 1, 7, 1, 10, 1, 22, 1, 23, 1, 24, 1};
562       PetscInt    faultPoints[4]       = {5, 6, 7, 8};
563 
564       PetscCall(DMPlexCreateFromDAG(dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
565       for (p = 0; p < 7; ++p) PetscCall(DMSetLabelValue(dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
566       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(dm, "fault", faultPoints[p], 1));
567       PetscCall(DMSetLabelValue(dm, "material", 0, 1));
568       PetscCall(DMSetLabelValue(dm, "material", 1, 2));
569     } break;
570     default:
571       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
572     }
573   } else {
574     PetscInt numPoints[4] = {0, 0, 0, 0};
575 
576     PetscCall(DMPlexCreateFromDAG(dm, depth, numPoints, NULL, NULL, NULL, NULL));
577     PetscCall(DMCreateLabel(dm, "fault"));
578   }
579   PetscFunctionReturn(PETSC_SUCCESS);
580 }
581 
CreateQuad_2D(MPI_Comm comm,PetscInt testNum,DM * dm)582 static PetscErrorCode CreateQuad_2D(MPI_Comm comm, PetscInt testNum, DM *dm)
583 {
584   DM          idm;
585   PetscInt    p;
586   PetscMPIInt rank;
587 
588   PetscFunctionBegin;
589   PetscCallMPI(MPI_Comm_rank(comm, &rank));
590   if (rank == 0) {
591     switch (testNum) {
592     case 0:
593     case 2:
594     case 3: {
595       PetscInt    numPoints[2]        = {6, 2};
596       PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
597       PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
598       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
599       PetscScalar vertexCoords[12]    = {-0.5, 0.0, 0.0, 0.0, 0.0, 1.0, -0.5, 1.0, 0.5, 0.0, 0.5, 1.0};
600       PetscInt    markerPoints[12]    = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1};
601       PetscInt    faultPoints[2]      = {3, 4};
602 
603       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
604       for (p = 0; p < 6; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
605       if (testNum == 0)
606         for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
607       if (testNum == 2 || testNum == 3)
608         for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "pfault", faultPoints[p], 1));
609       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
610       PetscCall(DMSetLabelValue(*dm, "material", 1, 2));
611     } break;
612     case 1: {
613       PetscInt    numPoints[2]         = {16, 9};
614       PetscInt    coneSize[25]         = {4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
615       PetscInt    cones[36]            = {9, 13, 14, 10, 10, 14, 15, 11, 11, 15, 16, 12, 13, 17, 18, 14, 14, 18, 19, 15, 15, 19, 20, 16, 17, 21, 22, 18, 18, 22, 23, 19, 19, 23, 24, 20};
616       PetscInt    coneOrientations[36] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
617       PetscScalar vertexCoords[32]     = {-3.0, 3.0, -1.0, 3.0, 1.0, 3.0, 3.0, 3.0, -3.0, 1.0, -1.0, 1.0, 1.0, 1.0, 3.0, 1.0, -3.0, -1.0, -1.0, -1.0, 1.0, -1.0, 3.0, -1.0, -3.0, -3.0, -1.0, -3.0, 1.0, -3.0, 3.0, -3.0};
618       PetscInt    faultPoints[4]       = {11, 15, 19, 20};
619       PetscInt    fault2Points[2]      = {17, 18};
620 
621       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
622       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
623       for (p = 3; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "faultBd", faultPoints[p], 1));
624       for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault2", fault2Points[p], 1));
625       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
626       PetscCall(DMSetLabelValue(*dm, "material", 1, 1));
627       PetscCall(DMSetLabelValue(*dm, "material", 2, 1));
628       PetscCall(DMSetLabelValue(*dm, "material", 3, 1));
629       PetscCall(DMSetLabelValue(*dm, "material", 4, 1));
630       PetscCall(DMSetLabelValue(*dm, "material", 5, 2));
631       PetscCall(DMSetLabelValue(*dm, "material", 6, 2));
632       PetscCall(DMSetLabelValue(*dm, "material", 7, 2));
633       PetscCall(DMSetLabelValue(*dm, "material", 8, 2));
634     } break;
635     default:
636       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
637     }
638   } else {
639     PetscInt numPoints[3] = {0, 0, 0};
640 
641     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
642     if (testNum == 2 || testNum == 3) PetscCall(DMCreateLabel(*dm, "pfault"));
643     else PetscCall(DMCreateLabel(*dm, "fault"));
644   }
645   PetscCall(DMPlexInterpolate(*dm, &idm));
646   PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
647   PetscCall(DMDestroy(dm));
648   *dm = idm;
649   PetscFunctionReturn(PETSC_SUCCESS);
650 }
651 
CreateHex_3D(MPI_Comm comm,PetscInt testNum,DM * dm)652 static PetscErrorCode CreateHex_3D(MPI_Comm comm, PetscInt testNum, DM *dm)
653 {
654   DM          idm;
655   PetscInt    depth = 3, p;
656   PetscMPIInt rank;
657 
658   PetscFunctionBegin;
659   PetscCallMPI(MPI_Comm_rank(comm, &rank));
660   if (rank == 0) {
661     switch (testNum) {
662     case 0: {
663       PetscInt    numPoints[2]         = {12, 2};
664       PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
665       PetscInt    cones[16]            = {2, 5, 4, 3, 6, 7, 8, 9, 3, 4, 11, 10, 7, 12, 13, 8};
666       PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
667       PetscScalar vertexCoords[36]     = {-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, 1.0, 0.0, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, -0.5, 1.0, 1.0, 0.5, 0.0, 0.0, 0.5, 1.0, 0.0, 0.5, 0.0, 1.0, 0.5, 1.0, 1.0};
668       PetscInt    markerPoints[52]     = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1};
669       PetscInt    faultPoints[4]       = {3, 4, 7, 8};
670 
671       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
672       PetscCall(DMPlexInterpolate(*dm, &idm));
673       for (p = 0; p < 8; ++p) PetscCall(DMSetLabelValue(idm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1]));
674       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(idm, "fault", faultPoints[p], 1));
675       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
676       PetscCall(DMSetLabelValue(*dm, "material", 1, 2));
677     } break;
678     case 1: {
679       /* Cell Adjacency Graph:
680         0 -- { 8, 13, 21, 24} --> 1
681         0 -- {20, 21, 23, 24} --> 5 F
682         1 -- {10, 15, 21, 24} --> 2
683         1 -- {13, 14, 15, 24} --> 6
684         2 -- {21, 22, 24, 25} --> 4 F
685         3 -- {21, 24, 30, 35} --> 4
686         3 -- {21, 24, 28, 33} --> 5
687        */
688       PetscInt numPoints[2] = {30, 7};
689       PetscInt coneSize[37] = {8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
690       PetscInt cones[56] = {8, 21, 20, 7, 13, 12, 23, 24, 14, 15, 10, 9, 13, 8, 21, 24, 15, 16, 11, 10, 24, 21, 22, 25, 30, 29, 28, 21, 35, 24, 33, 34, 24, 21, 30, 35, 25, 36, 31, 22, 27, 20, 21, 28, 32, 33, 24, 23, 15, 24, 13, 14, 19, 18, 17, 26};
691       PetscInt coneOrientations[56] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
692       PetscScalar vertexCoords[90]  = {-2.0, -2.0, -2.0, -2.0, -1.0, -2.0, -3.0, 0.0, -2.0, -2.0, 1.0,  -2.0, -2.0, 2.0, -2.0, -2.0, -2.0, 0.0,  -2.0, -1.0, 0.0, -3.0, 0.0, 0.0, -2.0, 1.0, 0.0, -2.0, 2.0, 0.0,
693                                        -2.0, -1.0, 2.0,  -3.0, 0.0,  2.0,  -2.0, 1.0, 2.0,  0.0,  -2.0, -2.0, 0.0,  0.0, -2.0, 0.0,  2.0,  -2.0, 0.0,  -2.0, 0.0, 0.0,  0.0, 0.0, 0.0,  2.0, 0.0, 0.0,  0.0, 2.0,
694                                        2.0,  -2.0, -2.0, 2.0,  -1.0, -2.0, 3.0,  0.0, -2.0, 2.0,  1.0,  -2.0, 2.0,  2.0, -2.0, 2.0,  -2.0, 0.0,  2.0,  -1.0, 0.0, 3.0,  0.0, 0.0, 2.0,  1.0, 0.0, 2.0,  2.0, 0.0};
695       PetscInt    faultPoints[6]    = {20, 21, 22, 23, 24, 25};
696 
697       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
698       PetscCall(DMPlexInterpolate(*dm, &idm));
699       for (p = 0; p < 6; ++p) PetscCall(DMSetLabelValue(idm, "fault", faultPoints[p], 1));
700       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
701       PetscCall(DMSetLabelValue(*dm, "material", 1, 1));
702       PetscCall(DMSetLabelValue(*dm, "material", 2, 1));
703       PetscCall(DMSetLabelValue(*dm, "material", 3, 2));
704       PetscCall(DMSetLabelValue(*dm, "material", 4, 2));
705       PetscCall(DMSetLabelValue(*dm, "material", 5, 2));
706       PetscCall(DMSetLabelValue(*dm, "material", 6, 2));
707     } break;
708     case 2: {
709       /* Buried fault edge */
710       PetscInt    numPoints[2]         = {18, 4};
711       PetscInt    coneSize[22]         = {8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
712       PetscInt    cones[32]            = {4, 5, 8, 7, 13, 16, 17, 14, 5, 6, 9, 8, 14, 17, 18, 15, 7, 8, 11, 10, 16, 19, 20, 17, 8, 9, 12, 11, 17, 20, 21, 18};
713       PetscInt    coneOrientations[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
714       PetscScalar vertexCoords[54]     = {-2.0, -2.0, 0.0, -2.0, 0.0, 0.0, -2.0, 2.0, 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, -2.0, 0.0, 2.0, 0.0, 0.0, 2.0, 2.0, 0.0,
715                                           -2.0, -2.0, 2.0, -2.0, 0.0, 2.0, -2.0, 2.0, 2.0, 0.0, -2.0, 2.0, 0.0, 0.0, 2.0, 0.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0};
716       PetscInt    faultPoints[4]       = {7, 8, 16, 17};
717 
718       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
719       PetscCall(DMPlexInterpolate(*dm, &idm));
720       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(idm, "fault", faultPoints[p], 1));
721       PetscCall(DMSetLabelValue(*dm, "material", 0, 1));
722       PetscCall(DMSetLabelValue(*dm, "material", 1, 1));
723       PetscCall(DMSetLabelValue(*dm, "material", 2, 2));
724       PetscCall(DMSetLabelValue(*dm, "material", 3, 2));
725     } break;
726     default:
727       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
728     }
729   } else {
730     PetscInt numPoints[4] = {0, 0, 0, 0};
731 
732     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, NULL, NULL, NULL, NULL));
733     PetscCall(DMPlexInterpolate(*dm, &idm));
734     PetscCall(DMCreateLabel(idm, "fault"));
735   }
736   PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
737   PetscCall(DMDestroy(dm));
738   *dm = idm;
739   PetscFunctionReturn(PETSC_SUCCESS);
740 }
741 
CreateFaultLabel(DM dm)742 static PetscErrorCode CreateFaultLabel(DM dm)
743 {
744   DMLabel  label;
745   PetscInt dim, h, pStart, pEnd, pMax, p;
746 
747   PetscFunctionBegin;
748   PetscCall(DMGetDimension(dm, &dim));
749   PetscCall(DMCreateLabel(dm, "cohesive"));
750   PetscCall(DMGetLabel(dm, "cohesive", &label));
751   for (h = 0; h <= dim; ++h) {
752     PetscCall(DMPlexGetSimplexOrBoxCells(dm, h, NULL, &pMax));
753     PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
754     for (p = pMax; p < pEnd; ++p) PetscCall(DMLabelSetValue(label, p, 1));
755   }
756   PetscFunctionReturn(PETSC_SUCCESS);
757 }
758 
759 /*
760   Create a displacement field, and some number of vector fault fields
761 */
CreateDiscretization(DM dm,AppCtx * user)762 static PetscErrorCode CreateDiscretization(DM dm, AppCtx *user)
763 {
764   PetscFE  fe;
765   DMLabel  fault;
766   PetscInt dim, Ncf = user->cohesiveFields, f;
767 
768   PetscFunctionBegin;
769   PetscCall(DMGetDimension(dm, &dim));
770   PetscCall(DMGetLabel(dm, "cohesive", &fault));
771   PetscCall(DMLabelView(fault, PETSC_VIEWER_STDOUT_WORLD));
772 
773   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, user->cellSimplex, "displacement_", PETSC_DETERMINE, &fe));
774   PetscCall(PetscFESetName(fe, "displacement"));
775   PetscCall(DMAddField(dm, NULL, (PetscObject)fe));
776   PetscCall(PetscFEDestroy(&fe));
777 
778   if (Ncf > 0) {
779     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim - 1, dim, user->cellSimplex, "faulttraction_", PETSC_DETERMINE, &fe));
780     PetscCall(PetscFESetName(fe, "fault traction"));
781     PetscCall(DMAddField(dm, fault, (PetscObject)fe));
782     PetscCall(PetscFEDestroy(&fe));
783   }
784   for (f = 1; f < Ncf; ++f) {
785     char name[256], opt[256];
786 
787     PetscCall(PetscSNPrintf(name, 256, "fault field %" PetscInt_FMT, f));
788     PetscCall(PetscSNPrintf(opt, 256, "faultfield_%" PetscInt_FMT "_", f));
789     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim - 1, dim, user->cellSimplex, opt, PETSC_DETERMINE, &fe));
790     PetscCall(PetscFESetName(fe, name));
791     PetscCall(DMAddField(dm, fault, (PetscObject)fe));
792     PetscCall(PetscFEDestroy(&fe));
793   }
794 
795   PetscCall(DMCreateDS(dm));
796   PetscFunctionReturn(PETSC_SUCCESS);
797 }
798 
CreateMesh(MPI_Comm comm,AppCtx * user,DM * dm)799 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
800 {
801   PetscInt    dim         = user->dim;
802   PetscBool   cellSimplex = user->cellSimplex, hasFault, hasFault2, hasParallelFault;
803   PetscMPIInt rank, size;
804   DMLabel     matLabel;
805 
806   PetscFunctionBegin;
807   PetscCallMPI(MPI_Comm_rank(comm, &rank));
808   PetscCallMPI(MPI_Comm_size(comm, &size));
809   PetscCall(DMCreate(comm, dm));
810   PetscCall(DMSetType(*dm, DMPLEX));
811   PetscCall(DMSetDimension(*dm, dim));
812   switch (dim) {
813   case 2:
814     if (cellSimplex) {
815       PetscCall(CreateSimplex_2D(comm, user->testNum, dm));
816     } else {
817       PetscCall(CreateQuad_2D(comm, user->testNum, dm));
818     }
819     break;
820   case 3:
821     if (cellSimplex) {
822       PetscCall(CreateSimplex_3D(comm, user, *dm));
823     } else {
824       PetscCall(CreateHex_3D(comm, user->testNum, dm));
825     }
826     break;
827   default:
828     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make hybrid meshes for dimension %" PetscInt_FMT, dim);
829   }
830   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "orig_"));
831   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
832   PetscCall(DMSetFromOptions(*dm));
833   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
834   PetscCall(DMHasLabel(*dm, "fault", &hasFault));
835   if (hasFault) {
836     DM      dmHybrid = NULL, dmInterface = NULL;
837     DMLabel faultLabel, faultBdLabel, hybridLabel, splitLabel;
838 
839     PetscCall(DMGetLabel(*dm, "fault", &faultLabel));
840     PetscCall(DMGetLabel(*dm, "faultBd", &faultBdLabel));
841     PetscCall(DMPlexCreateHybridMesh(*dm, faultLabel, faultBdLabel, 1, &hybridLabel, &splitLabel, &dmInterface, &dmHybrid));
842     PetscCall(DMLabelView(hybridLabel, PETSC_VIEWER_STDOUT_WORLD));
843     PetscCall(DMLabelDestroy(&hybridLabel));
844     PetscCall(DMLabelView(splitLabel, PETSC_VIEWER_STDOUT_WORLD));
845     PetscCall(DMLabelDestroy(&splitLabel));
846     PetscCall(DMViewFromOptions(dmInterface, NULL, "-dm_interface_view"));
847     PetscCall(DMDestroy(&dmInterface));
848     PetscCall(DMDestroy(dm));
849     *dm = dmHybrid;
850   }
851   PetscCall(DMHasLabel(*dm, "fault2", &hasFault2));
852   if (hasFault2) {
853     DM      dmHybrid = NULL;
854     DMLabel faultLabel, faultBdLabel, hybridLabel;
855 
856     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "faulted_"));
857     PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_pre"));
858     PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
859     PetscCall(DMSetFromOptions(*dm));
860     PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
861     PetscCall(DMGetLabel(*dm, "fault2", &faultLabel));
862     PetscCall(DMGetLabel(*dm, "fault2Bd", &faultBdLabel));
863     PetscCall(DMPlexCreateHybridMesh(*dm, faultLabel, faultBdLabel, 1, &hybridLabel, NULL, NULL, &dmHybrid));
864     PetscCall(DMLabelView(hybridLabel, PETSC_VIEWER_STDOUT_WORLD));
865     PetscCall(DMLabelDestroy(&hybridLabel));
866     PetscCall(DMDestroy(dm));
867     *dm = dmHybrid;
868   }
869   if (user->testPartition && size > 1) {
870     PetscPartitioner part;
871     PetscInt        *sizes  = NULL;
872     PetscInt        *points = NULL;
873 
874     if (rank == 0) {
875       if (dim == 2 && cellSimplex && size == 2) {
876         switch (user->testNum) {
877         case 0: {
878           PetscInt triSizes_p2[2]  = {1, 2};
879           PetscInt triPoints_p2[3] = {0, 1, 2};
880 
881           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
882           PetscCall(PetscArraycpy(sizes, triSizes_p2, 2));
883           PetscCall(PetscArraycpy(points, triPoints_p2, 3));
884           break;
885         }
886         case 3: {
887           PetscInt triSizes_p2[2]  = {3, 3};
888           PetscInt triPoints_p2[6] = {0, 1, 2, 3, 4, 5};
889 
890           PetscCall(PetscMalloc2(2, &sizes, 6, &points));
891           PetscCall(PetscArraycpy(sizes, triSizes_p2, 2));
892           PetscCall(PetscArraycpy(points, triPoints_p2, 6));
893           break;
894         }
895         default:
896           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for triangular mesh on 2 procs", user->testNum);
897         }
898       } else if (dim == 2 && cellSimplex && size == 6) {
899         switch (user->testNum) {
900         case 4: {
901           PetscInt triSizes_p6[6]  = {1, 1, 1, 1, 1, 1};
902           PetscInt triPoints_p6[6] = {0, 1, 2, 3, 4, 5};
903 
904           PetscCall(PetscMalloc2(6, &sizes, 6, &points));
905           PetscCall(PetscArraycpy(sizes, triSizes_p6, 6));
906           PetscCall(PetscArraycpy(points, triPoints_p6, 6));
907           break;
908         }
909         default:
910           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for triangular mesh on 6 procs", user->testNum);
911         }
912       } else if (dim == 2 && !cellSimplex && size == 2) {
913         switch (user->testNum) {
914         case 0: {
915           PetscInt quadSizes_p2[2]  = {1, 2};
916           PetscInt quadPoints_p2[3] = {0, 1, 2};
917 
918           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
919           PetscCall(PetscArraycpy(sizes, quadSizes_p2, 2));
920           PetscCall(PetscArraycpy(points, quadPoints_p2, 3));
921           break;
922         }
923         case 2: {
924           PetscInt quadSizes_p2[2]  = {1, 1};
925           PetscInt quadPoints_p2[2] = {0, 1};
926 
927           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
928           PetscCall(PetscArraycpy(sizes, quadSizes_p2, 2));
929           PetscCall(PetscArraycpy(points, quadPoints_p2, 2));
930           break;
931         }
932         case 3: {
933           PetscInt quadSizes_p2[2]  = {1, 1};
934           PetscInt quadPoints_p2[2] = {1, 0};
935 
936           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
937           PetscCall(PetscArraycpy(sizes, quadSizes_p2, 2));
938           PetscCall(PetscArraycpy(points, quadPoints_p2, 2));
939           break;
940         }
941         default:
942           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for quadrilateral mesh on 2 procs", user->testNum);
943         }
944       } else if (dim == 3 && cellSimplex && size == 2) {
945         switch (user->testNum) {
946         case 0: {
947           PetscInt tetSizes_p2[2]  = {1, 2};
948           PetscInt tetPoints_p2[3] = {0, 1, 2};
949 
950           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
951           PetscCall(PetscArraycpy(sizes, tetSizes_p2, 2));
952           PetscCall(PetscArraycpy(points, tetPoints_p2, 3));
953           break;
954         }
955         default:
956           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for teterehedral mesh on 2 procs", user->testNum);
957         }
958       } else if (dim == 3 && !cellSimplex && size == 2) {
959         switch (user->testNum) {
960         case 0: {
961           PetscInt hexSizes_p2[2]  = {1, 2};
962           PetscInt hexPoints_p2[3] = {0, 1, 2};
963 
964           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
965           PetscCall(PetscArraycpy(sizes, hexSizes_p2, 2));
966           PetscCall(PetscArraycpy(points, hexPoints_p2, 3));
967           break;
968         }
969         default:
970           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for hexahedral mesh on 2 procs", user->testNum);
971         }
972       } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test partition");
973     }
974     PetscCall(DMPlexGetPartitioner(*dm, &part));
975     PetscCall(PetscPartitionerSetType(part, PETSCPARTITIONERSHELL));
976     PetscCall(PetscPartitionerShellSetPartition(part, size, sizes, points));
977     PetscCall(PetscFree2(sizes, points));
978   }
979   PetscCall(DMGetLabel(*dm, "material", &matLabel));
980   if (matLabel) PetscCall(DMPlexLabelComplete(*dm, matLabel));
981   {
982     DM pdm = NULL;
983 
984     /* Distribute mesh over processes */
985     PetscCall(DMPlexDistribute(*dm, 0, NULL, &pdm));
986     if (pdm) {
987       PetscCall(DMViewFromOptions(pdm, NULL, "-dm_view"));
988       PetscCall(DMDestroy(dm));
989       *dm = pdm;
990     }
991   }
992   PetscCall(DMHasLabel(*dm, "pfault", &hasParallelFault));
993   if (hasParallelFault) {
994     DM      dmHybrid = NULL, dmInterface;
995     DMLabel faultLabel, faultBdLabel, hybridLabel;
996 
997     PetscCall(DMGetLabel(*dm, "pfault", &faultLabel));
998     PetscCall(DMGetLabel(*dm, "pfaultBd", &faultBdLabel));
999     PetscCall(DMPlexCreateHybridMesh(*dm, faultLabel, faultBdLabel, 1, &hybridLabel, NULL, &dmInterface, &dmHybrid));
1000     PetscCall(DMViewFromOptions(dmInterface, NULL, "-dm_fault_view"));
1001     {
1002       PetscViewer viewer;
1003       PetscMPIInt rank;
1004 
1005       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)*dm), &rank));
1006       PetscCall(PetscViewerGetSubViewer(PETSC_VIEWER_STDOUT_WORLD, PETSC_COMM_SELF, &viewer));
1007       PetscCall(PetscViewerASCIIPrintf(viewer, "Rank %d\n", rank));
1008       PetscCall(DMLabelView(hybridLabel, viewer));
1009       PetscCall(PetscViewerRestoreSubViewer(PETSC_VIEWER_STDOUT_WORLD, PETSC_COMM_SELF, &viewer));
1010     }
1011     PetscCall(DMLabelDestroy(&hybridLabel));
1012     PetscCall(DMDestroy(&dmInterface));
1013     PetscCall(DMDestroy(dm));
1014     *dm = dmHybrid;
1015   }
1016   PetscCall(PetscObjectSetName((PetscObject)*dm, "Hybrid Mesh"));
1017   PetscCall(CreateFaultLabel(*dm));
1018   PetscCall(CreateDiscretization(*dm, user));
1019   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_pre"));
1020   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
1021   PetscCall(DMSetFromOptions(*dm));
1022   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
1023   PetscFunctionReturn(PETSC_SUCCESS);
1024 }
1025 
TestMesh(DM dm,AppCtx * user)1026 static PetscErrorCode TestMesh(DM dm, AppCtx *user)
1027 {
1028   PetscFunctionBegin;
1029   PetscCall(DMPlexCheckSymmetry(dm));
1030   PetscCall(DMPlexCheckSkeleton(dm, 0));
1031   PetscCall(DMPlexCheckFaces(dm, 0));
1032   PetscFunctionReturn(PETSC_SUCCESS);
1033 }
1034 
TestDiscretization(DM dm,AppCtx * user)1035 static PetscErrorCode TestDiscretization(DM dm, AppCtx *user)
1036 {
1037   PetscSection s;
1038 
1039   PetscFunctionBegin;
1040   PetscCall(DMGetLocalSection(dm, &s));
1041   PetscCall(PetscObjectViewFromOptions((PetscObject)s, NULL, "-local_section_view"));
1042   PetscFunctionReturn(PETSC_SUCCESS);
1043 }
1044 
r(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)1045 static PetscErrorCode r(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
1046 {
1047   PetscInt d;
1048   for (d = 0; d < dim; ++d) u[d] = x[d];
1049   return PETSC_SUCCESS;
1050 }
1051 
rp1(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)1052 static PetscErrorCode rp1(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
1053 {
1054   PetscInt d;
1055   for (d = 0; d < dim; ++d) u[d] = x[d] + (d > 0 ? 1.0 : 0.0);
1056   return PETSC_SUCCESS;
1057 }
1058 
phi(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)1059 static PetscErrorCode phi(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
1060 {
1061   PetscInt d;
1062   u[0] = -x[1];
1063   u[1] = x[0];
1064   for (d = 2; d < dim; ++d) u[d] = x[d];
1065   return PETSC_SUCCESS;
1066 }
1067 
add_fields(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])1068 static void add_fields(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
1069 {
1070   PetscInt       d;
1071   const PetscInt offN = 0;
1072   const PetscInt offP = dim;
1073   for (d = 0; d < dim; ++d) f[d] = u[offN + d] + u[offP + d];
1074 }
1075 
normal_field(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])1076 static void normal_field(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
1077 {
1078   PetscInt d;
1079   for (d = 0; d < dim; ++d) f[d] = n[d];
1080 }
1081 
1082 /* \lambda \cdot (\psi_u^- - \psi_u^+) */
f0_bd_u_neg(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1083 static void f0_bd_u_neg(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1084 {
1085   const PetscInt Nc = dim + 1;
1086   for (PetscInt c = 0; c < Nc; ++c) f0[c] = -u[uOff[1] + c];
1087 }
1088 
f0_bd_u_pos(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1089 static void f0_bd_u_pos(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1090 {
1091   const PetscInt Nc = dim + 1;
1092   for (PetscInt c = 0; c < Nc; ++c) f0[c] = u[uOff[1] + c];
1093 }
1094 
1095 /* (d - u^+ + u^-) \cdot \psi_\lambda */
f0_bd_l(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])1096 static void f0_bd_l(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1097 {
1098   const PetscInt Nc = uOff[2] - uOff[1];
1099 
1100   for (PetscInt c = 0; c < Nc; ++c) f0[c] = (c > 0 ? 1.0 : 0.0) + u[c] - u[Nc + c];
1101 }
1102 
1103 /* \psi_lambda \cdot (\psi_u^- - \psi_u^+) */
g0_bd_ul_neg(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])1104 static void g0_bd_ul_neg(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1105 {
1106   const PetscInt Nc = dim + 1;
1107   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = -1.0;
1108 }
1109 
g0_bd_ul_pos(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])1110 static void g0_bd_ul_pos(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1111 {
1112   const PetscInt Nc = dim + 1;
1113   for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0;
1114 }
1115 
1116 /* (-\psi_u^+ + \psi_u^-) \cdot \psi_\lambda */
g0_bd_lu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])1117 static void g0_bd_lu(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
1118 {
1119   const PetscInt Nc = uOff[2] - uOff[1];
1120 
1121   for (PetscInt c = 0; c < Nc; ++c) {
1122     g0[c * Nc + c]           = -1.0;
1123     g0[Nc * Nc + c * Nc + c] = 1.0;
1124   }
1125 }
1126 
TestAssembly(DM dm,AppCtx * user)1127 static PetscErrorCode TestAssembly(DM dm, AppCtx *user)
1128 {
1129   Mat           J;
1130   Vec           locX, locF, locW;
1131   PetscDS       probh;
1132   DMLabel       fault, material;
1133   DM            dmFault;
1134   IS            cohesiveCells;
1135   PetscFE       fe;
1136   PetscWeakForm wf;
1137   PetscFormKey  keys[3];
1138   PetscErrorCode (*initialGuess[2])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], PetscCtx ctx);
1139   PetscInt    dim, Nf, cMax, cEnd, id;
1140   PetscMPIInt rank;
1141 
1142   PetscFunctionBegin;
1143   if (!user->testAssembly) PetscFunctionReturn(PETSC_SUCCESS);
1144   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1145   PetscCall(DMGetDimension(dm, &dim));
1146   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, NULL, &cMax));
1147   PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &cEnd));
1148   PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cMax, cMax, 1, &cohesiveCells));
1149   PetscCall(DMGetLabel(dm, "cohesive", &fault));
1150   PetscCall(DMGetLocalVector(dm, &locX));
1151   PetscCall(PetscObjectSetName((PetscObject)locX, "Local Solution"));
1152   PetscCall(DMGetLocalVector(dm, &locF));
1153   PetscCall(PetscObjectSetName((PetscObject)locF, "Local Residual"));
1154   PetscCall(DMCreateMatrix(dm, &J));
1155   PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian"));
1156 
1157   /* The initial guess has displacement shifted by one unit in each fault parallel direction across the fault */
1158   PetscCall(DMGetLabel(dm, "material", &material));
1159   id              = 1;
1160   initialGuess[0] = r;
1161   initialGuess[1] = NULL;
1162   PetscCall(DMProjectFunctionLabelLocal(dm, 0.0, material, 1, &id, PETSC_DETERMINE, NULL, initialGuess, NULL, INSERT_VALUES, locX));
1163   id              = 2;
1164   initialGuess[0] = rp1;
1165   initialGuess[1] = NULL;
1166   PetscCall(DMProjectFunctionLabelLocal(dm, 0.0, material, 1, &id, PETSC_DETERMINE, NULL, initialGuess, NULL, INSERT_VALUES, locX));
1167   id              = 1;
1168   initialGuess[0] = NULL;
1169   initialGuess[1] = phi;
1170   PetscCall(DMProjectFunctionLabelLocal(dm, 0.0, fault, 1, &id, PETSC_DETERMINE, NULL, initialGuess, NULL, INSERT_VALUES, locX));
1171   PetscCall(VecViewFromOptions(locX, NULL, "-local_solution_view"));
1172 
1173   /* Test projection to fault mesh */
1174   PetscCall(DMPlexCreateCohesiveSubmesh(dm, PETSC_FALSE, NULL, 0, &dmFault));
1175   PetscCall(DMViewFromOptions(dmFault, NULL, "-fault_view"));
1176   PetscCall(DMPlexOrient(dmFault));
1177   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim - 1, dim, user->cellSimplex, "fault_field_", PETSC_DETERMINE, &fe));
1178   PetscCall(PetscFESetName(fe, "fault_field"));
1179   PetscCall(DMAddField(dmFault, NULL, (PetscObject)fe));
1180   PetscCall(PetscFEDestroy(&fe));
1181   PetscCall(DMCreateDS(dmFault));
1182   PetscCall(DMGetLocalVector(dmFault, &locW));
1183   PetscCall(DMViewFromOptions(dmFault, NULL, "-cohesive_view"));
1184   void (*faultFuncs[1])(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
1185 
1186   DMLabel  depthLabel;
1187   PetscInt depth;
1188   PetscCall(DMPlexGetDepthLabel(dmFault, &depthLabel));
1189   PetscCall(DMPlexGetDepth(dmFault, &depth));
1190   id = depth - 1;
1191   /* w = r + rp1 */
1192   faultFuncs[0] = add_fields;
1193   PetscCall(DMProjectBdFieldLabelLocal(dmFault, 0.0, depthLabel, 1, &id, PETSC_DETERMINE, NULL, locX, faultFuncs, INSERT_VALUES, locW));
1194   PetscCall(VecViewFromOptions(locW, NULL, "-local_projection_view"));
1195 
1196   /* w = fault_normal */
1197   faultFuncs[0] = normal_field;
1198   PetscCall(DMProjectBdFieldLabelLocal(dmFault, 0.0, depthLabel, 1, &id, PETSC_DETERMINE, NULL, locX, faultFuncs, INSERT_VALUES, locW));
1199   PetscCall(VecViewFromOptions(locW, NULL, "-local_projection_view"));
1200   PetscCall(DMRestoreLocalVector(dmFault, &locW));
1201   PetscCall(DMDestroy(&dmFault));
1202 
1203   PetscCall(DMGetCellDS(dm, cMax, &probh, NULL));
1204   PetscCall(PetscDSGetWeakForm(probh, &wf));
1205   PetscCall(PetscDSGetNumFields(probh, &Nf));
1206   PetscCall(PetscWeakFormSetIndexBdResidual(wf, material, 1, 0, 0, 0, f0_bd_u_neg, 0, NULL));
1207   PetscCall(PetscWeakFormSetIndexBdResidual(wf, material, 2, 0, 0, 0, f0_bd_u_pos, 0, NULL));
1208   PetscCall(PetscWeakFormSetIndexBdJacobian(wf, material, 1, 0, 1, 0, 0, g0_bd_ul_neg, 0, NULL, 0, NULL, 0, NULL));
1209   PetscCall(PetscWeakFormSetIndexBdJacobian(wf, material, 2, 0, 1, 0, 0, g0_bd_ul_pos, 0, NULL, 0, NULL, 0, NULL));
1210   if (Nf > 1) {
1211     PetscCall(PetscWeakFormSetIndexBdResidual(wf, fault, 1, 1, 0, 0, f0_bd_l, 0, NULL));
1212     PetscCall(PetscWeakFormSetIndexBdJacobian(wf, fault, 1, 1, 0, 0, 0, g0_bd_lu, 0, NULL, 0, NULL, 0, NULL));
1213   }
1214   if (rank == 0) PetscCall(PetscDSView(probh, NULL));
1215 
1216   keys[0].label = material;
1217   keys[0].value = 1;
1218   keys[0].field = 0;
1219   keys[0].part  = 0;
1220   keys[1].label = material;
1221   keys[1].value = 2;
1222   keys[1].field = 0;
1223   keys[1].part  = 0;
1224   keys[2].label = fault;
1225   keys[2].value = 1;
1226   keys[2].field = 1;
1227   keys[2].part  = 0;
1228   PetscCall(VecSet(locF, 0.));
1229   PetscCall(DMPlexComputeResidualHybridByKey(dm, keys, cohesiveCells, 0.0, locX, NULL, 0.0, locF, user));
1230   PetscCall(VecViewFromOptions(locF, NULL, "-local_residual_view"));
1231   PetscCall(MatZeroEntries(J));
1232   PetscCall(DMPlexComputeJacobianHybridByKey(dm, keys, cohesiveCells, 0.0, 0.0, locX, NULL, J, J, user));
1233   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1234   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
1235   PetscCall(MatViewFromOptions(J, NULL, "-local_jacobian_view"));
1236 
1237   PetscCall(DMRestoreLocalVector(dm, &locX));
1238   PetscCall(DMRestoreLocalVector(dm, &locF));
1239   PetscCall(MatDestroy(&J));
1240   PetscCall(ISDestroy(&cohesiveCells));
1241 
1242   if (cMax < cEnd) {
1243     PetscDS         ds;
1244     PetscFE         fe;
1245     PetscQuadrature quad;
1246     IS             *perm;
1247     const PetscInt *cone;
1248     PetscInt        Na, a;
1249 
1250     PetscCall(DMPlexGetCone(dm, cMax, &cone));
1251     PetscCall(DMGetCellDS(dm, cMax, &ds, NULL));
1252     PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
1253     PetscCall(PetscFEGetQuadrature(fe, &quad));
1254     PetscCall(PetscQuadratureComputePermutations(quad, &Na, &perm));
1255     for (a = 0; a < Na; ++a) PetscCall(ISDestroy(&perm[a]));
1256     PetscCall(PetscFree(perm));
1257   }
1258   PetscFunctionReturn(PETSC_SUCCESS);
1259 }
1260 
main(int argc,char ** argv)1261 int main(int argc, char **argv)
1262 {
1263   DM     dm;
1264   AppCtx user; /* user-defined work context */
1265 
1266   PetscFunctionBeginUser;
1267   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
1268   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
1269   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
1270   PetscCall(TestMesh(dm, &user));
1271   PetscCall(TestDiscretization(dm, &user));
1272   PetscCall(TestAssembly(dm, &user));
1273   PetscCall(DMDestroy(&dm));
1274   PetscCall(PetscFinalize());
1275   return 0;
1276 }
1277 
1278 /*TEST
1279   testset:
1280     args: -orig_dm_plex_check_all -dm_plex_check_all \
1281           -displacement_petscspace_degree 1 -faulttraction_petscspace_degree 1 -local_section_view \
1282           -local_solution_view -local_residual_view -local_jacobian_view
1283     test:
1284       suffix: tri_0
1285       args: -dim 2
1286       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1287     test:
1288       suffix: tri_0_perm
1289       args: -dim 2 -dm_reorder_section -dm_reorder_section_type cohesive
1290       filter: sed -e "s/_start//g" -e "s/f0_bd_u//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul//g" -e "s/g0_bd_lu//g" -e "s/_neg//g" -e "s/_pos//g" -e "s~_ZL.*~~g"
1291     test:
1292       suffix: tri_t1_0
1293       args: -dim 2 -test_num 1
1294       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1295     test:
1296       suffix: tri_t1_0_perm
1297       args: -dim 2 -test_num 1 -dm_reorder_section -dm_reorder_section_type cohesive
1298       filter: sed -e "s/_start//g" -e "s/f0_bd_u//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul//g" -e "s/g0_bd_lu//g" -e "s/_neg//g" -e "s/_pos//g" -e "s~_ZL.*~~g"
1299     test:
1300       suffix: tri_t2_0
1301       args: -dim 2 -test_num 2
1302       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1303 
1304     test:
1305       suffix: tri_t5_0
1306       args: -dim 2 -test_num 5
1307       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1308 
1309     test:
1310       suffix: tet_0
1311       args: -dim 3
1312       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1313 
1314     test:
1315       suffix: tet_t1_0
1316       args: -dim 3 -test_num 1
1317       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1318 
1319   testset:
1320     args: -orig_dm_plex_check_all -dm_plex_check_all \
1321           -displacement_petscspace_degree 1 -faulttraction_petscspace_degree 1
1322     test:
1323       suffix: tet_1
1324       nsize: 2
1325       args: -dim 3
1326       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1327 
1328     test:
1329       suffix: tri_1
1330       nsize: 2
1331       args: -dim 2
1332       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1333 
1334     test:
1335       suffix: tri_t3_0
1336       nsize: 2
1337       args: -dim 2 -test_num 3
1338       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1339 
1340     test:
1341       suffix: tri_t4_0
1342       nsize: 6
1343       args: -dim 2 -test_num 4
1344       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1345 
1346   testset:
1347     args: -orig_dm_plex_check_all -dm_plex_check_all \
1348           -displacement_petscspace_degree 1 -faulttraction_petscspace_degree 1
1349     # 2D Quads
1350     test:
1351       suffix: quad_0
1352       args: -dim 2 -cell_simplex 0
1353       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1354 
1355     test:
1356       suffix: quad_1
1357       nsize: 2
1358       args: -dim 2 -cell_simplex 0
1359       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1360 
1361     # Caanot run the assembly test because we cannot orient a fault mesh in a T-shape
1362     test:
1363       suffix: quad_t1_0
1364       args: -dim 2 -cell_simplex 0 -test_num 1 -faulted_dm_plex_check_all -test_assembly 0
1365       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1366 
1367     test:
1368       suffix: quad_t2_0
1369       nsize: 2
1370       args: -dim 2 -cell_simplex 0 -test_num 2
1371       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1372 
1373     test:
1374       # TODO: The PetscSF is wrong here (connects to wrong side of split)
1375       suffix: quad_t3_0
1376       nsize: 2
1377       args: -dim 2 -cell_simplex 0 -test_num 3
1378       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1379 
1380     # 3D Hex
1381     test:
1382       suffix: hex_0
1383       args: -dim 3 -cell_simplex 0
1384       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1385     test:
1386       suffix: hex_1
1387       nsize: 2
1388       args: -dim 3 -cell_simplex 0
1389       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1390     test:
1391       suffix: hex_t1_0
1392       args: -dim 3 -cell_simplex 0 -test_num 1
1393       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1394     test:
1395       suffix: hex_t2_0
1396       args: -dim 3 -cell_simplex 0 -test_num 2
1397       filter: sed -e "s/_start//g" -e "s/f0_bd_u_neg//g" -e "s/f0_bd_u_pos//g" -e "s/f0_bd_l//g" -e "s/g0_bd_ul_neg//g" -e "s/g0_bd_ul_pos//g" -e "s/g0_bd_lu//g" -e "s~_ZL.*~~g"
1398 
1399 TEST*/
1400