xref: /petsc/src/dm/impls/plex/tutorials/ex11.c (revision 6a5217c03994f2d95bb2e6dbd8bed42381aeb015)
1 static char help[] = "Mesh Orientation Tutorial\n\n";
2 
3 #include <petscdmplex.h>
4 #include <petscdmplextransform.h>
5 
6 typedef struct {
7   PetscBool genArr;        /* Generate all possible cell arrangements */
8   PetscBool refArr;        /* Refine all possible cell arrangements */
9   PetscBool printTable;    /* Print the CAyley table */
10   PetscInt  orntBounds[2]; /* Bounds for the orientation check */
11   PetscInt  numOrnt;       /* Number of specific orientations specified, or -1 for all orientations */
12   PetscInt  ornts[48];     /* Specific orientations if specified */
13   PetscInt  initOrnt;      /* Initial orientation for starting mesh */
14 } AppCtx;
15 
16 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
17 {
18   PetscInt       n = 2;
19   PetscBool      flg;
20   PetscErrorCode ierr;
21 
22   PetscFunctionBeginUser;
23   options->genArr        = PETSC_FALSE;
24   options->refArr        = PETSC_FALSE;
25   options->printTable    = PETSC_FALSE;
26   options->orntBounds[0] = PETSC_MIN_INT;
27   options->orntBounds[1] = PETSC_MAX_INT;
28   options->numOrnt       = -1;
29   options->initOrnt      = 0;
30 
31   ierr = PetscOptionsBegin(comm, "", "Mesh Orientation Tutorials Options", "DMPLEX");PetscCall(ierr);
32   PetscCall(PetscOptionsBool("-gen_arrangements", "Flag for generating all arrangements of the cell", "ex11.c", options->genArr, &options->genArr, NULL));
33   PetscCall(PetscOptionsBool("-ref_arrangements", "Flag for refining all arrangements of the cell", "ex11.c", options->refArr, &options->refArr, NULL));
34   PetscCall(PetscOptionsBool("-print_table", "Print the Cayley table", "ex11.c", options->printTable, &options->printTable, NULL));
35   PetscCall(PetscOptionsIntArray("-ornt_bounds", "Bounds for orientation checks", "ex11.c", options->orntBounds, &n, NULL));
36   n    = 48;
37   PetscCall(PetscOptionsIntArray("-ornts", "Specific orientations for checks", "ex11.c", options->ornts, &n, &flg));
38   if (flg) {
39     options->numOrnt = n;
40     PetscCall(PetscSortInt(n, options->ornts));
41   }
42   PetscCall(PetscOptionsInt("-init_ornt", "Initial orientation for starting mesh", "ex11.c", options->initOrnt, &options->initOrnt, NULL));
43   ierr = PetscOptionsEnd();
44   PetscFunctionReturn(0);
45 }
46 
47 static PetscBool ignoreOrnt(AppCtx *user, PetscInt o)
48 {
49   PetscInt       loc;
50   PetscErrorCode ierr;
51 
52   if (user->numOrnt < 0) return PETSC_FALSE;
53   ierr = PetscFindInt(o, user->numOrnt, user->ornts, &loc);
54   if (loc < 0 || ierr)   return PETSC_TRUE;
55   return PETSC_FALSE;
56 }
57 
58 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
59 {
60   PetscFunctionBeginUser;
61   PetscCall(DMCreate(comm, dm));
62   PetscCall(DMSetType(*dm, DMPLEX));
63   PetscCall(DMSetFromOptions(*dm));
64   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
65   PetscFunctionReturn(0);
66 }
67 
68 static PetscErrorCode CheckCellVertices(DM dm, PetscInt cell, PetscInt o)
69 {
70   DMPolytopeType  ct;
71   const PetscInt *arrVerts;
72   PetscInt       *closure = NULL;
73   PetscInt        Ncl, cl, Nv, vStart, vEnd, v;
74   MPI_Comm        comm;
75 
76   PetscFunctionBeginUser;
77   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
78   PetscCall(DMPlexGetCellType(dm, cell, &ct));
79   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
80   PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &Ncl, &closure));
81   for (cl = 0, Nv = 0; cl < Ncl*2; cl += 2) {
82     const PetscInt vertex = closure[cl];
83 
84     if (vertex < vStart || vertex >= vEnd) continue;
85     closure[Nv++] = vertex;
86   }
87   PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct),comm, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D vertices in a %s", cell, Nv, DMPolytopeTypeGetNumVertices(ct), DMPolytopeTypes[ct]);
88   arrVerts = DMPolytopeTypeGetVertexArrangment(ct, o);
89   for (v = 0; v < Nv; ++v) {
90     PetscCheck(closure[v] == arrVerts[v]+vStart,comm, PETSC_ERR_ARG_WRONG, "Cell %D vertex[%D]: %D should be %D for arrangement %D", cell, v, closure[v], arrVerts[v]+vStart, o);
91   }
92   PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &Ncl, &closure));
93   PetscFunctionReturn(0);
94 }
95 
96 /* Transform cell with group operation o */
97 static PetscErrorCode ReorientCell(DM dm, PetscInt cell, PetscInt o, PetscBool swapCoords)
98 {
99   DM              cdm;
100   Vec             coordinates;
101   PetscScalar    *coords, *ccoords = NULL;
102   PetscInt       *closure = NULL;
103   PetscInt        cdim, d, Nc, Ncl, cl, vStart, vEnd, Nv;
104 
105   PetscFunctionBegin;
106   /* Change vertex coordinates so that it plots as we expect */
107   PetscCall(DMGetCoordinateDM(dm, &cdm));
108   PetscCall(DMGetCoordinateDim(dm, &cdim));
109   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
110   PetscCall(DMPlexVecGetClosure(cdm, NULL, coordinates, cell, &Nc, &ccoords));
111   /* Reorient cone */
112   PetscCall(DMPlexOrientPoint(dm, cell, o));
113   /* Finish resetting coordinates */
114   if (swapCoords) {
115     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
116     PetscCall(VecGetArrayWrite(coordinates, &coords));
117     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &Ncl, &closure));
118     for (cl = 0, Nv = 0; cl < Ncl*2; cl += 2) {
119       const PetscInt vertex = closure[cl];
120       PetscScalar   *vcoords;
121 
122       if (vertex < vStart || vertex >= vEnd) continue;
123       PetscCall(DMPlexPointLocalRef(cdm, vertex, coords, &vcoords));
124       for (d = 0; d < cdim; ++d) vcoords[d] = ccoords[Nv*cdim + d];
125       ++Nv;
126     }
127     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &Ncl, &closure));
128     PetscCall(VecRestoreArrayWrite(coordinates, &coords));
129   }
130   PetscCall(DMPlexVecRestoreClosure(cdm, NULL, coordinates, cell, &Nc, &ccoords));
131   PetscFunctionReturn(0);
132 }
133 
134 static PetscErrorCode GenerateArrangments(DM dm, AppCtx *user)
135 {
136   DM             odm;
137   DMPolytopeType ct;
138   PetscInt       No, o;
139   const char    *name;
140 
141   PetscFunctionBeginUser;
142   if (!user->genArr) PetscFunctionReturn(0);
143   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
144   PetscCall(DMPlexGetCellType(dm, 0, &ct));
145   No   = DMPolytopeTypeGetNumArrangments(ct)/2;
146   for (o = PetscMax(-No, user->orntBounds[0]); o < PetscMin(No, user->orntBounds[1]); ++o) {
147     if (ignoreOrnt(user, o)) continue;
148     PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &odm));
149     PetscCall(ReorientCell(odm, 0, o, PETSC_TRUE));
150     PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "%s orientation %D\n", name, o));
151     PetscCall(DMViewFromOptions(odm, NULL, "-gen_dm_view"));
152     PetscCall(CheckCellVertices(odm, 0, o));
153     PetscCall(DMDestroy(&odm));
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 static PetscErrorCode VerifyCayleyTable(DM dm, AppCtx *user)
159 {
160   DM              dm1, dm2;
161   DMPolytopeType  ct;
162   const PetscInt *refcone, *cone;
163   PetscInt        No, o1, o2, o3, o4;
164   PetscBool       equal;
165   const char     *name;
166 
167   PetscFunctionBeginUser;
168   if (!user->genArr) PetscFunctionReturn(0);
169   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
170   PetscCall(DMPlexGetCellType(dm, 0, &ct));
171   PetscCall(DMPlexGetCone(dm, 0, &refcone));
172   No   = DMPolytopeTypeGetNumArrangments(ct)/2;
173   if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cayley Table for %s\n", DMPolytopeTypes[ct]));
174   for (o1 = PetscMax(-No, user->orntBounds[0]); o1 < PetscMin(No, user->orntBounds[1]); ++o1) {
175     for (o2 = PetscMax(-No, user->orntBounds[0]); o2 < PetscMin(No, user->orntBounds[1]); ++o2) {
176       PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &dm1));
177       PetscCall(DMPlexOrientPoint(dm1, 0, o2));
178       PetscCall(DMPlexCheckFaces(dm1, 0));
179       PetscCall(DMPlexOrientPoint(dm1, 0, o1));
180       PetscCall(DMPlexCheckFaces(dm1, 0));
181       o3   = DMPolytopeTypeComposeOrientation(ct, o1, o2);
182       /* First verification */
183       PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &dm2));
184       PetscCall(DMPlexOrientPoint(dm2, 0, o3));
185       PetscCall(DMPlexCheckFaces(dm2, 0));
186       PetscCall(DMPlexEqual(dm1, dm2, &equal));
187       if (!equal) {
188         PetscCall(DMViewFromOptions(dm1, NULL, "-error_dm_view"));
189         PetscCall(DMViewFromOptions(dm2, NULL, "-error_dm_view"));
190         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cayley table error for %s: %D * %D != %D", DMPolytopeTypes[ct], o1, o2, o3);
191       }
192       /* Second verification */
193       PetscCall(DMPlexGetCone(dm1, 0, &cone));
194       PetscCall(DMPolytopeGetOrientation(ct, refcone, cone, &o4));
195       if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", o4));
196       PetscCheck(o3 == o4,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cayley table error for %s: %D * %D = %D != %D", DMPolytopeTypes[ct], o1, o2, o3, o4);
197       PetscCall(DMDestroy(&dm1));
198       PetscCall(DMDestroy(&dm2));
199     }
200     if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
201   }
202   PetscFunctionReturn(0);
203 }
204 
205 static PetscErrorCode VerifyInverse(DM dm, AppCtx *user)
206 {
207   DM              dm1, dm2;
208   DMPolytopeType  ct;
209   const PetscInt *refcone, *cone;
210   PetscInt        No, o, oi, o2;
211   PetscBool       equal;
212   const char     *name;
213 
214   PetscFunctionBeginUser;
215   if (!user->genArr) PetscFunctionReturn(0);
216   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
217   PetscCall(DMPlexGetCellType(dm, 0, &ct));
218   PetscCall(DMPlexGetCone(dm, 0, &refcone));
219   No   = DMPolytopeTypeGetNumArrangments(ct)/2;
220   if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Inverse table for %s\n", DMPolytopeTypes[ct]));
221   for (o = PetscMax(-No, user->orntBounds[0]); o < PetscMin(No, user->orntBounds[1]); ++o) {
222     if (ignoreOrnt(user, o)) continue;
223     oi   = DMPolytopeTypeComposeOrientationInv(ct, 0, o);
224     PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &dm1));
225     PetscCall(DMPlexOrientPoint(dm1, 0, o));
226     PetscCall(DMPlexCheckFaces(dm1, 0));
227     PetscCall(DMPlexOrientPoint(dm1, 0, oi));
228     PetscCall(DMPlexCheckFaces(dm1, 0));
229     /* First verification */
230     PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &dm2));
231     PetscCall(DMPlexEqual(dm1, dm2, &equal));
232     if (!equal) {
233       PetscCall(DMViewFromOptions(dm1, NULL, "-error_dm_view"));
234       PetscCall(DMViewFromOptions(dm2, NULL, "-error_dm_view"));
235       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inverse error for %s: %D * %D != 0", DMPolytopeTypes[ct], o, oi);
236     }
237     /* Second verification */
238     PetscCall(DMPlexGetCone(dm1, 0, &cone));
239     PetscCall(DMPolytopeGetOrientation(ct, refcone, cone, &o2));
240     if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", oi));
241     PetscCheck(o2 == 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inverse error for %s: %D * %D = %D != 0", DMPolytopeTypes[ct], o, oi, o2);
242     PetscCall(DMDestroy(&dm1));
243     PetscCall(DMDestroy(&dm2));
244   }
245   if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
246   PetscFunctionReturn(0);
247 }
248 
249 /* Suppose that point p has the same arrangement as o from canonical, compare the subcells to canonical subcells */
250 static PetscErrorCode CheckSubcells(DM dm, DM odm, PetscInt p, PetscInt o, AppCtx *user)
251 {
252   DMPlexTransform tr, otr;
253   DMPolytopeType  ct;
254   DMPolytopeType *rct;
255   const PetscInt *cone, *ornt, *ocone, *oornt;
256   PetscInt       *rsize, *rcone, *rornt;
257   PetscInt        Nct, n, oi, debug = 0;
258 
259   PetscFunctionBeginUser;
260   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject) dm), &tr));
261   PetscCall(DMPlexTransformSetDM(tr, dm));
262   PetscCall(DMPlexTransformSetFromOptions(tr));
263   PetscCall(DMPlexTransformSetUp(tr));
264 
265   PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject) odm), &otr));
266   PetscCall(DMPlexTransformSetDM(otr, odm));
267   PetscCall(DMPlexTransformSetFromOptions(otr));
268   PetscCall(DMPlexTransformSetUp(otr));
269 
270   PetscCall(DMPlexGetCellType(dm, p, &ct));
271   PetscCall(DMPlexGetCone(dm, p, &cone));
272   PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
273   PetscCall(DMPlexGetCone(odm, p, &ocone));
274   PetscCall(DMPlexGetConeOrientation(odm, p, &oornt));
275   oi   = DMPolytopeTypeComposeOrientationInv(ct, 0, o);
276   if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Orientation %D\n", oi));
277 
278   PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt));
279   for (n = 0; n < Nct; ++n) {
280     DMPolytopeType ctNew = rct[n];
281     PetscInt       r, ro;
282 
283     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Checking type %s\n", DMPolytopeTypes[ctNew]));
284     for (r = 0; r < rsize[n]; ++r) {
285       const PetscInt *qcone, *qornt, *oqcone, *oqornt;
286       PetscInt        pNew, opNew, oo, pr, fo;
287       PetscBool       restore = PETSC_TRUE;
288 
289       PetscCall(DMPlexTransformGetTargetPoint(tr, ct, ctNew, p, r, &pNew));
290       PetscCall(DMPlexTransformGetCone(tr, pNew, &qcone, &qornt));
291       if (debug) {
292         PetscInt c;
293 
294         PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Checking replica %D (%D)\n      Original Cone", r, pNew));
295         for (c = 0; c < DMPolytopeTypeGetConeSize(ctNew); ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D (%D)", qcone[c], qornt[c]));
296         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
297       }
298       for (ro = 0; ro < rsize[n]; ++ro) {
299         PetscBool found;
300 
301         PetscCall(DMPlexTransformGetTargetPoint(otr, ct, ctNew, p, ro, &opNew));
302         PetscCall(DMPlexTransformGetConeOriented(otr, opNew, o, &oqcone, &oqornt));
303         PetscCall(DMPolytopeMatchOrientation(ctNew, oqcone, qcone, &oo, &found));
304         if (found) break;
305         PetscCall(DMPlexTransformRestoreCone(otr, pNew, &oqcone, &oqornt));
306       }
307       if (debug) {
308         PetscInt c;
309 
310         PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Checking transform replica %D (%D) (%D)\n      Transform Cone", ro, opNew, o));
311         for (c = 0; c < DMPolytopeTypeGetConeSize(ctNew); ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D (%D)", oqcone[c], oqornt[c]));
312         PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
313         PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Matched %D\n", oo));
314       }
315       if (ro == rsize[n]) {
316         /* The tetrahedron has 3 pairs of opposing edges, and any pair can be connected by the interior segment */
317         if (ct == DM_POLYTOPE_TETRAHEDRON) {
318           /* The segment in a tetrahedron does not map into itself under the group action */
319           if (ctNew == DM_POLYTOPE_SEGMENT) {restore = PETSC_FALSE; ro = r; oo = 0;}
320           /* The last four interior faces do not map into themselves under the group action */
321           if (r > 3 && ctNew == DM_POLYTOPE_TRIANGLE) {restore = PETSC_FALSE; ro = r; oo = 0;}
322           /* The last four interior faces do not map into themselves under the group action */
323           if (r > 3 && ctNew == DM_POLYTOPE_TETRAHEDRON) {restore = PETSC_FALSE; ro = r; oo = 0;}
324         }
325         PetscCheck(!restore,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to find matching %s %D orientation for cell orientation %D", DMPolytopeTypes[ctNew], r, o);
326       }
327       if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, %D, ", ro, oo));
328       PetscCall(DMPlexTransformGetSubcellOrientation(tr, ct, p, oi, ctNew, r, 0, &pr, &fo));
329       if (!user->printTable) {
330         PetscCheck(pr == ro,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Choose wrong replica %D != %D", pr, ro);
331         PetscCheck(fo == oo,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Choose wrong orientation %D != %D", fo, oo);
332       }
333       PetscCall(DMPlexTransformRestoreCone(tr, pNew, &qcone, &qornt));
334       if (restore) PetscCall(DMPlexTransformRestoreCone(otr, pNew, &oqcone, &oqornt));
335     }
336     if (user->printTable) PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
337   }
338   PetscCall(DMPlexTransformDestroy(&tr));
339   PetscCall(DMPlexTransformDestroy(&otr));
340   PetscFunctionReturn(0);
341 }
342 
343 static PetscErrorCode RefineArrangments(DM dm, AppCtx *user)
344 {
345   DM             odm, rdm;
346   DMPolytopeType ct;
347   PetscInt       No, o;
348   const char    *name;
349 
350   PetscFunctionBeginUser;
351   if (!user->refArr) PetscFunctionReturn(0);
352   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
353   PetscCall(DMPlexGetCellType(dm, 0, &ct));
354   No   = DMPolytopeTypeGetNumArrangments(ct)/2;
355   for (o = PetscMax(-No, user->orntBounds[0]); o < PetscMin(No, user->orntBounds[1]); ++o) {
356     if (ignoreOrnt(user, o)) continue;
357     PetscCall(CreateMesh(PetscObjectComm((PetscObject) dm), user, &odm));
358     if (user->initOrnt) PetscCall(ReorientCell(odm, 0, user->initOrnt, PETSC_FALSE));
359     PetscCall(ReorientCell(odm, 0, o, PETSC_TRUE));
360     PetscCall(DMViewFromOptions(odm, NULL, "-orig_dm_view"));
361     PetscCall(DMRefine(odm, MPI_COMM_NULL, &rdm));
362     PetscCall(DMSetFromOptions(rdm));
363     PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "%s orientation %D\n", name, o));
364     PetscCall(DMViewFromOptions(rdm, NULL, "-ref_dm_view"));
365     PetscCall(CheckSubcells(dm, odm, 0, o, user));
366     PetscCall(DMDestroy(&odm));
367     PetscCall(DMDestroy(&rdm));
368   }
369   PetscFunctionReturn(0);
370 }
371 
372 int main(int argc, char **argv)
373 {
374   DM             dm;
375   AppCtx         user;
376 
377   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
378   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
379   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
380   if (user.initOrnt) {
381     PetscCall(ReorientCell(dm, 0, user.initOrnt, PETSC_FALSE));
382     PetscCall(DMViewFromOptions(dm, NULL, "-ornt_dm_view"));
383   }
384   PetscCall(GenerateArrangments(dm, &user));
385   PetscCall(VerifyCayleyTable(dm, &user));
386   PetscCall(VerifyInverse(dm, &user));
387   PetscCall(RefineArrangments(dm, &user));
388   PetscCall(DMDestroy(&dm));
389   PetscCall(PetscFinalize());
390   return 0;
391 }
392 
393 /*TEST
394 
395   testset:
396     args: -dm_coord_space 0 -dm_plex_reference_cell_domain -gen_arrangements \
397           -gen_dm_view ::ascii_latex -dm_plex_view_tikzscale 0.5
398 
399     test:
400       suffix: segment
401       args: -dm_plex_cell segment \
402             -dm_plex_view_numbers_depth 1,0 -dm_plex_view_colors_depth 1,0
403 
404     test:
405       suffix: triangle
406       args: -dm_plex_cell triangle \
407             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
408 
409     test:
410       suffix: quadrilateral
411       args: -dm_plex_cell quadrilateral \
412             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
413 
414     test:
415       suffix: tensor_segment
416       args: -dm_plex_cell tensor_quad \
417             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
418 
419     test:
420       suffix: tetrahedron
421       args: -dm_plex_cell tetrahedron \
422             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
423 
424     test:
425       suffix: hexahedron
426       args: -dm_plex_cell hexahedron \
427             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 0.3
428 
429     test:
430       suffix: triangular_prism
431       args: -dm_plex_cell triangular_prism \
432             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
433 
434     test:
435       suffix: tensor_triangular_prism
436       args: -dm_plex_cell tensor_triangular_prism \
437             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
438 
439     test:
440       suffix: tensor_quadrilateral_prism
441       args: -dm_plex_cell tensor_quadrilateral_prism \
442             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
443 
444     test:
445       suffix: pyramid
446       args: -dm_plex_cell pyramid \
447             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
448 
449   testset:
450     args: -dm_coord_space 0 -dm_plex_reference_cell_domain -ref_arrangements -dm_plex_check_all \
451           -ref_dm_view ::ascii_latex -dm_plex_view_tikzscale 1.0
452 
453     test:
454       suffix: ref_segment
455       args: -dm_plex_cell segment \
456             -dm_plex_view_numbers_depth 1,0 -dm_plex_view_colors_depth 1,0
457 
458     test:
459       suffix: ref_triangle
460       args: -dm_plex_cell triangle \
461             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
462 
463     test:
464       suffix: ref_quadrilateral
465       args: -dm_plex_cell quadrilateral \
466             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
467 
468     test:
469       suffix: ref_tensor_segment
470       args: -dm_plex_cell tensor_quad \
471             -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0
472 
473     test:
474       suffix: ref_tetrahedron
475       args: -dm_plex_cell tetrahedron \
476             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
477 
478     test:
479       suffix: ref_hexahedron
480       args: -dm_plex_cell hexahedron \
481             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
482 
483     test:
484       suffix: ref_triangular_prism
485       args: -dm_plex_cell triangular_prism \
486             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
487 
488     test:
489       suffix: ref_tensor_triangular_prism
490       args: -dm_plex_cell tensor_triangular_prism \
491             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
492 
493     test:
494       suffix: ref_tensor_quadrilateral_prism
495       args: -dm_plex_cell tensor_quadrilateral_prism \
496             -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0
497 
498   # ToBox should recreate the coordinate space since the cell shape changes
499   testset:
500     args: -dm_coord_space 0 -dm_plex_transform_type refine_tobox -ref_arrangements -dm_plex_check_all
501 
502     test:
503       suffix: tobox_triangle
504       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle \
505             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
506 
507     test:
508       suffix: tobox_tensor_segment
509       args: -dm_plex_reference_cell_domain -dm_plex_cell tensor_quad \
510             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
511 
512     test:
513       suffix: tobox_tetrahedron
514       args: -dm_plex_reference_cell_domain -dm_plex_cell tetrahedron \
515             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
516 
517     test:
518       suffix: tobox_triangular_prism
519       args: -dm_plex_reference_cell_domain -dm_plex_cell triangular_prism \
520             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
521 
522     test:
523       suffix: tobox_tensor_triangular_prism
524       args: -dm_plex_reference_cell_domain -dm_plex_cell tensor_triangular_prism \
525             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
526 
527     test:
528       suffix: tobox_tensor_quadrilateral_prism
529       args: -dm_plex_reference_cell_domain -dm_plex_cell tensor_quadrilateral_prism \
530             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
531 
532   testset:
533     args: -dm_coord_space 0 -dm_plex_transform_type refine_alfeld -ref_arrangements -dm_plex_check_all
534 
535     test:
536       suffix: alfeld_triangle
537       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle \
538             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
539 
540     test:
541       suffix: alfeld_tetrahedron
542       args: -dm_plex_reference_cell_domain -dm_plex_cell tetrahedron \
543             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
544 
545   testset:
546     args: -dm_plex_transform_type refine_sbr -ref_arrangements -dm_plex_check_all
547 
548     # This splits edge 1 of the triangle, and reflects about the added edge
549     test:
550       suffix: sbr_triangle_0
551       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5 -ornts -2,0 \
552             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
553 
554     # This splits edge 0 of the triangle, and reflects about the added edge
555     test:
556       suffix: sbr_triangle_1
557       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5 -init_ornt 1 -ornts -3,0 \
558             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
559 
560     # This splits edge 2 of the triangle, and reflects about the added edge
561     test:
562       suffix: sbr_triangle_2
563       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5 -init_ornt 2 -ornts -1,0 \
564             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
565 
566     # This splits edges 1 and 2 of the triangle
567     test:
568       suffix: sbr_triangle_3
569       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5,6 -ornts 0 \
570             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
571 
572     # This splits edges 1 and 0 of the triangle
573     test:
574       suffix: sbr_triangle_4
575       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 4,5 -ornts 0 \
576             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
577 
578     # This splits edges 0 and 1 of the triangle
579     test:
580       suffix: sbr_triangle_5
581       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5,6 -init_ornt 1 -ornts 0 \
582             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
583 
584     # This splits edges 0 and 2 of the triangle
585     test:
586       suffix: sbr_triangle_6
587       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 4,5 -init_ornt 1 -ornts 0 \
588             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
589 
590     # This splits edges 2 and 0 of the triangle
591     test:
592       suffix: sbr_triangle_7
593       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 5,6 -init_ornt 2 -ornts 0 \
594             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
595 
596     # This splits edges 2 and 1 of the triangle
597     test:
598       suffix: sbr_triangle_8
599       args: -dm_plex_reference_cell_domain -dm_plex_cell triangle -dm_plex_transform_sbr_ref_cell 4,5 -init_ornt 2 -ornts 0 \
600             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
601 
602   testset:
603     args: -dm_plex_transform_type refine_boundary_layer -dm_plex_transform_bl_splits 2 -ref_arrangements -dm_plex_check_all
604 
605     test:
606       suffix: bl_tensor_segment
607       args: -dm_plex_reference_cell_domain -dm_plex_cell tensor_quad \
608             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,1,0 -dm_plex_view_colors_depth 1,1,0 -dm_plex_view_tikzscale 1.0
609 
610     # The subcell check is broken because at orientation 3, the internal triangles do not get properly permuted for the check
611     test:
612       suffix: bl_tensor_triangular_prism
613       requires: TODO
614       args: -dm_plex_reference_cell_domain -dm_plex_cell tensor_triangular_prism \
615             -ref_dm_view ::ascii_latex -dm_plex_view_numbers_depth 1,0,0,0 -dm_plex_view_colors_depth 1,0,0,0 -dm_plex_view_tikzscale 1.0
616 
617 TEST*/
618