xref: /petsc/src/dm/impls/plex/tests/ex4.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1 static char help[] = "Tests for refinement of meshes created by hand\n\n";
2 
3 #include <petscdmplex.h>
4 
5 typedef struct {
6   PetscInt  debug;         /* The debugging level */
7   PetscInt  dim;           /* The topological mesh dimension */
8   PetscBool cellHybrid;    /* Use a hybrid mesh */
9   PetscBool cellSimplex;   /* Use simplices or hexes */
10   PetscBool testPartition; /* Use a fixed partitioning for testing */
11   PetscInt  testNum;       /* The particular mesh to test */
12   PetscBool uninterpolate; /* Uninterpolate the mesh at the end */
13   PetscBool reinterpolate; /* Reinterpolate the mesh at the end */
14 } AppCtx;
15 
16 PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
17 {
18   PetscFunctionBegin;
19   options->debug         = 0;
20   options->dim           = 2;
21   options->cellHybrid    = PETSC_TRUE;
22   options->cellSimplex   = PETSC_TRUE;
23   options->testPartition = PETSC_TRUE;
24   options->testNum       = 0;
25   options->uninterpolate = PETSC_FALSE;
26   options->reinterpolate = PETSC_FALSE;
27 
28   PetscOptionsBegin(comm, "", "Meshing Problem Options", "DMPLEX");
29   PetscCall(PetscOptionsBoundedInt("-debug", "The debugging level", "ex4.c", options->debug, &options->debug, NULL, 0));
30   PetscCall(PetscOptionsRangeInt("-dim", "The topological mesh dimension", "ex4.c", options->dim, &options->dim, NULL, 1, 3));
31   PetscCall(PetscOptionsBool("-cell_hybrid", "Use a hybrid mesh", "ex4.c", options->cellHybrid, &options->cellHybrid, NULL));
32   PetscCall(PetscOptionsBool("-cell_simplex", "Use simplices if true, otherwise hexes", "ex4.c", options->cellSimplex, &options->cellSimplex, NULL));
33   PetscCall(PetscOptionsBool("-test_partition", "Use a fixed partition for testing", "ex4.c", options->testPartition, &options->testPartition, NULL));
34   PetscCall(PetscOptionsBoundedInt("-test_num", "The particular mesh to test", "ex4.c", options->testNum, &options->testNum, NULL, 0));
35   PetscCall(PetscOptionsBool("-uninterpolate", "Uninterpolate the mesh at the end", "ex4.c", options->uninterpolate, &options->uninterpolate, NULL));
36   PetscCall(PetscOptionsBool("-reinterpolate", "Reinterpolate the mesh at the end", "ex4.c", options->reinterpolate, &options->reinterpolate, NULL));
37   PetscOptionsEnd();
38   PetscFunctionReturn(0);
39 }
40 
41 /* Two segments
42 
43   2-------0-------3-------1-------4
44 
45 become
46 
47   4---0---7---1---5---2---8---3---6
48 
49 */
50 PetscErrorCode CreateSimplex_1D(MPI_Comm comm, DM *dm)
51 {
52   PetscInt    depth = 1;
53   PetscMPIInt rank;
54 
55   PetscFunctionBegin;
56   PetscCallMPI(MPI_Comm_rank(comm, &rank));
57   if (rank == 0) {
58     PetscInt    numPoints[2]         = {3, 2};
59     PetscInt    coneSize[5]          = {2, 2, 0, 0, 0};
60     PetscInt    cones[4]             = {2, 3, 3, 4};
61     PetscInt    coneOrientations[16] = {0, 0, 0, 0};
62     PetscScalar vertexCoords[3]      = {-1.0, 0.0, 1.0};
63 
64     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
65   } else {
66     PetscInt numPoints[2] = {0, 0};
67 
68     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, NULL, NULL, NULL, NULL));
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 /* Two triangles
74         4
75       / | \
76      8  |  10
77     /   |   \
78    2  0 7  1 5
79     \   |   /
80      6  |  9
81       \ | /
82         3
83 
84 Becomes
85            10
86           / | \
87         21  |  26
88         /   |   \
89       14 2 20 4  16
90       /|\   |   /|\
91     22 | 28 | 32 | 25
92     /  |  \ | /  | 6\
93    8  29 3 13  7 31  11
94     \0 |  / | \  |  /
95     17 | 27 | 30 | 24
96       \|/   |   \|/
97       12 1 19 5  15
98         \   |   /
99         18  |  23
100           \ | /
101             9
102 */
103 PetscErrorCode CreateSimplex_2D(MPI_Comm comm, DM *dm)
104 {
105   PetscInt    depth = 2;
106   PetscMPIInt rank;
107 
108   PetscFunctionBegin;
109   PetscCallMPI(MPI_Comm_rank(comm, &rank));
110   if (rank == 0) {
111     PetscInt    numPoints[3]         = {4, 5, 2};
112     PetscInt    coneSize[11]         = {3, 3, 0, 0, 0, 0, 2, 2, 2, 2, 2};
113     PetscInt    cones[16]            = {6, 7, 8, 7, 9, 10, 2, 3, 3, 4, 4, 2, 3, 5, 5, 4};
114     PetscInt    coneOrientations[16] = {0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
115     PetscScalar vertexCoords[8]      = {-0.5, 0.0, 0.0, -0.5, 0.0, 0.5, 0.5, 0.0};
116 
117     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
118   } else {
119     PetscInt numPoints[3] = {0, 0, 0};
120 
121     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, NULL, NULL, NULL, NULL));
122   }
123   PetscFunctionReturn(0);
124 }
125 
126 /* Two triangles separated by a zero-volume cell with 4 vertices/2 edges
127         5--16--8
128       / |      | \
129     11  |      |  12
130     /   |      |   \
131    3  0 10  2 14 1  6
132     \   |      |   /
133      9  |      |  13
134       \ |      | /
135         4--15--7
136 */
137 PetscErrorCode CreateSimplexHybrid_2D(MPI_Comm comm, PetscInt testNum, DM *dm)
138 {
139   DM          idm, hdm = NULL;
140   DMLabel     faultLabel, hybridLabel;
141   PetscInt    p;
142   PetscMPIInt rank;
143 
144   PetscFunctionBegin;
145   PetscCallMPI(MPI_Comm_rank(comm, &rank));
146   if (rank == 0) {
147     switch (testNum) {
148     case 0: {
149       PetscInt    numPoints[2]        = {4, 2};
150       PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
151       PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
152       PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
153       PetscScalar vertexCoords[8]     = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, 1.0, 0.5};
154       PetscInt    faultPoints[2]      = {3, 4};
155 
156       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
157       for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
158     } break;
159     case 1: {
160       PetscInt    numPoints[2]         = {5, 4};
161       PetscInt    coneSize[9]          = {3, 3, 3, 3, 0, 0, 0, 0, 0};
162       PetscInt    cones[12]            = {4, 5, 6, 6, 7, 4, 6, 5, 8, 6, 8, 7};
163       PetscInt    coneOrientations[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
164       PetscScalar vertexCoords[10]     = {-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0};
165       PetscInt    faultPoints[3]       = {5, 6, 7};
166 
167       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
168       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
169     } break;
170     default:
171       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
172     }
173     PetscCall(DMPlexInterpolate(*dm, &idm));
174     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
175     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
176     PetscCall(DMSetFromOptions(idm));
177     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
178     PetscCall(DMGetLabel(*dm, "fault", &faultLabel));
179     PetscCall(DMPlexCreateHybridMesh(idm, faultLabel, NULL, 0, &hybridLabel, NULL, NULL, &hdm));
180     PetscCall(DMLabelDestroy(&hybridLabel));
181     PetscCall(DMDestroy(&idm));
182     PetscCall(DMDestroy(dm));
183     *dm = hdm;
184   } else {
185     PetscInt numPoints[2] = {0, 0};
186 
187     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
188     PetscCall(DMPlexInterpolate(*dm, &idm));
189     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
190     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
191     PetscCall(DMSetFromOptions(idm));
192     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
193     PetscCall(DMPlexCreateHybridMesh(idm, NULL, NULL, 0, NULL, NULL, NULL, &hdm));
194     PetscCall(DMDestroy(&idm));
195     PetscCall(DMDestroy(dm));
196     *dm = hdm;
197   }
198   PetscFunctionReturn(0);
199 }
200 
201 /* Two quadrilaterals
202 
203   5----10-----4----14-----7
204   |           |           |
205   |           |           |
206   |           |           |
207  11     0     9     1     13
208   |           |           |
209   |           |           |
210   |           |           |
211   2-----8-----3----12-----6
212 */
213 PetscErrorCode CreateTensorProduct_2D(MPI_Comm comm, PetscInt testNum, DM *dm)
214 {
215   PetscInt    depth = 2;
216   PetscMPIInt rank;
217 
218   PetscFunctionBegin;
219   PetscCallMPI(MPI_Comm_rank(comm, &rank));
220   if (rank == 0) {
221     PetscInt    numPoints[3]         = {6, 7, 2};
222     PetscInt    coneSize[15]         = {4, 4, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2};
223     PetscInt    cones[22]            = {8, 9, 10, 11, 12, 13, 14, 9, 2, 3, 3, 4, 4, 5, 5, 2, 3, 6, 6, 7, 7, 4};
224     PetscInt    coneOrientations[22] = {0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
225     PetscScalar vertexCoords[12]     = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5};
226 
227     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
228   } else {
229     PetscInt numPoints[3] = {0, 0, 0};
230 
231     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, NULL, NULL, NULL, NULL));
232   }
233   PetscFunctionReturn(0);
234 }
235 
236 PetscErrorCode CreateTensorProductHybrid_2D(MPI_Comm comm, PetscInt testNum, DM *dm)
237 {
238   DM          idm, hdm = NULL;
239   DMLabel     faultLabel, hybridLabel;
240   PetscInt    p;
241   PetscMPIInt rank;
242 
243   PetscFunctionBegin;
244   PetscCallMPI(MPI_Comm_rank(comm, &rank));
245   if (rank == 0) {
246     PetscInt numPoints[2] = {6, 2};
247     PetscInt coneSize[8]  = {4, 4, 0, 0, 0, 0, 0, 0};
248     PetscInt cones[8]     = {
249       2, 3, 4, 5, 3, 6, 7, 4,
250     };
251     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
252     PetscScalar vertexCoords[12]    = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5};
253     PetscInt    faultPoints[2]      = {3, 4};
254 
255     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
256     for (p = 0; p < 2; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
257     PetscCall(DMPlexInterpolate(*dm, &idm));
258     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
259     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
260     PetscCall(DMSetFromOptions(idm));
261     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
262     PetscCall(DMGetLabel(*dm, "fault", &faultLabel));
263     PetscCall(DMPlexCreateHybridMesh(idm, faultLabel, NULL, 0, &hybridLabel, NULL, NULL, &hdm));
264     PetscCall(DMLabelDestroy(&hybridLabel));
265   } else {
266     PetscInt numPoints[3] = {0, 0, 0};
267 
268     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
269     PetscCall(DMPlexInterpolate(*dm, &idm));
270     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
271     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
272     PetscCall(DMSetFromOptions(idm));
273     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
274     PetscCall(DMPlexCreateHybridMesh(idm, NULL, NULL, 0, NULL, NULL, NULL, &hdm));
275   }
276   PetscCall(DMDestroy(&idm));
277   PetscCall(DMDestroy(dm));
278   *dm = hdm;
279   PetscFunctionReturn(0);
280 }
281 
282 /* Two tetrahedrons
283 
284  cell   5          5______    cell
285  0    / | \        |\      \     1
286     17  |  18      | 18 13  21
287     /8 19 10\     19  \      \
288    2-14-|----4     |   4--22--6
289     \ 9 | 7 /      |10 /      /
290     16  |  15      | 15  12 20
291       \ | /        |/      /
292         3          3------
293 */
294 PetscErrorCode CreateSimplex_3D(MPI_Comm comm, PetscInt testNum, DM *dm)
295 {
296   DM          idm;
297   PetscInt    depth = 3;
298   PetscMPIInt rank;
299 
300   PetscFunctionBegin;
301   PetscCallMPI(MPI_Comm_rank(comm, &rank));
302   if (rank == 0) {
303     switch (testNum) {
304     case 0: {
305       PetscInt    numPoints[4]         = {5, 9, 7, 2};
306       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};
307       PetscInt    cones[47]            = {7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 14, 16, 19, 17, 15, 18, 19, 20, 21, 19, 15, 22, 20, 18, 21, 22, 2, 4, 4, 3, 3, 2, 2, 5, 5, 4, 3, 5, 3, 6, 6, 5, 4, 6};
308       PetscInt    coneOrientations[47] = {0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, -1, -1, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
309       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};
310 
311       PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
312     } break;
313     case 1: {
314       PetscInt    numPoints[2]        = {5, 2};
315       PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
316       PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
317       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
318       PetscScalar vertexCoords[15]    = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};
319 
320       depth = 1;
321       PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
322       PetscCall(DMPlexInterpolate(*dm, &idm));
323       PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
324       PetscCall(DMDestroy(dm));
325       *dm = idm;
326     } break;
327     case 2: {
328       PetscInt    numPoints[2]        = {4, 1};
329       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
330       PetscInt    cones[4]            = {2, 3, 4, 1};
331       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
332       PetscScalar vertexCoords[12]    = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
333 
334       depth = 1;
335       PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, coneSize, cones, coneOrientations, vertexCoords));
336       PetscCall(DMPlexInterpolate(*dm, &idm));
337       PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
338       PetscCall(DMDestroy(dm));
339       *dm = idm;
340     } break;
341     default:
342       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
343     }
344   } else {
345     PetscInt numPoints[4] = {0, 0, 0, 0};
346 
347     PetscCall(DMPlexCreateFromDAG(*dm, depth, numPoints, NULL, NULL, NULL, NULL));
348     switch (testNum) {
349     case 1:
350       PetscCall(DMPlexInterpolate(*dm, &idm));
351       PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
352       PetscCall(DMDestroy(dm));
353       *dm = idm;
354       break;
355     }
356   }
357   PetscFunctionReturn(0);
358 }
359 
360 /* Two tetrahedrons separated by a zero-volume cell with 6 vertices
361 
362  cell   6 ___33___10______    cell
363  0    / | \        |\      \     1
364     21  |  23      | 29     27
365     /12 24 14\    30  \      \
366    3-20-|----5--32-|---9--26--7
367     \ 13| 11/      |18 /      /
368     19  |  22      | 28     25
369       \ | /        |/      /
370         4----31----8------
371          cell 2
372 */
373 PetscErrorCode CreateSimplexHybrid_3D(MPI_Comm comm, PetscInt testNum, DM *dm)
374 {
375   DM          idm, hdm = NULL;
376   DMLabel     faultLabel, hybridLabel;
377   PetscInt    p;
378   PetscMPIInt rank;
379 
380   PetscFunctionBegin;
381   PetscCallMPI(MPI_Comm_rank(comm, &rank));
382   if (rank == 0) {
383     switch (testNum) {
384     case 0: {
385       PetscInt    numPoints[2]        = {5, 2};
386       PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
387       PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
388       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
389       PetscScalar vertexCoords[15]    = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};
390       PetscInt    faultPoints[3]      = {3, 4, 5};
391 
392       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
393       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
394     } break;
395     case 1: {
396       /* Tets 0,3,5 and 1,2,4 */
397       PetscInt    numPoints[2]         = {9, 6};
398       PetscInt    coneSize[15]         = {4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
399       PetscInt    cones[24]            = {7, 8, 9, 6, 11, 13, 9, 14, 10, 11, 13, 9, 9, 10, 11, 7, 9, 14, 13, 12, 7, 8, 11, 9};
400       PetscInt    coneOrientations[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
401       PetscScalar vertexCoords[27]     = {-2.0, -1.0, 0.0, -2.0, 0.0, 0.0, -2.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, -1.0, 0.0, 2.0, 0.0, 0.0, 2.0, 0.0, 1.0};
402       PetscInt    faultPoints[3]       = {9, 10, 11};
403 
404       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
405       for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
406     } break;
407     default:
408       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
409     }
410     PetscCall(DMPlexInterpolate(*dm, &idm));
411     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
412     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
413     PetscCall(DMSetFromOptions(idm));
414     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
415     PetscCall(DMGetLabel(*dm, "fault", &faultLabel));
416     PetscCall(DMPlexCreateHybridMesh(idm, faultLabel, NULL, 0, &hybridLabel, NULL, NULL, &hdm));
417     PetscCall(DMLabelDestroy(&hybridLabel));
418     PetscCall(DMDestroy(&idm));
419     PetscCall(DMDestroy(dm));
420     *dm = hdm;
421   } else {
422     PetscInt numPoints[4] = {0, 0, 0, 0};
423 
424     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
425     PetscCall(DMPlexInterpolate(*dm, &idm));
426     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
427     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
428     PetscCall(DMSetFromOptions(idm));
429     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
430     PetscCall(DMPlexCreateHybridMesh(idm, NULL, NULL, 0, NULL, NULL, NULL, &hdm));
431     PetscCall(DMDestroy(&idm));
432     PetscCall(DMDestroy(dm));
433     *dm = hdm;
434   }
435   PetscFunctionReturn(0);
436 }
437 
438 PetscErrorCode CreateTensorProduct_3D(MPI_Comm comm, PetscInt testNum, DM *dm)
439 {
440   DM          idm;
441   PetscMPIInt rank;
442 
443   PetscFunctionBegin;
444   PetscCallMPI(MPI_Comm_rank(comm, &rank));
445   if (rank == 0) {
446     switch (testNum) {
447     case 0: {
448       PetscInt    numPoints[2]         = {12, 2};
449       PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
450       PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
451       PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
452       PetscScalar vertexCoords[36]     = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5};
453 
454       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
455     } break;
456     case 1: {
457       PetscInt    numPoints[2]        = {8, 1};
458       PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
459       PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
460       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
461       PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};
462 
463       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
464     } break;
465     default:
466       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
467     }
468   } else {
469     PetscInt numPoints[4] = {0, 0, 0, 0};
470 
471     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
472   }
473   PetscCall(DMPlexInterpolate(*dm, &idm));
474   PetscCall(DMViewFromOptions(idm, NULL, "-in_dm_view"));
475   PetscCall(DMDestroy(dm));
476   *dm = idm;
477   PetscFunctionReturn(0);
478 }
479 
480 PetscErrorCode CreateTensorProductHybrid_3D(MPI_Comm comm, PetscInt testNum, DM *dm)
481 {
482   DM          idm, hdm = NULL;
483   DMLabel     faultLabel;
484   PetscInt    p;
485   PetscMPIInt rank;
486 
487   PetscFunctionBegin;
488   PetscCallMPI(MPI_Comm_rank(comm, &rank));
489   if (rank == 0) {
490     switch (testNum) {
491     case 0: {
492       PetscInt    numPoints[2]         = {12, 2};
493       PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
494       PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
495       PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
496       PetscScalar vertexCoords[36]     = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5};
497       PetscInt    faultPoints[4]       = {2, 3, 5, 6};
498 
499       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
500       for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
501     } break;
502     case 1: {
503       PetscInt numPoints[2] = {30, 7};
504       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};
505       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};
506       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};
507       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,
508                                        -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,
509                                        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};
510       PetscInt    faultPoints[6]    = {20, 21, 22, 23, 24, 25};
511 
512       PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
513       for (p = 0; p < 6; ++p) PetscCall(DMSetLabelValue(*dm, "fault", faultPoints[p], 1));
514     } break;
515     default:
516       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum);
517     }
518     PetscCall(DMPlexInterpolate(*dm, &idm));
519     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
520     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
521     PetscCall(DMSetFromOptions(idm));
522     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
523     PetscCall(DMGetLabel(*dm, "fault", &faultLabel));
524     PetscCall(DMPlexCreateHybridMesh(idm, faultLabel, NULL, 0, NULL, NULL, NULL, &hdm));
525     PetscCall(DMDestroy(&idm));
526     PetscCall(DMDestroy(dm));
527     *dm = hdm;
528   } else {
529     PetscInt numPoints[4] = {0, 0, 0, 0};
530 
531     PetscCall(DMPlexCreateFromDAG(*dm, 1, numPoints, NULL, NULL, NULL, NULL));
532     PetscCall(DMPlexInterpolate(*dm, &idm));
533     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)idm, "in_"));
534     PetscCall(DMPlexDistributeSetDefault(idm, PETSC_FALSE));
535     PetscCall(DMSetFromOptions(idm));
536     PetscCall(DMViewFromOptions(idm, NULL, "-dm_view"));
537     PetscCall(DMPlexCreateHybridMesh(idm, NULL, NULL, 0, NULL, NULL, NULL, &hdm));
538     PetscCall(DMDestroy(&idm));
539     PetscCall(DMDestroy(dm));
540     *dm = hdm;
541   }
542   PetscFunctionReturn(0);
543 }
544 
545 PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
546 {
547   PetscInt    dim         = user->dim;
548   PetscBool   cellHybrid  = user->cellHybrid;
549   PetscBool   cellSimplex = user->cellSimplex;
550   PetscMPIInt rank, size;
551 
552   PetscFunctionBegin;
553   PetscCallMPI(MPI_Comm_rank(comm, &rank));
554   PetscCallMPI(MPI_Comm_size(comm, &size));
555   PetscCall(DMCreate(comm, dm));
556   PetscCall(DMSetType(*dm, DMPLEX));
557   PetscCall(DMSetDimension(*dm, dim));
558   switch (dim) {
559   case 1:
560     PetscCheck(!cellHybrid, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make hybrid meshes for dimension %" PetscInt_FMT, dim);
561     PetscCall(CreateSimplex_1D(comm, dm));
562     break;
563   case 2:
564     if (cellSimplex) {
565       if (cellHybrid) {
566         PetscCall(CreateSimplexHybrid_2D(comm, user->testNum, dm));
567       } else {
568         PetscCall(CreateSimplex_2D(comm, dm));
569       }
570     } else {
571       if (cellHybrid) {
572         PetscCall(CreateTensorProductHybrid_2D(comm, user->testNum, dm));
573       } else {
574         PetscCall(CreateTensorProduct_2D(comm, user->testNum, dm));
575       }
576     }
577     break;
578   case 3:
579     if (cellSimplex) {
580       if (cellHybrid) {
581         PetscCall(CreateSimplexHybrid_3D(comm, user->testNum, dm));
582       } else {
583         PetscCall(CreateSimplex_3D(comm, user->testNum, dm));
584       }
585     } else {
586       if (cellHybrid) {
587         PetscCall(CreateTensorProductHybrid_3D(comm, user->testNum, dm));
588       } else {
589         PetscCall(CreateTensorProduct_3D(comm, user->testNum, dm));
590       }
591     }
592     break;
593   default:
594     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
595   }
596   if (user->testPartition && size > 1) {
597     PetscPartitioner part;
598     PetscInt        *sizes  = NULL;
599     PetscInt        *points = NULL;
600 
601     if (rank == 0) {
602       if (dim == 2 && cellSimplex && !cellHybrid && size == 2) {
603         switch (user->testNum) {
604         case 0: {
605           PetscInt triSizes_p2[2]  = {1, 1};
606           PetscInt triPoints_p2[2] = {0, 1};
607 
608           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
609           PetscCall(PetscArraycpy(sizes, triSizes_p2, 2));
610           PetscCall(PetscArraycpy(points, triPoints_p2, 2));
611           break;
612         }
613         default:
614           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for triangular mesh on 2 procs", user->testNum);
615         }
616       } else if (dim == 2 && cellSimplex && cellHybrid && size == 2) {
617         switch (user->testNum) {
618         case 0: {
619           PetscInt triSizes_p2[2]  = {1, 2};
620           PetscInt triPoints_p2[3] = {0, 1, 2};
621 
622           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
623           PetscCall(PetscArraycpy(sizes, triSizes_p2, 2));
624           PetscCall(PetscArraycpy(points, triPoints_p2, 3));
625           break;
626         }
627         default:
628           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for triangular hybrid mesh on 2 procs", user->testNum);
629         }
630       } else if (dim == 2 && !cellSimplex && !cellHybrid && size == 2) {
631         switch (user->testNum) {
632         case 0: {
633           PetscInt quadSizes_p2[2]  = {1, 1};
634           PetscInt quadPoints_p2[2] = {0, 1};
635 
636           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
637           PetscCall(PetscArraycpy(sizes, quadSizes_p2, 2));
638           PetscCall(PetscArraycpy(points, quadPoints_p2, 2));
639           break;
640         }
641         default:
642           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for quadrilateral mesh on 2 procs", user->testNum);
643         }
644       } else if (dim == 2 && !cellSimplex && cellHybrid && size == 2) {
645         switch (user->testNum) {
646         case 0: {
647           PetscInt quadSizes_p2[2]  = {1, 2};
648           PetscInt quadPoints_p2[3] = {0, 1, 2};
649 
650           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
651           PetscCall(PetscArraycpy(sizes, quadSizes_p2, 2));
652           PetscCall(PetscArraycpy(points, quadPoints_p2, 3));
653           break;
654         }
655         default:
656           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for quadrilateral hybrid mesh on 2 procs", user->testNum);
657         }
658       } else if (dim == 3 && cellSimplex && !cellHybrid && size == 2) {
659         switch (user->testNum) {
660         case 0: {
661           PetscInt tetSizes_p2[2]  = {1, 1};
662           PetscInt tetPoints_p2[2] = {0, 1};
663 
664           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
665           PetscCall(PetscArraycpy(sizes, tetSizes_p2, 2));
666           PetscCall(PetscArraycpy(points, tetPoints_p2, 2));
667           break;
668         }
669         case 1: {
670           PetscInt tetSizes_p2[2]  = {1, 1};
671           PetscInt tetPoints_p2[2] = {0, 1};
672 
673           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
674           PetscCall(PetscArraycpy(sizes, tetSizes_p2, 2));
675           PetscCall(PetscArraycpy(points, tetPoints_p2, 2));
676           break;
677         }
678         default:
679           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for tetrahedral mesh on 2 procs", user->testNum);
680         }
681       } else if (dim == 3 && cellSimplex && cellHybrid && size == 2) {
682         switch (user->testNum) {
683         case 0: {
684           PetscInt tetSizes_p2[2]  = {1, 2};
685           PetscInt tetPoints_p2[3] = {0, 1, 2};
686 
687           PetscCall(PetscMalloc2(2, &sizes, 3, &points));
688           PetscCall(PetscArraycpy(sizes, tetSizes_p2, 2));
689           PetscCall(PetscArraycpy(points, tetPoints_p2, 3));
690           break;
691         }
692         case 1: {
693           PetscInt tetSizes_p2[2]  = {3, 4};
694           PetscInt tetPoints_p2[7] = {0, 3, 5, 1, 2, 4, 6};
695 
696           PetscCall(PetscMalloc2(2, &sizes, 7, &points));
697           PetscCall(PetscArraycpy(sizes, tetSizes_p2, 2));
698           PetscCall(PetscArraycpy(points, tetPoints_p2, 7));
699           break;
700         }
701         default:
702           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for tetrahedral hybrid mesh on 2 procs", user->testNum);
703         }
704       } else if (dim == 3 && !cellSimplex && !cellHybrid && size == 2) {
705         switch (user->testNum) {
706         case 0: {
707           PetscInt hexSizes_p2[2]  = {1, 1};
708           PetscInt hexPoints_p2[2] = {0, 1};
709 
710           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
711           PetscCall(PetscArraycpy(sizes, hexSizes_p2, 2));
712           PetscCall(PetscArraycpy(points, hexPoints_p2, 2));
713           break;
714         }
715         default:
716           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for hexahedral mesh on 2 procs", user->testNum);
717         }
718       } else if (dim == 3 && !cellSimplex && cellHybrid && size == 2) {
719         switch (user->testNum) {
720         case 0: {
721           PetscInt hexSizes_p2[2]  = {1, 1};
722           PetscInt hexPoints_p2[2] = {0, 1};
723 
724           PetscCall(PetscMalloc2(2, &sizes, 2, &points));
725           PetscCall(PetscArraycpy(sizes, hexSizes_p2, 2));
726           PetscCall(PetscArraycpy(points, hexPoints_p2, 2));
727           break;
728         }
729         case 1: {
730           PetscInt hexSizes_p2[2]  = {5, 4};
731           PetscInt hexPoints_p2[9] = {3, 4, 5, 7, 8, 0, 1, 2, 6};
732 
733           PetscCall(PetscMalloc2(2, &sizes, 9, &points));
734           PetscCall(PetscArraycpy(sizes, hexSizes_p2, 2));
735           PetscCall(PetscArraycpy(points, hexPoints_p2, 9));
736           break;
737         }
738         default:
739           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test number %" PetscInt_FMT " for hexahedral hybrid mesh on 2 procs", user->testNum);
740         }
741       } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Could not find matching test partition");
742     }
743     PetscCall(DMPlexGetPartitioner(*dm, &part));
744     PetscCall(PetscPartitionerSetType(part, PETSCPARTITIONERSHELL));
745     PetscCall(PetscPartitionerShellSetPartition(part, size, sizes, points));
746     PetscCall(PetscFree2(sizes, points));
747   } else {
748     PetscPartitioner part;
749 
750     PetscCall(DMPlexGetPartitioner(*dm, &part));
751     PetscCall(PetscPartitionerSetFromOptions(part));
752   }
753   {
754     DM pdm = NULL;
755 
756     PetscCall(DMPlexDistribute(*dm, 0, NULL, &pdm));
757     if (pdm) {
758       PetscCall(DMViewFromOptions(pdm, NULL, "-dm_view"));
759       PetscCall(DMDestroy(dm));
760       *dm = pdm;
761     }
762   }
763   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
764   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_pre"));
765   PetscCall(DMSetFromOptions(*dm));
766   if (user->uninterpolate || user->reinterpolate) {
767     DM udm = NULL;
768 
769     PetscCall(DMPlexUninterpolate(*dm, &udm));
770     PetscCall(DMPlexCopyCoordinates(*dm, udm));
771     PetscCall(DMDestroy(dm));
772     *dm = udm;
773   }
774   if (user->reinterpolate) {
775     DM idm = NULL;
776 
777     PetscCall(DMPlexInterpolate(*dm, &idm));
778     PetscCall(DMPlexCopyCoordinates(*dm, idm));
779     PetscCall(DMDestroy(dm));
780     *dm = idm;
781   }
782   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
783   PetscCall(PetscObjectSetName((PetscObject)*dm, "Hybrid Mesh"));
784   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
785   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "hyb_"));
786   PetscCall(DMSetFromOptions(*dm));
787   PetscFunctionReturn(0);
788 }
789 
790 int main(int argc, char **argv)
791 {
792   DM     dm;
793   AppCtx user; /* user-defined work context */
794 
795   PetscFunctionBeginUser;
796   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
797   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
798   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
799   PetscCall(DMDestroy(&dm));
800   PetscCall(PetscFinalize());
801   return 0;
802 }
803 
804 /*TEST
805 
806   # 1D Simplex 29-31
807   testset:
808     args: -dim 1 -cell_hybrid 0 -hyb_dm_plex_check_all -dm_plex_check_all
809     test:
810       suffix: 29
811     test:
812       suffix: 30
813       args: -dm_refine 1
814     test:
815       suffix: 31
816       args: -dm_refine 5
817 
818   # 2D Simplex 0-3
819   testset:
820     args: -dim 2 -cell_hybrid 0 -hyb_dm_plex_check_all -dm_plex_check_all
821     test:
822       suffix: 0
823     test:
824       suffix: 1
825       args: -dm_refine 1
826     test:
827       suffix: 2
828       nsize: 2
829     test:
830       suffix: 3
831       nsize: 2
832       args: -dm_refine 1
833     test:
834       suffix: 32
835       args: -dm_refine 1 -uninterpolate
836     test:
837       suffix: 33
838       nsize: 2
839       args: -dm_refine 1 -uninterpolate
840     test:
841       suffix: 34
842       nsize: 2
843       args: -dm_refine 3 -uninterpolate
844 
845   # 2D Hybrid Simplex 4-7
846   testset:
847     args: -dim 2 -hyb_dm_plex_check_all -in_dm_plex_check_all -dm_plex_check_all
848     test:
849       suffix: 4
850     test:
851       suffix: 5
852       args: -dm_refine 1
853     test:
854       suffix: 6
855       nsize: 2
856     test:
857       suffix: 7
858       nsize: 2
859       args: -dm_refine 1
860     test:
861       suffix: 24
862       args: -test_num 1 -dm_refine 1
863 
864   # 2D Quad 12-13
865   testset:
866     args: -dim 2 -cell_simplex 0 -cell_hybrid 0 -hyb_dm_plex_check_all -dm_plex_check_all
867     test:
868       suffix: 12
869       args: -dm_refine 1
870     test:
871       suffix: 13
872       nsize: 2
873       args: -dm_refine 1
874 
875   # 2D Hybrid Quad 27-28
876   testset:
877     args: -dim 2 -cell_simplex 0 -hyb_dm_plex_check_all -in_dm_plex_check_all -dm_plex_check_all
878     test:
879       suffix: 27
880       args: -dm_refine 1
881     test:
882       suffix: 28
883       nsize: 2
884       args: -dm_refine 1
885 
886   # 3D Simplex 8-11
887   testset:
888     args: -dim 3 -cell_hybrid 0 -hyb_dm_plex_check_all -dm_plex_check_all
889     test:
890       suffix: 8
891       args: -dm_refine 1
892     test:
893       suffix: 9
894       nsize: 2
895       args: -dm_refine 1
896     test:
897       suffix: 10
898       args: -test_num 1 -dm_refine 1
899     test:
900       suffix: 11
901       nsize: 2
902       args: -test_num 1 -dm_refine 1
903     test:
904       suffix: 25
905       args: -test_num 2 -dm_refine 2
906 
907   # 3D Hybrid Simplex 16-19
908   testset:
909     args: -dim 3 -hyb_dm_plex_check_all -in_dm_plex_check_all -dm_plex_check_all
910     test:
911       suffix: 16
912       args: -dm_refine 1
913     test:
914       suffix: 17
915       nsize: 2
916       args: -dm_refine 1
917     test:
918       suffix: 18
919       args: -test_num 1 -dm_refine 1
920     test:
921       suffix: 19
922       nsize: 2
923       args: -test_num 1 -dm_refine 1
924 
925   # 3D Hex 14-15
926   testset:
927     args: -dim 3 -cell_simplex 0 -cell_hybrid 0 -hyb_dm_plex_check_all -dm_plex_check_all
928     test:
929       suffix: 14
930       args: -dm_refine 1
931     test:
932       suffix: 15
933       nsize: 2
934      args: -dm_refine 1
935     test:
936       suffix: 26
937       args: -test_num 1 -dm_refine 2
938 
939   # 3D Hybrid Hex 20-23
940   testset:
941     args: -dim 3 -cell_simplex 0 -hyb_dm_plex_check_all -in_dm_plex_check_all -dm_plex_check_all
942     test:
943       suffix: 20
944       args: -dm_refine 1
945     test:
946       suffix: 21
947       nsize: 2
948       args: -dm_refine 1
949     test:
950       suffix: 22
951       args: -test_num 1 -dm_refine 1
952     test:
953       suffix: 23
954       nsize: 2
955       args: -test_num 1 -dm_refine 1
956 
957   # Hybrid interpolation
958   #   TODO Setup new tests (like -reinterpolate) that interpolate hybrid cells
959   testset:
960     nsize: 2
961     args: -test_partition 0 -petscpartitioner_type simple -dm_view -hyb_dm_plex_check_all -in_dm_plex_check_all -dm_plex_check_all
962     test:
963       suffix: hybint_2d_0
964       args: -dim 2 -dm_refine 2
965     test:
966       suffix: hybint_2d_1
967       args: -dim 2 -dm_refine 2 -test_num 1
968     test:
969       suffix: hybint_3d_0
970       args: -dim 3 -dm_refine 1
971     test:
972       suffix: hybint_3d_1
973       args: -dim 3 -dm_refine 1 -test_num 1
974 
975 TEST*/
976