xref: /petsc/src/dm/impls/plex/tests/ex8.c (revision 2c71b3e237ead271e4f3aa1505f92bf476e3413d)
1 static char help[] = "Tests for cell geometry\n\n";
2 
3 #include <petscdmplex.h>
4 
5 typedef enum {RUN_REFERENCE, RUN_HEX_CURVED, RUN_FILE, RUN_DISPLAY} RunType;
6 
7 typedef struct {
8   DM        dm;
9   RunType   runType;                      /* Type of mesh to use */
10   PetscBool transform;                    /* Use random coordinate transformations */
11   /* Data for input meshes */
12   PetscReal *v0, *J, *invJ, *detJ;        /* FEM data */
13   PetscReal *centroid, *normal, *vol;     /* FVM data */
14 } AppCtx;
15 
16 static PetscErrorCode ReadMesh(MPI_Comm comm, AppCtx *user, DM *dm)
17 {
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
22   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
23   ierr = DMSetFromOptions(*dm);CHKERRQ(ierr);
24   ierr = DMSetApplicationContext(*dm, user);CHKERRQ(ierr);
25   ierr = PetscObjectSetName((PetscObject) *dm, "Input Mesh");CHKERRQ(ierr);
26   ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr);
27   PetscFunctionReturn(0);
28 }
29 
30 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
31 {
32   const char    *runTypes[4] = {"reference", "hex_curved", "file", "display"};
33   PetscInt       run;
34   PetscErrorCode ierr;
35 
36   PetscFunctionBeginUser;
37   options->runType   = RUN_REFERENCE;
38   options->transform = PETSC_FALSE;
39 
40   ierr = PetscOptionsBegin(comm, "", "Geometry Test Options", "DMPLEX");CHKERRQ(ierr);
41   run  = options->runType;
42   ierr = PetscOptionsEList("-run_type", "The run type", "ex8.c", runTypes, 3, runTypes[options->runType], &run, NULL);CHKERRQ(ierr);
43   options->runType = (RunType) run;
44   ierr = PetscOptionsBool("-transform", "Use random transforms", "ex8.c", options->transform, &options->transform, NULL);CHKERRQ(ierr);
45 
46   if (options->runType == RUN_FILE) {
47     PetscInt  dim, cStart, cEnd, numCells, n;
48     PetscBool flg, feFlg;
49 
50     ierr = ReadMesh(PETSC_COMM_WORLD, options, &options->dm);CHKERRQ(ierr);
51     ierr = DMGetDimension(options->dm, &dim);CHKERRQ(ierr);
52     ierr = DMPlexGetHeightStratum(options->dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
53     numCells = cEnd-cStart;
54     ierr = PetscMalloc4(numCells*dim, &options->v0, numCells*dim*dim, &options->J, numCells*dim*dim, &options->invJ, numCells, &options->detJ);CHKERRQ(ierr);
55     ierr = PetscMalloc1(numCells*dim, &options->centroid);CHKERRQ(ierr);
56     ierr = PetscMalloc1(numCells*dim, &options->normal);CHKERRQ(ierr);
57     ierr = PetscMalloc1(numCells, &options->vol);CHKERRQ(ierr);
58     n    = numCells*dim;
59     ierr = PetscOptionsRealArray("-v0", "Input v0 for each cell", "ex8.c", options->v0, &n, &feFlg);CHKERRQ(ierr);
60     PetscCheckFalse(feFlg && n != numCells*dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of v0 %D should be %D", n, numCells*dim);
61     n    = numCells*dim*dim;
62     ierr = PetscOptionsRealArray("-J", "Input Jacobian for each cell", "ex8.c", options->J, &n, &flg);CHKERRQ(ierr);
63     PetscCheckFalse(flg && n != numCells*dim*dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of J %D should be %D", n, numCells*dim*dim);
64     n    = numCells*dim*dim;
65     ierr = PetscOptionsRealArray("-invJ", "Input inverse Jacobian for each cell", "ex8.c", options->invJ, &n, &flg);CHKERRQ(ierr);
66     PetscCheckFalse(flg && n != numCells*dim*dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of invJ %D should be %D", n, numCells*dim*dim);
67     n    = numCells;
68     ierr = PetscOptionsRealArray("-detJ", "Input Jacobian determinant for each cell", "ex8.c", options->detJ, &n, &flg);CHKERRQ(ierr);
69     PetscCheckFalse(flg && n != numCells,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of detJ %D should be %D", n, numCells);
70     n    = numCells*dim;
71     if (!feFlg) {
72       ierr = PetscFree4(options->v0, options->J, options->invJ, options->detJ);CHKERRQ(ierr);
73       options->v0 = options->J = options->invJ = options->detJ = NULL;
74     }
75     ierr = PetscOptionsRealArray("-centroid", "Input centroid for each cell", "ex8.c", options->centroid, &n, &flg);CHKERRQ(ierr);
76     PetscCheckFalse(flg && n != numCells*dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of centroid %D should be %D", n, numCells*dim);
77     if (!flg) {
78       ierr = PetscFree(options->centroid);CHKERRQ(ierr);
79       options->centroid = NULL;
80     }
81     n    = numCells*dim;
82     ierr = PetscOptionsRealArray("-normal", "Input normal for each cell", "ex8.c", options->normal, &n, &flg);CHKERRQ(ierr);
83     PetscCheckFalse(flg && n != numCells*dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of normal %D should be %D", n, numCells*dim);
84     if (!flg) {
85       ierr = PetscFree(options->normal);CHKERRQ(ierr);
86       options->normal = NULL;
87     }
88     n    = numCells;
89     ierr = PetscOptionsRealArray("-vol", "Input volume for each cell", "ex8.c", options->vol, &n, &flg);CHKERRQ(ierr);
90     PetscCheckFalse(flg && n != numCells,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of vol %D should be %D", n, numCells);
91     if (!flg) {
92       ierr = PetscFree(options->vol);CHKERRQ(ierr);
93       options->vol = NULL;
94     }
95   } else if (options->runType == RUN_DISPLAY) {
96     ierr = ReadMesh(PETSC_COMM_WORLD, options, &options->dm);CHKERRQ(ierr);
97   }
98   ierr = PetscOptionsEnd();CHKERRQ(ierr);
99 
100   if (options->transform) {ierr = PetscPrintf(comm, "Using random transforms\n");CHKERRQ(ierr);}
101   PetscFunctionReturn(0);
102 }
103 
104 static PetscErrorCode ChangeCoordinates(DM dm, PetscInt spaceDim, PetscScalar vertexCoords[])
105 {
106   PetscSection   coordSection;
107   Vec            coordinates;
108   PetscScalar   *coords;
109   PetscInt       vStart, vEnd, v, d, coordSize;
110   PetscErrorCode ierr;
111 
112   PetscFunctionBegin;
113   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
114   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
115   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
116   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
117   ierr = PetscSectionSetChart(coordSection, vStart, vEnd);CHKERRQ(ierr);
118   for (v = vStart; v < vEnd; ++v) {
119     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
120     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
121   }
122   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
123   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
124   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
125   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
126   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
127   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
128   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
129   for (v = vStart; v < vEnd; ++v) {
130     PetscInt off;
131 
132     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
133     for (d = 0; d < spaceDim; ++d) {
134       coords[off+d] = vertexCoords[(v-vStart)*spaceDim+d];
135     }
136   }
137   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
138   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
139   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
140   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
141   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
142   PetscFunctionReturn(0);
143 }
144 
145 #define RelativeError(a,b) PetscAbs(a-b)/(1.0+PetscMax(PetscAbs(a),PetscAbs(b)))
146 
147 static PetscErrorCode CheckFEMGeometry(DM dm, PetscInt cell, PetscInt spaceDim, PetscReal v0Ex[], PetscReal JEx[], PetscReal invJEx[], PetscReal detJEx)
148 {
149   PetscReal      v0[3], J[9], invJ[9], detJ;
150   PetscInt       d, i, j;
151   PetscErrorCode ierr;
152 
153   PetscFunctionBegin;
154   ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
155   for (d = 0; d < spaceDim; ++d) {
156     if (v0[d] != v0Ex[d]) {
157       switch (spaceDim) {
158       case 2: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid v0 (%g, %g) != (%g, %g)", (double)v0[0], (double)v0[1], (double)v0Ex[0], (double)v0Ex[1]);
159       case 3: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid v0 (%g, %g, %g) != (%g, %g, %g)", (double)v0[0], (double)v0[1], (double)v0[2], (double)v0Ex[0], (double)v0Ex[1], (double)v0Ex[2]);
160       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid space dimension %D", spaceDim);
161       }
162     }
163   }
164   for (i = 0; i < spaceDim; ++i) {
165     for (j = 0; j < spaceDim; ++j) {
166       PetscCheckFalse(RelativeError(J[i*spaceDim+j],JEx[i*spaceDim+j])    > 10*PETSC_SMALL,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid J[%D,%D]: %g != %g", i, j, (double)J[i*spaceDim+j], (double)JEx[i*spaceDim+j]);
167       PetscCheckFalse(RelativeError(invJ[i*spaceDim+j],invJEx[i*spaceDim+j]) > 10*PETSC_SMALL,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid invJ[%D,%D]: %g != %g", i, j, (double)invJ[i*spaceDim+j], (double)invJEx[i*spaceDim+j]);
168     }
169   }
170   PetscCheckFalse(RelativeError(detJ,detJEx) > 10*PETSC_SMALL,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid |J| = %g != %g diff %g", (double)detJ, (double)detJEx,(double)(detJ - detJEx));
171   PetscFunctionReturn(0);
172 }
173 
174 static PetscErrorCode CheckFVMGeometry(DM dm, PetscInt cell, PetscInt spaceDim, PetscReal centroidEx[], PetscReal normalEx[], PetscReal volEx)
175 {
176   PetscReal      tol = PetscMax(10*PETSC_SMALL, 1e-10);
177   PetscReal      centroid[3], normal[3], vol;
178   PetscInt       d;
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   ierr = DMPlexComputeCellGeometryFVM(dm, cell, volEx? &vol : NULL, centroidEx? centroid : NULL, normalEx? normal : NULL);CHKERRQ(ierr);
183   for (d = 0; d < spaceDim; ++d) {
184     if (centroidEx)
185       PetscCheckFalse(RelativeError(centroid[d],centroidEx[d]) > tol,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %D, Invalid centroid[%D]: %g != %g diff %g", cell, d, (double)centroid[d], (double)centroidEx[d],(double)(centroid[d]-centroidEx[d]));
186     if (normalEx)
187       PetscCheckFalse(RelativeError(normal[d],normalEx[d]) > tol,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %D, Invalid normal[%D]: %g != %g", cell, d, (double)normal[d], (double)normalEx[d]);
188   }
189   if (volEx)
190     PetscCheckFalse(RelativeError(volEx,vol) > tol,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %D, Invalid volume = %g != %g diff %g", cell, (double)vol, (double)volEx,(double)(vol - volEx));
191   PetscFunctionReturn(0);
192 }
193 
194 static PetscErrorCode CheckGaussLaw(DM dm, PetscInt cell)
195 {
196   DMPolytopeType  ct;
197   PetscReal       tol = PetscMax(10*PETSC_SMALL, 1e-10);
198   PetscReal       normal[3], integral[3] = {0., 0., 0.}, area;
199   const PetscInt *cone, *ornt;
200   PetscInt        coneSize, f, dim, cdim, d;
201   PetscErrorCode  ierr;
202 
203   PetscFunctionBegin;
204   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
205   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
206   if (dim != cdim) PetscFunctionReturn(0);
207   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
208   if (ct == DM_POLYTOPE_TRI_PRISM_TENSOR) PetscFunctionReturn(0);
209   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
210   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
211   ierr = DMPlexGetConeOrientation(dm, cell, &ornt);CHKERRQ(ierr);
212   for (f = 0; f < coneSize; ++f) {
213     const PetscInt sgn = dim == 1? (f == 0 ? -1 : 1) : (ornt[f] < 0 ? -1 : 1);
214 
215     ierr = DMPlexComputeCellGeometryFVM(dm, cone[f], &area, NULL, normal);CHKERRQ(ierr);
216     for (d = 0; d < cdim; ++d) integral[d] += sgn*area*normal[d];
217   }
218   for (d = 0; d < cdim; ++d) PetscCheckFalse(PetscAbsReal(integral[d]) > tol,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %D Surface integral for component %D: %g != 0. as it should be for a constant field", cell, d, (double) integral[d]);
219   PetscFunctionReturn(0);
220 }
221 
222 static PetscErrorCode CheckCell(DM dm, PetscInt cell, PetscBool transform, PetscReal v0Ex[], PetscReal JEx[], PetscReal invJEx[], PetscReal detJEx, PetscReal centroidEx[], PetscReal normalEx[], PetscReal volEx, PetscReal faceCentroidEx[], PetscReal faceNormalEx[], PetscReal faceVolEx[])
223 {
224   const PetscInt *cone;
225   PetscInt        coneSize, c;
226   PetscInt        dim, depth, cdim;
227   PetscErrorCode  ierr;
228 
229   PetscFunctionBegin;
230   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
231   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
232   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
233   if (v0Ex) {
234     ierr = CheckFEMGeometry(dm, cell, cdim, v0Ex, JEx, invJEx, detJEx);CHKERRQ(ierr);
235   }
236   if (dim == depth && centroidEx) {
237     ierr = CheckFVMGeometry(dm, cell, cdim, centroidEx, normalEx, volEx);CHKERRQ(ierr);
238     ierr = CheckGaussLaw(dm, cell);CHKERRQ(ierr);
239     if (faceCentroidEx) {
240       ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
241       ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
242       for (c = 0; c < coneSize; ++c) {
243         ierr = CheckFVMGeometry(dm, cone[c], dim, &faceCentroidEx[c*dim], &faceNormalEx[c*dim], faceVolEx[c]);CHKERRQ(ierr);
244       }
245     }
246   }
247   if (transform) {
248     Vec          coordinates;
249     PetscSection coordSection;
250     PetscScalar *coords = NULL, *origCoords, *newCoords;
251     PetscReal   *v0ExT, *JExT, *invJExT, detJExT=0, *centroidExT, *normalExT, volExT=0;
252     PetscReal   *faceCentroidExT, *faceNormalExT, faceVolExT;
253     PetscRandom  r, ang, ang2;
254     PetscInt     coordSize, numCorners, t;
255 
256     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
257     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
258     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr);
259     ierr = PetscMalloc2(coordSize, &origCoords, coordSize, &newCoords);CHKERRQ(ierr);
260     ierr = PetscMalloc5(cdim, &v0ExT, cdim*cdim, &JExT, cdim*cdim, &invJExT, cdim, &centroidExT, cdim, &normalExT);CHKERRQ(ierr);
261     ierr = PetscMalloc2(cdim, &faceCentroidExT, cdim, &faceNormalExT);CHKERRQ(ierr);
262     for (c = 0; c < coordSize; ++c) origCoords[c] = coords[c];
263     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr);
264     numCorners = coordSize/cdim;
265 
266     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
267     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
268     ierr = PetscRandomSetInterval(r, 0.0, 10.0);CHKERRQ(ierr);
269     ierr = PetscRandomCreate(PETSC_COMM_SELF, &ang);CHKERRQ(ierr);
270     ierr = PetscRandomSetFromOptions(ang);CHKERRQ(ierr);
271     ierr = PetscRandomSetInterval(ang, 0.0, 2*PETSC_PI);CHKERRQ(ierr);
272     ierr = PetscRandomCreate(PETSC_COMM_SELF, &ang2);CHKERRQ(ierr);
273     ierr = PetscRandomSetFromOptions(ang2);CHKERRQ(ierr);
274     ierr = PetscRandomSetInterval(ang2, 0.0, PETSC_PI);CHKERRQ(ierr);
275     for (t = 0; t < 1; ++t) {
276       PetscScalar trans[3];
277       PetscReal   R[9], rot[3], rotM[9];
278       PetscReal   scale, phi, theta, psi = 0.0, norm;
279       PetscInt    d, e, f, p;
280 
281       for (c = 0; c < coordSize; ++c) newCoords[c] = origCoords[c];
282       ierr = PetscRandomGetValueReal(r, &scale);CHKERRQ(ierr);
283       ierr = PetscRandomGetValueReal(ang, &phi);CHKERRQ(ierr);
284       ierr = PetscRandomGetValueReal(ang2, &theta);CHKERRQ(ierr);
285       for (d = 0; d < cdim; ++d) {
286         ierr = PetscRandomGetValue(r, &trans[d]);CHKERRQ(ierr);
287       }
288       switch (cdim) {
289       case 2:
290         R[0] = PetscCosReal(phi); R[1] = -PetscSinReal(phi);
291         R[2] = PetscSinReal(phi); R[3] =  PetscCosReal(phi);
292         break;
293       case 3:
294       {
295         const PetscReal ct = PetscCosReal(theta), st = PetscSinReal(theta);
296         const PetscReal cp = PetscCosReal(phi),   sp = PetscSinReal(phi);
297         const PetscReal cs = PetscCosReal(psi),   ss = PetscSinReal(psi);
298         R[0] = ct*cs; R[1] = sp*st*cs - cp*ss;    R[2] = sp*ss    + cp*st*cs;
299         R[3] = ct*ss; R[4] = cp*cs    + sp*st*ss; R[5] = cp*st*ss - sp*cs;
300         R[6] = -st;   R[7] = sp*ct;               R[8] = cp*ct;
301         break;
302       }
303       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Invalid coordinate dimension %D", cdim);
304       }
305       if (v0Ex) {
306         detJExT = detJEx;
307         for (d = 0; d < cdim; ++d) {
308           v0ExT[d] = v0Ex[d];
309           for (e = 0; e < cdim; ++e) {
310             JExT[d*cdim+e]    = JEx[d*cdim+e];
311             invJExT[d*cdim+e] = invJEx[d*cdim+e];
312           }
313         }
314         for (d = 0; d < cdim; ++d) {
315           v0ExT[d] *= scale;
316           v0ExT[d] += PetscRealPart(trans[d]);
317           /* Only scale dimensions in the manifold */
318           for (e = 0; e < dim; ++e) {
319             JExT[d*cdim+e]    *= scale;
320             invJExT[d*cdim+e] /= scale;
321           }
322           if (d < dim) detJExT *= scale;
323         }
324         /* Do scaling and translation before rotation, so that we can leave out the normal dimension for lower dimensional manifolds */
325         for (d = 0; d < cdim; ++d) {
326           for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
327             rot[d] += R[d*cdim+e] * v0ExT[e];
328           }
329         }
330         for (d = 0; d < cdim; ++d) v0ExT[d] = rot[d];
331         for (d = 0; d < cdim; ++d) {
332           for (e = 0; e < cdim; ++e) {
333             for (f = 0, rotM[d*cdim+e] = 0.0; f < cdim; ++f) {
334               rotM[d*cdim+e] += R[d*cdim+f] * JExT[f*cdim+e];
335             }
336           }
337         }
338         for (d = 0; d < cdim; ++d) {
339           for (e = 0; e < cdim; ++e) {
340             JExT[d*cdim+e] = rotM[d*cdim+e];
341           }
342         }
343         for (d = 0; d < cdim; ++d) {
344           for (e = 0; e < cdim; ++e) {
345             for (f = 0, rotM[d*cdim+e] = 0.0; f < cdim; ++f) {
346               rotM[d*cdim+e] += invJExT[d*cdim+f] * R[e*cdim+f];
347             }
348           }
349         }
350         for (d = 0; d < cdim; ++d) {
351           for (e = 0; e < cdim; ++e) {
352             invJExT[d*cdim+e] = rotM[d*cdim+e];
353           }
354         }
355       }
356       if (centroidEx) {
357         volExT = volEx;
358         for (d = 0; d < cdim; ++d) {
359           centroidExT[d]  = centroidEx[d];
360           normalExT[d]    = normalEx[d];
361         }
362         for (d = 0; d < cdim; ++d) {
363           centroidExT[d] *= scale;
364           centroidExT[d] += PetscRealPart(trans[d]);
365           normalExT[d]   /= scale;
366           /* Only scale dimensions in the manifold */
367           if (d < dim) volExT  *= scale;
368         }
369         /* Do scaling and translation before rotation, so that we can leave out the normal dimension for lower dimensional manifolds */
370         for (d = 0; d < cdim; ++d) {
371           for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
372             rot[d] += R[d*cdim+e] * centroidExT[e];
373           }
374         }
375         for (d = 0; d < cdim; ++d) centroidExT[d] = rot[d];
376         for (d = 0; d < cdim; ++d) {
377           for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
378             rot[d] += R[d*cdim+e] * normalExT[e];
379           }
380         }
381         for (d = 0; d < cdim; ++d) normalExT[d] = rot[d];
382         for (d = 0, norm = 0.0; d < cdim; ++d) norm += PetscSqr(normalExT[d]);
383         norm = PetscSqrtReal(norm);
384         for (d = 0; d < cdim; ++d) normalExT[d] /= norm;
385       }
386       for (d = 0; d < cdim; ++d) {
387         for (p = 0; p < numCorners; ++p) {
388           newCoords[p*cdim+d] *= scale;
389           newCoords[p*cdim+d] += trans[d];
390         }
391       }
392       for (p = 0; p < numCorners; ++p) {
393         for (d = 0; d < cdim; ++d) {
394           for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
395             rot[d] += R[d*cdim+e] * PetscRealPart(newCoords[p*cdim+e]);
396           }
397         }
398         for (d = 0; d < cdim; ++d) newCoords[p*cdim+d] = rot[d];
399       }
400 
401       ierr = ChangeCoordinates(dm, cdim, newCoords);CHKERRQ(ierr);
402       if (v0Ex) {
403         ierr = CheckFEMGeometry(dm, 0, cdim, v0ExT, JExT, invJExT, detJExT);CHKERRQ(ierr);
404       }
405       if (dim == depth && centroidEx) {
406         ierr = CheckFVMGeometry(dm, cell, cdim, centroidExT, normalExT, volExT);CHKERRQ(ierr);
407         ierr = CheckGaussLaw(dm, cell);CHKERRQ(ierr);
408         if (faceCentroidEx) {
409           ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
410           ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
411           for (c = 0; c < coneSize; ++c) {
412             PetscInt off = c*cdim;
413 
414             faceVolExT = faceVolEx[c];
415             for (d = 0; d < cdim; ++d) {
416               faceCentroidExT[d]  = faceCentroidEx[off+d];
417               faceNormalExT[d]    = faceNormalEx[off+d];
418             }
419             for (d = 0; d < cdim; ++d) {
420               faceCentroidExT[d] *= scale;
421               faceCentroidExT[d] += PetscRealPart(trans[d]);
422               faceNormalExT[d]   /= scale;
423               /* Only scale dimensions in the manifold */
424               if (d < dim-1) {
425                 faceVolExT *= scale;
426               }
427             }
428             for (d = 0; d < cdim; ++d) {
429               for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
430                 rot[d] += R[d*cdim+e] * faceCentroidExT[e];
431               }
432             }
433             for (d = 0; d < cdim; ++d) faceCentroidExT[d] = rot[d];
434             for (d = 0; d < cdim; ++d) {
435               for (e = 0, rot[d] = 0.0; e < cdim; ++e) {
436                 rot[d] += R[d*cdim+e] * faceNormalExT[e];
437               }
438             }
439             for (d = 0; d < cdim; ++d) faceNormalExT[d] = rot[d];
440             for (d = 0, norm = 0.0; d < cdim; ++d) norm += PetscSqr(faceNormalExT[d]);
441             norm = PetscSqrtReal(norm);
442             for (d = 0; d < cdim; ++d) faceNormalExT[d] /= norm;
443 
444             ierr = CheckFVMGeometry(dm, cone[c], cdim, faceCentroidExT, faceNormalExT, faceVolExT);CHKERRQ(ierr);
445           }
446         }
447       }
448     }
449     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
450     ierr = PetscRandomDestroy(&ang);CHKERRQ(ierr);
451     ierr = PetscRandomDestroy(&ang2);CHKERRQ(ierr);
452     ierr = PetscFree2(origCoords, newCoords);CHKERRQ(ierr);
453     ierr = PetscFree5(v0ExT, JExT, invJExT, centroidExT, normalExT);CHKERRQ(ierr);
454     ierr = PetscFree2(faceCentroidExT, faceNormalExT);CHKERRQ(ierr);
455   }
456   PetscFunctionReturn(0);
457 }
458 
459 static PetscErrorCode TestTriangle(MPI_Comm comm, PetscBool transform)
460 {
461   DM             dm;
462   PetscErrorCode ierr;
463 
464   PetscFunctionBegin;
465   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TRIANGLE, &dm);CHKERRQ(ierr);
466   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
467   /* Check reference geometry: determinant is scaled by reference volume (2.0) */
468   {
469     PetscReal v0Ex[2]       = {-1.0, -1.0};
470     PetscReal JEx[4]        = {1.0, 0.0, 0.0, 1.0};
471     PetscReal invJEx[4]     = {1.0, 0.0, 0.0, 1.0};
472     PetscReal detJEx        = 1.0;
473     PetscReal centroidEx[2] = {-((PetscReal)1.)/((PetscReal)3.), -((PetscReal)1.)/((PetscReal)3.)};
474     PetscReal normalEx[2]   = {0.0, 0.0};
475     PetscReal volEx         = 2.0;
476 
477     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
478   }
479   /* Move to 3D: Check reference geometry: determinant is scaled by reference volume (2.0) */
480   {
481     PetscScalar vertexCoords[9] = {-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0};
482     PetscReal   v0Ex[3]         = {-1.0, -1.0, 0.0};
483     PetscReal   JEx[9]          = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
484     PetscReal   invJEx[9]       = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
485     PetscReal   detJEx          = 1.0;
486     PetscReal   centroidEx[3]   = {-((PetscReal)1.)/((PetscReal)3.), -((PetscReal)1.)/((PetscReal)3.), 0.0};
487     PetscReal   normalEx[3]     = {0.0, 0.0, 1.0};
488     PetscReal   volEx           = 2.0;
489 
490     ierr = ChangeCoordinates(dm, 3, vertexCoords);CHKERRQ(ierr);
491     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
492   }
493   /* Cleanup */
494   ierr = DMDestroy(&dm);CHKERRQ(ierr);
495   PetscFunctionReturn(0);
496 }
497 
498 static PetscErrorCode TestQuadrilateral(MPI_Comm comm, PetscBool transform)
499 {
500   DM             dm;
501   PetscErrorCode ierr;
502 
503   PetscFunctionBegin;
504   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_QUADRILATERAL, &dm);CHKERRQ(ierr);
505   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
506   /* Check reference geometry: determinant is scaled by reference volume (2.0) */
507   {
508     PetscReal v0Ex[2]       = {-1.0, -1.0};
509     PetscReal JEx[4]        = {1.0, 0.0, 0.0, 1.0};
510     PetscReal invJEx[4]     = {1.0, 0.0, 0.0, 1.0};
511     PetscReal detJEx        = 1.0;
512     PetscReal centroidEx[2] = {0.0, 0.0};
513     PetscReal normalEx[2]   = {0.0, 0.0};
514     PetscReal volEx         = 4.0;
515 
516     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
517   }
518   /* Move to 3D: Check reference geometry: determinant is scaled by reference volume (4.0) */
519   {
520     PetscScalar vertexCoords[12] = {-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0};
521     PetscReal   v0Ex[3]          = {-1.0, -1.0, 0.0};
522     PetscReal   JEx[9]           = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
523     PetscReal   invJEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
524     PetscReal   detJEx           = 1.0;
525     PetscReal   centroidEx[3]    = {0.0, 0.0, 0.0};
526     PetscReal   normalEx[3]      = {0.0, 0.0, 1.0};
527     PetscReal   volEx            = 4.0;
528 
529     ierr = ChangeCoordinates(dm, 3, vertexCoords);CHKERRQ(ierr);
530     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
531   }
532   /* Cleanup */
533   ierr = DMDestroy(&dm);CHKERRQ(ierr);
534   PetscFunctionReturn(0);
535 }
536 
537 static PetscErrorCode TestTetrahedron(MPI_Comm comm, PetscBool transform)
538 {
539   DM             dm;
540   PetscErrorCode ierr;
541 
542   PetscFunctionBegin;
543   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TETRAHEDRON, &dm);CHKERRQ(ierr);
544   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
545   /* Check reference geometry: determinant is scaled by reference volume (4/3) */
546   {
547     PetscReal v0Ex[3]       = {-1.0, -1.0, -1.0};
548     PetscReal JEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
549     PetscReal invJEx[9]     = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
550     PetscReal detJEx        = 1.0;
551     PetscReal centroidEx[3] = {-0.5, -0.5, -0.5};
552     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
553     PetscReal volEx         = (PetscReal)4.0/(PetscReal)3.0;
554 
555     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
556   }
557   /* Cleanup */
558   ierr = DMDestroy(&dm);CHKERRQ(ierr);
559   PetscFunctionReturn(0);
560 }
561 
562 static PetscErrorCode TestHexahedron(MPI_Comm comm, PetscBool transform)
563 {
564   DM             dm;
565   PetscErrorCode ierr;
566 
567   PetscFunctionBegin;
568   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_HEXAHEDRON, &dm);CHKERRQ(ierr);
569   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
570   /* Check reference geometry: determinant is scaled by reference volume 8.0 */
571   {
572     PetscReal v0Ex[3]       = {-1.0, -1.0, -1.0};
573     PetscReal JEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
574     PetscReal invJEx[9]     = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
575     PetscReal detJEx        = 1.0;
576     PetscReal centroidEx[3] = {0.0, 0.0, 0.0};
577     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
578     PetscReal volEx         = 8.0;
579 
580     ierr = CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
581   }
582   /* Cleanup */
583   ierr = DMDestroy(&dm);CHKERRQ(ierr);
584   PetscFunctionReturn(0);
585 }
586 
587 static PetscErrorCode TestHexahedronCurved(MPI_Comm comm)
588 {
589   DM             dm;
590   PetscScalar    coords[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,
591                                -1.0, -1.0,  1.1,   1.0, -1.0,  1.0,  1.0, 1.0,  1.1,  -1.0,  1.0,  1.0};
592   PetscErrorCode ierr;
593 
594   PetscFunctionBegin;
595   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_HEXAHEDRON, &dm);CHKERRQ(ierr);
596   ierr = ChangeCoordinates(dm, 3, coords);CHKERRQ(ierr);
597   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
598   {
599     PetscReal centroidEx[3] = {0.0, 0.0, 0.016803278688524603};
600     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
601     PetscReal volEx         = 8.1333333333333346;
602 
603     ierr = CheckCell(dm, 0, PETSC_FALSE, NULL, NULL, NULL, 0.0, centroidEx, normalEx, volEx, NULL, NULL, NULL);CHKERRQ(ierr);
604   }
605   ierr = DMDestroy(&dm);CHKERRQ(ierr);
606   PetscFunctionReturn(0);
607 }
608 
609 /* This wedge is a tensor product cell, rather than a normal wedge */
610 static PetscErrorCode TestWedge(MPI_Comm comm, PetscBool transform)
611 {
612   DM             dm;
613   PetscErrorCode ierr;
614 
615   PetscFunctionBegin;
616   ierr = DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TRI_PRISM_TENSOR, &dm);CHKERRQ(ierr);
617   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
618   /* Check reference geometry: determinant is scaled by reference volume 4.0 */
619   {
620 #if 0
621     /* FEM geometry is not functional for wedges */
622     PetscReal v0Ex[3]   = {-1.0, -1.0, -1.0};
623     PetscReal JEx[9]    = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
624     PetscReal invJEx[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
625     PetscReal detJEx    = 1.0;
626 #endif
627 
628     {
629       PetscReal       centroidEx[3]      = {-((PetscReal)1.)/((PetscReal)3.), -((PetscReal)1.)/((PetscReal)3.), 0.0};
630       PetscReal       normalEx[3]        = {0.0, 0.0, 0.0};
631       PetscReal       volEx              = 4.0;
632       PetscReal       faceVolEx[5]       = {2.0, 2.0, 4.0, PETSC_SQRT2*4.0, 4.0};
633       PetscReal       faceNormalEx[15]   = {0.0, 0.0, 1.0,  0.0, 0.0, 1.0,  0.0, -1.0, 0.0,  PETSC_SQRT2/2.0, PETSC_SQRT2/2.0, 0.0,  -1.0, 0.0, 0.0};
634       PetscReal       faceCentroidEx[15] = {-((PetscReal)1.)/((PetscReal)3.), -((PetscReal)1.)/((PetscReal)3.), -1.0,
635                                             -((PetscReal)1.)/((PetscReal)3.), -((PetscReal)1.)/((PetscReal)3.),  1.0,
636                                             0.0, -1.0, 0.0,  0.0, 0.0, 0.0,  -1.0, 0.0, 0.0};
637 
638       ierr = CheckCell(dm, 0, transform, NULL, NULL, NULL, 0.0, centroidEx, normalEx, volEx, faceCentroidEx, faceNormalEx, faceVolEx);CHKERRQ(ierr);
639     }
640   }
641   /* Cleanup */
642   ierr = DMDestroy(&dm);CHKERRQ(ierr);
643   PetscFunctionReturn(0);
644 }
645 
646 int main(int argc, char **argv)
647 {
648   AppCtx         user;
649   PetscErrorCode ierr;
650 
651   ierr = PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr;
652   ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr);
653   if (user.runType == RUN_REFERENCE) {
654     ierr = TestTriangle(PETSC_COMM_SELF, user.transform);CHKERRQ(ierr);
655     ierr = TestQuadrilateral(PETSC_COMM_SELF, user.transform);CHKERRQ(ierr);
656     ierr = TestTetrahedron(PETSC_COMM_SELF, user.transform);CHKERRQ(ierr);
657     ierr = TestHexahedron(PETSC_COMM_SELF, user.transform);CHKERRQ(ierr);
658     ierr = TestWedge(PETSC_COMM_SELF, user.transform);CHKERRQ(ierr);
659   } else if (user.runType == RUN_HEX_CURVED) {
660     ierr = TestHexahedronCurved(PETSC_COMM_SELF);CHKERRQ(ierr);
661   } else if (user.runType == RUN_FILE) {
662     PetscInt dim, cStart, cEnd, c;
663 
664     ierr = DMGetDimension(user.dm, &dim);CHKERRQ(ierr);
665     ierr = DMPlexGetHeightStratum(user.dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
666     for (c = 0; c < cEnd-cStart; ++c) {
667       PetscReal *v0       = user.v0       ? &user.v0[c*dim] : NULL;
668       PetscReal *J        = user.J        ? &user.J[c*dim*dim] : NULL;
669       PetscReal *invJ     = user.invJ     ? &user.invJ[c*dim*dim] : NULL;
670       PetscReal  detJ     = user.detJ     ?  user.detJ[c] : 0.0;
671       PetscReal *centroid = user.centroid ? &user.centroid[c*dim] : NULL;
672       PetscReal *normal   = user.normal   ? &user.normal[c*dim] : NULL;
673       PetscReal  vol      = user.vol      ?  user.vol[c] : 0.0;
674 
675       ierr = CheckCell(user.dm, c+cStart, PETSC_FALSE, v0, J, invJ, detJ, centroid, normal, vol, NULL, NULL, NULL);CHKERRQ(ierr);
676     }
677     ierr = PetscFree4(user.v0,user.J,user.invJ,user.detJ);CHKERRQ(ierr);
678     ierr = PetscFree(user.centroid);CHKERRQ(ierr);
679     ierr = PetscFree(user.normal);CHKERRQ(ierr);
680     ierr = PetscFree(user.vol);CHKERRQ(ierr);
681     ierr = DMDestroy(&user.dm);CHKERRQ(ierr);
682   } else if (user.runType == RUN_DISPLAY) {
683     DM                 gdm, dmCell;
684     Vec                cellgeom, facegeom;
685     const PetscScalar *cgeom;
686     PetscInt           dim, d, cStart, cEnd, cEndInterior, c;
687 
688     ierr = DMGetCoordinateDim(user.dm, &dim);CHKERRQ(ierr);
689     ierr = DMPlexConstructGhostCells(user.dm, NULL, NULL, &gdm);CHKERRQ(ierr);
690     if (gdm) {
691       ierr = DMDestroy(&user.dm);CHKERRQ(ierr);
692       user.dm = gdm;
693     }
694     ierr = DMPlexComputeGeometryFVM(user.dm, &cellgeom, &facegeom);CHKERRQ(ierr);
695     ierr = DMPlexGetHeightStratum(user.dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
696     ierr = DMPlexGetGhostCellStratum(user.dm, &cEndInterior, NULL);CHKERRQ(ierr);
697     if (cEndInterior >= 0) cEnd = cEndInterior;
698     ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
699     ierr = VecGetArrayRead(cellgeom, &cgeom);CHKERRQ(ierr);
700     for (c = 0; c < cEnd-cStart; ++c) {
701       PetscFVCellGeom *cg;
702 
703       ierr = DMPlexPointLocalRead(dmCell, c, cgeom, &cg);CHKERRQ(ierr);
704       ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %4D: Centroid (", c);CHKERRQ(ierr);
705       for (d = 0; d < dim; ++d) {
706         if (d > 0) {ierr = PetscPrintf(PETSC_COMM_SELF, ", ");CHKERRQ(ierr);}
707         ierr = PetscPrintf(PETSC_COMM_SELF, "%12.2g", cg->centroid[d]);CHKERRQ(ierr);
708       }
709       ierr = PetscPrintf(PETSC_COMM_SELF, ") Vol %12.2g\n", cg->volume);CHKERRQ(ierr);
710     }
711     ierr = VecRestoreArrayRead(cellgeom, &cgeom);CHKERRQ(ierr);
712     ierr = VecDestroy(&cellgeom);CHKERRQ(ierr);
713     ierr = VecDestroy(&facegeom);CHKERRQ(ierr);
714     ierr = DMDestroy(&user.dm);CHKERRQ(ierr);
715   }
716   ierr = PetscFinalize();
717   return ierr;
718 }
719 
720 /*TEST
721 
722   test:
723     suffix: 1
724     args: -dm_view ascii::ascii_info_detail
725   test:
726     suffix: 2
727     args: -run_type hex_curved
728   test:
729     suffix: 3
730     args: -transform
731   test:
732     suffix: 4
733     requires: exodusii
734     args: -run_type file -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/simpleblock-100.exo -dm_view ascii::ascii_info_detail -v0 -1.5,-0.5,0.5,-0.5,-0.5,0.5,0.5,-0.5,0.5 -J 0.0,0.0,0.5,0.0,0.5,0.0,-0.5,0.0,0.0,0.0,0.0,0.5,0.0,0.5,0.0,-0.5,0.0,0.0,0.0,0.0,0.5,0.0,0.5,0.0,-0.5,0.0,0.0 -invJ 0.0,0.0,-2.0,0.0,2.0,0.0,2.0,0.0,0.0,0.0,0.0,-2.0,0.0,2.0,0.0,2.0,0.0,0.0,0.0,0.0,-2.0,0.0,2.0,0.0,2.0,0.0,0.0 -detJ 0.125,0.125,0.125 -centroid -1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -normal 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -vol 1.0,1.0,1.0
735   test:
736     suffix: 5
737     args: -run_type file -dm_plex_dim 3 -dm_plex_simplex 0 -dm_plex_box_faces 3,1,1 -dm_plex_box_lower -1.5,-0.5,-0.5 -dm_plex_box_upper 1.5,0.5,0.5 -dm_view ascii::ascii_info_detail -centroid -1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -normal 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -vol 1.0,1.0,1.0
738   test:
739     suffix: 6
740     args: -run_type file -dm_plex_dim 1 -dm_plex_simplex 0 -dm_plex_box_faces 3 -dm_plex_box_lower -1.5 -dm_plex_box_upper 1.5 -dm_view ascii::ascii_info_detail -centroid -1.0,0.0,1.0 -vol 1.0,1.0,1.0
741 TEST*/
742