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