xref: /petsc/src/dm/impls/plex/tests/ex8.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1c4762a1bSJed Brown static char help[] = "Tests for cell geometry\n\n";
2c4762a1bSJed Brown 
3c4762a1bSJed Brown #include <petscdmplex.h>
4c4762a1bSJed Brown 
59371c9d4SSatish Balay typedef enum {
69371c9d4SSatish Balay   RUN_REFERENCE,
79371c9d4SSatish Balay   RUN_HEX_CURVED,
89371c9d4SSatish Balay   RUN_FILE,
99371c9d4SSatish Balay   RUN_DISPLAY
109371c9d4SSatish Balay } RunType;
11c4762a1bSJed Brown 
12c4762a1bSJed Brown typedef struct {
13c4762a1bSJed Brown   DM         dm;
14c4762a1bSJed Brown   RunType    runType;   /* Type of mesh to use */
15c4762a1bSJed Brown   PetscBool  transform; /* Use random coordinate transformations */
16c4762a1bSJed Brown   /* Data for input meshes */
17c4762a1bSJed Brown   PetscReal *v0, *J, *invJ, *detJ;    /* FEM data */
18c4762a1bSJed Brown   PetscReal *centroid, *normal, *vol; /* FVM data */
19c4762a1bSJed Brown } AppCtx;
20c4762a1bSJed Brown 
219371c9d4SSatish Balay static PetscErrorCode ReadMesh(MPI_Comm comm, AppCtx *user, DM *dm) {
22c4762a1bSJed Brown   PetscFunctionBegin;
239566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
249566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
259566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
269566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*dm, user));
279566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*dm, "Input Mesh"));
289566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
29c4762a1bSJed Brown   PetscFunctionReturn(0);
30c4762a1bSJed Brown }
31c4762a1bSJed Brown 
329371c9d4SSatish Balay static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) {
334f99dae5SMatthew G. Knepley   const char *runTypes[4] = {"reference", "hex_curved", "file", "display"};
34c4762a1bSJed Brown   PetscInt    run;
35c4762a1bSJed Brown 
36c4762a1bSJed Brown   PetscFunctionBeginUser;
37c4762a1bSJed Brown   options->runType   = RUN_REFERENCE;
38c4762a1bSJed Brown   options->transform = PETSC_FALSE;
39c4762a1bSJed Brown 
40d0609cedSBarry Smith   PetscOptionsBegin(comm, "", "Geometry Test Options", "DMPLEX");
41c4762a1bSJed Brown   run = options->runType;
429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-run_type", "The run type", "ex8.c", runTypes, 3, runTypes[options->runType], &run, NULL));
43c4762a1bSJed Brown   options->runType = (RunType)run;
449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-transform", "Use random transforms", "ex8.c", options->transform, &options->transform, NULL));
45c4762a1bSJed Brown 
46c4762a1bSJed Brown   if (options->runType == RUN_FILE) {
47c4762a1bSJed Brown     PetscInt  dim, cStart, cEnd, numCells, n;
489bf2564aSMatt McGurn     PetscBool flg, feFlg;
49c4762a1bSJed Brown 
509566063dSJacob Faibussowitsch     PetscCall(ReadMesh(PETSC_COMM_WORLD, options, &options->dm));
519566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(options->dm, &dim));
529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(options->dm, 0, &cStart, &cEnd));
53c4762a1bSJed Brown     numCells = cEnd - cStart;
549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc4(numCells * dim, &options->v0, numCells * dim * dim, &options->J, numCells * dim * dim, &options->invJ, numCells, &options->detJ));
559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numCells * dim, &options->centroid));
569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numCells * dim, &options->normal));
579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numCells, &options->vol));
58c4762a1bSJed Brown     n = numCells * dim;
599566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-v0", "Input v0 for each cell", "ex8.c", options->v0, &n, &feFlg));
6063a3b9bcSJacob Faibussowitsch     PetscCheck(!feFlg || n == numCells * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of v0 %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells * dim);
61c4762a1bSJed Brown     n = numCells * dim * dim;
629566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-J", "Input Jacobian for each cell", "ex8.c", options->J, &n, &flg));
6363a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells * dim * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of J %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells * dim * dim);
64c4762a1bSJed Brown     n = numCells * dim * dim;
659566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-invJ", "Input inverse Jacobian for each cell", "ex8.c", options->invJ, &n, &flg));
6663a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells * dim * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of invJ %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells * dim * dim);
67c4762a1bSJed Brown     n = numCells;
689566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-detJ", "Input Jacobian determinant for each cell", "ex8.c", options->detJ, &n, &flg));
6963a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of detJ %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells);
70c4762a1bSJed Brown     n = numCells * dim;
714f99dae5SMatthew G. Knepley     if (!feFlg) {
729566063dSJacob Faibussowitsch       PetscCall(PetscFree4(options->v0, options->J, options->invJ, options->detJ));
734f99dae5SMatthew G. Knepley       options->v0 = options->J = options->invJ = options->detJ = NULL;
744f99dae5SMatthew G. Knepley     }
759566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-centroid", "Input centroid for each cell", "ex8.c", options->centroid, &n, &flg));
7663a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of centroid %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells * dim);
779bf2564aSMatt McGurn     if (!flg) {
789566063dSJacob Faibussowitsch       PetscCall(PetscFree(options->centroid));
799bf2564aSMatt McGurn       options->centroid = NULL;
809bf2564aSMatt McGurn     }
81c4762a1bSJed Brown     n = numCells * dim;
829566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-normal", "Input normal for each cell", "ex8.c", options->normal, &n, &flg));
8363a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of normal %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells * dim);
849bf2564aSMatt McGurn     if (!flg) {
859566063dSJacob Faibussowitsch       PetscCall(PetscFree(options->normal));
869bf2564aSMatt McGurn       options->normal = NULL;
879bf2564aSMatt McGurn     }
88c4762a1bSJed Brown     n = numCells;
899566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-vol", "Input volume for each cell", "ex8.c", options->vol, &n, &flg));
9063a3b9bcSJacob Faibussowitsch     PetscCheck(!flg || n == numCells, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid size of vol %" PetscInt_FMT " should be %" PetscInt_FMT, n, numCells);
919bf2564aSMatt McGurn     if (!flg) {
929566063dSJacob Faibussowitsch       PetscCall(PetscFree(options->vol));
939bf2564aSMatt McGurn       options->vol = NULL;
944f99dae5SMatthew G. Knepley     }
95c4762a1bSJed Brown   } else if (options->runType == RUN_DISPLAY) {
969566063dSJacob Faibussowitsch     PetscCall(ReadMesh(PETSC_COMM_WORLD, options, &options->dm));
97c4762a1bSJed Brown   }
98d0609cedSBarry Smith   PetscOptionsEnd();
99c4762a1bSJed Brown 
1009566063dSJacob Faibussowitsch   if (options->transform) PetscCall(PetscPrintf(comm, "Using random transforms\n"));
101c4762a1bSJed Brown   PetscFunctionReturn(0);
102c4762a1bSJed Brown }
103c4762a1bSJed Brown 
1049371c9d4SSatish Balay static PetscErrorCode ChangeCoordinates(DM dm, PetscInt spaceDim, PetscScalar vertexCoords[]) {
105c4762a1bSJed Brown   PetscSection coordSection;
106c4762a1bSJed Brown   Vec          coordinates;
107c4762a1bSJed Brown   PetscScalar *coords;
108c4762a1bSJed Brown   PetscInt     vStart, vEnd, v, d, coordSize;
109c4762a1bSJed Brown 
110c4762a1bSJed Brown   PetscFunctionBegin;
1119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1129566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
1139566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
1149566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
1159566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
116c4762a1bSJed Brown   for (v = vStart; v < vEnd; ++v) {
1179566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
1189566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
119c4762a1bSJed Brown   }
1209566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
1219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1229566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1239566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1249566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1259566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(coordinates));
1269566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
127c4762a1bSJed Brown   for (v = vStart; v < vEnd; ++v) {
128c4762a1bSJed Brown     PetscInt off;
129c4762a1bSJed Brown 
1309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, v, &off));
1319371c9d4SSatish Balay     for (d = 0; d < spaceDim; ++d) { coords[off + d] = vertexCoords[(v - vStart) * spaceDim + d]; }
132c4762a1bSJed Brown   }
1339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
1349566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, spaceDim));
1359566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
1379566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
138c4762a1bSJed Brown   PetscFunctionReturn(0);
139c4762a1bSJed Brown }
140c4762a1bSJed Brown 
141c4762a1bSJed Brown #define RelativeError(a, b) PetscAbs(a - b) / (1.0 + PetscMax(PetscAbs(a), PetscAbs(b)))
142c4762a1bSJed Brown 
1439371c9d4SSatish Balay static PetscErrorCode CheckFEMGeometry(DM dm, PetscInt cell, PetscInt spaceDim, PetscReal v0Ex[], PetscReal JEx[], PetscReal invJEx[], PetscReal detJEx) {
144c4762a1bSJed Brown   PetscReal v0[3], J[9], invJ[9], detJ;
145c4762a1bSJed Brown   PetscInt  d, i, j;
146c4762a1bSJed Brown 
147c4762a1bSJed Brown   PetscFunctionBegin;
1489566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, invJ, &detJ));
149c4762a1bSJed Brown   for (d = 0; d < spaceDim; ++d) {
150c4762a1bSJed Brown     if (v0[d] != v0Ex[d]) {
151c4762a1bSJed Brown       switch (spaceDim) {
15298921bdaSJacob Faibussowitsch       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]);
15398921bdaSJacob Faibussowitsch       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]);
15463a3b9bcSJacob Faibussowitsch       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid space dimension %" PetscInt_FMT, spaceDim);
155c4762a1bSJed Brown       }
156c4762a1bSJed Brown     }
157c4762a1bSJed Brown   }
158c4762a1bSJed Brown   for (i = 0; i < spaceDim; ++i) {
159c4762a1bSJed Brown     for (j = 0; j < spaceDim; ++j) {
16063a3b9bcSJacob Faibussowitsch       PetscCheck(RelativeError(J[i * spaceDim + j], JEx[i * spaceDim + j]) < 10 * PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid J[%" PetscInt_FMT ",%" PetscInt_FMT "]: %g != %g", i, j, (double)J[i * spaceDim + j], (double)JEx[i * spaceDim + j]);
16163a3b9bcSJacob Faibussowitsch       PetscCheck(RelativeError(invJ[i * spaceDim + j], invJEx[i * spaceDim + j]) < 10 * PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid invJ[%" PetscInt_FMT ",%" PetscInt_FMT "]: %g != %g", i, j, (double)invJ[i * spaceDim + j], (double)invJEx[i * spaceDim + j]);
162c4762a1bSJed Brown     }
163c4762a1bSJed Brown   }
164700a43edSPierre Jolivet   PetscCheck(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));
165c4762a1bSJed Brown   PetscFunctionReturn(0);
166c4762a1bSJed Brown }
167c4762a1bSJed Brown 
1689371c9d4SSatish Balay static PetscErrorCode CheckFVMGeometry(DM dm, PetscInt cell, PetscInt spaceDim, PetscReal centroidEx[], PetscReal normalEx[], PetscReal volEx) {
1694f99dae5SMatthew G. Knepley   PetscReal tol = PetscMax(10 * PETSC_SMALL, 1e-10);
170c4762a1bSJed Brown   PetscReal centroid[3], normal[3], vol;
171c4762a1bSJed Brown   PetscInt  d;
172c4762a1bSJed Brown 
173c4762a1bSJed Brown   PetscFunctionBegin;
1749566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFVM(dm, cell, volEx ? &vol : NULL, centroidEx ? centroid : NULL, normalEx ? normal : NULL));
175c4762a1bSJed Brown   for (d = 0; d < spaceDim; ++d) {
1769bf2564aSMatt McGurn     if (centroidEx)
17763a3b9bcSJacob Faibussowitsch       PetscCheck(RelativeError(centroid[d], centroidEx[d]) < tol, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT ", Invalid centroid[%" PetscInt_FMT "]: %g != %g diff %g", cell, d, (double)centroid[d], (double)centroidEx[d], (double)(centroid[d] - centroidEx[d]));
1789371c9d4SSatish Balay     if (normalEx) PetscCheck(RelativeError(normal[d], normalEx[d]) < tol, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT ", Invalid normal[%" PetscInt_FMT "]: %g != %g", cell, d, (double)normal[d], (double)normalEx[d]);
179c4762a1bSJed Brown   }
1809371c9d4SSatish Balay   if (volEx) PetscCheck(RelativeError(volEx, vol) < tol, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT ", Invalid volume = %g != %g diff %g", cell, (double)vol, (double)volEx, (double)(vol - volEx));
1814f99dae5SMatthew G. Knepley   PetscFunctionReturn(0);
1824f99dae5SMatthew G. Knepley }
1834f99dae5SMatthew G. Knepley 
1849371c9d4SSatish Balay static PetscErrorCode CheckGaussLaw(DM dm, PetscInt cell) {
1854f99dae5SMatthew G. Knepley   DMPolytopeType  ct;
1864f99dae5SMatthew G. Knepley   PetscReal       tol = PetscMax(10 * PETSC_SMALL, 1e-10);
1874f99dae5SMatthew G. Knepley   PetscReal       normal[3], integral[3] = {0., 0., 0.}, area;
1884f99dae5SMatthew G. Knepley   const PetscInt *cone, *ornt;
1894f99dae5SMatthew G. Knepley   PetscInt        coneSize, f, dim, cdim, d;
1904f99dae5SMatthew G. Knepley 
1914f99dae5SMatthew G. Knepley   PetscFunctionBegin;
1929566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1939566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
1944f99dae5SMatthew G. Knepley   if (dim != cdim) PetscFunctionReturn(0);
1959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1964f99dae5SMatthew G. Knepley   if (ct == DM_POLYTOPE_TRI_PRISM_TENSOR) PetscFunctionReturn(0);
1979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
1989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, cell, &cone));
1999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
2004f99dae5SMatthew G. Knepley   for (f = 0; f < coneSize; ++f) {
2019bf2564aSMatt McGurn     const PetscInt sgn = dim == 1 ? (f == 0 ? -1 : 1) : (ornt[f] < 0 ? -1 : 1);
2024f99dae5SMatthew G. Knepley 
2039566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, cone[f], &area, NULL, normal));
2044f99dae5SMatthew G. Knepley     for (d = 0; d < cdim; ++d) integral[d] += sgn * area * normal[d];
2054f99dae5SMatthew G. Knepley   }
2069371c9d4SSatish Balay   for (d = 0; d < cdim; ++d)
2079371c9d4SSatish Balay     PetscCheck(PetscAbsReal(integral[d]) < tol, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " Surface integral for component %" PetscInt_FMT ": %g != 0. as it should be for a constant field", cell, d, (double)integral[d]);
208c4762a1bSJed Brown   PetscFunctionReturn(0);
209c4762a1bSJed Brown }
210c4762a1bSJed Brown 
2119371c9d4SSatish Balay 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[]) {
212c4762a1bSJed Brown   const PetscInt *cone;
213c4762a1bSJed Brown   PetscInt        coneSize, c;
214c4762a1bSJed Brown   PetscInt        dim, depth, cdim;
215c4762a1bSJed Brown 
216c4762a1bSJed Brown   PetscFunctionBegin;
2179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
2189566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
2199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
2201baa6e33SBarry Smith   if (v0Ex) PetscCall(CheckFEMGeometry(dm, cell, cdim, v0Ex, JEx, invJEx, detJEx));
221c4762a1bSJed Brown   if (dim == depth && centroidEx) {
2229566063dSJacob Faibussowitsch     PetscCall(CheckFVMGeometry(dm, cell, cdim, centroidEx, normalEx, volEx));
2239566063dSJacob Faibussowitsch     PetscCall(CheckGaussLaw(dm, cell));
224c4762a1bSJed Brown     if (faceCentroidEx) {
2259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
2269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
227*48a46eb9SPierre Jolivet       for (c = 0; c < coneSize; ++c) PetscCall(CheckFVMGeometry(dm, cone[c], dim, &faceCentroidEx[c * dim], &faceNormalEx[c * dim], faceVolEx[c]));
228c4762a1bSJed Brown     }
229c4762a1bSJed Brown   }
230c4762a1bSJed Brown   if (transform) {
231c4762a1bSJed Brown     Vec          coordinates;
232c4762a1bSJed Brown     PetscSection coordSection;
233c4762a1bSJed Brown     PetscScalar *coords = NULL, *origCoords, *newCoords;
234c4762a1bSJed Brown     PetscReal   *v0ExT, *JExT, *invJExT, detJExT = 0, *centroidExT, *normalExT, volExT = 0;
235c4762a1bSJed Brown     PetscReal   *faceCentroidExT, *faceNormalExT, faceVolExT;
236c4762a1bSJed Brown     PetscRandom  r, ang, ang2;
237c4762a1bSJed Brown     PetscInt     coordSize, numCorners, t;
238c4762a1bSJed Brown 
2399566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2409566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2419566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords));
2429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(coordSize, &origCoords, coordSize, &newCoords));
2439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(cdim, &v0ExT, cdim * cdim, &JExT, cdim * cdim, &invJExT, cdim, &centroidExT, cdim, &normalExT));
2449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(cdim, &faceCentroidExT, cdim, &faceNormalExT));
245c4762a1bSJed Brown     for (c = 0; c < coordSize; ++c) origCoords[c] = coords[c];
2469566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords));
247c4762a1bSJed Brown     numCorners = coordSize / cdim;
248c4762a1bSJed Brown 
2499566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &r));
2509566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetFromOptions(r));
2519566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetInterval(r, 0.0, 10.0));
2529566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &ang));
2539566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetFromOptions(ang));
2549566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetInterval(ang, 0.0, 2 * PETSC_PI));
2559566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &ang2));
2569566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetFromOptions(ang2));
2579566063dSJacob Faibussowitsch     PetscCall(PetscRandomSetInterval(ang2, 0.0, PETSC_PI));
258c4762a1bSJed Brown     for (t = 0; t < 1; ++t) {
259c4762a1bSJed Brown       PetscScalar trans[3];
260c4762a1bSJed Brown       PetscReal   R[9], rot[3], rotM[9];
261c4762a1bSJed Brown       PetscReal   scale, phi, theta, psi = 0.0, norm;
262c4762a1bSJed Brown       PetscInt    d, e, f, p;
263c4762a1bSJed Brown 
264c4762a1bSJed Brown       for (c = 0; c < coordSize; ++c) newCoords[c] = origCoords[c];
2659566063dSJacob Faibussowitsch       PetscCall(PetscRandomGetValueReal(r, &scale));
2669566063dSJacob Faibussowitsch       PetscCall(PetscRandomGetValueReal(ang, &phi));
2679566063dSJacob Faibussowitsch       PetscCall(PetscRandomGetValueReal(ang2, &theta));
268*48a46eb9SPierre Jolivet       for (d = 0; d < cdim; ++d) PetscCall(PetscRandomGetValue(r, &trans[d]));
269c4762a1bSJed Brown       switch (cdim) {
270c4762a1bSJed Brown       case 2:
2719371c9d4SSatish Balay         R[0] = PetscCosReal(phi);
2729371c9d4SSatish Balay         R[1] = -PetscSinReal(phi);
2739371c9d4SSatish Balay         R[2] = PetscSinReal(phi);
2749371c9d4SSatish Balay         R[3] = PetscCosReal(phi);
275c4762a1bSJed Brown         break;
2769371c9d4SSatish Balay       case 3: {
277c4762a1bSJed Brown         const PetscReal ct = PetscCosReal(theta), st = PetscSinReal(theta);
278c4762a1bSJed Brown         const PetscReal cp = PetscCosReal(phi), sp = PetscSinReal(phi);
279c4762a1bSJed Brown         const PetscReal cs = PetscCosReal(psi), ss = PetscSinReal(psi);
2809371c9d4SSatish Balay         R[0] = ct * cs;
2819371c9d4SSatish Balay         R[1] = sp * st * cs - cp * ss;
2829371c9d4SSatish Balay         R[2] = sp * ss + cp * st * cs;
2839371c9d4SSatish Balay         R[3] = ct * ss;
2849371c9d4SSatish Balay         R[4] = cp * cs + sp * st * ss;
2859371c9d4SSatish Balay         R[5] = cp * st * ss - sp * cs;
2869371c9d4SSatish Balay         R[6] = -st;
2879371c9d4SSatish Balay         R[7] = sp * ct;
2889371c9d4SSatish Balay         R[8] = cp * ct;
289c4762a1bSJed Brown         break;
290c4762a1bSJed Brown       }
29163a3b9bcSJacob Faibussowitsch       default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid coordinate dimension %" PetscInt_FMT, cdim);
292c4762a1bSJed Brown       }
293c4762a1bSJed Brown       if (v0Ex) {
294c4762a1bSJed Brown         detJExT = detJEx;
295c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
296c4762a1bSJed Brown           v0ExT[d] = v0Ex[d];
297c4762a1bSJed Brown           for (e = 0; e < cdim; ++e) {
298c4762a1bSJed Brown             JExT[d * cdim + e]    = JEx[d * cdim + e];
299c4762a1bSJed Brown             invJExT[d * cdim + e] = invJEx[d * cdim + e];
300c4762a1bSJed Brown           }
301c4762a1bSJed Brown         }
302c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
303c4762a1bSJed Brown           v0ExT[d] *= scale;
304c4762a1bSJed Brown           v0ExT[d] += PetscRealPart(trans[d]);
305c4762a1bSJed Brown           /* Only scale dimensions in the manifold */
306c4762a1bSJed Brown           for (e = 0; e < dim; ++e) {
307c4762a1bSJed Brown             JExT[d * cdim + e] *= scale;
308c4762a1bSJed Brown             invJExT[d * cdim + e] /= scale;
309c4762a1bSJed Brown           }
310c4762a1bSJed Brown           if (d < dim) detJExT *= scale;
311c4762a1bSJed Brown         }
312c4762a1bSJed Brown         /* Do scaling and translation before rotation, so that we can leave out the normal dimension for lower dimensional manifolds */
313c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
3149371c9d4SSatish Balay           for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * v0ExT[e]; }
315c4762a1bSJed Brown         }
316c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) v0ExT[d] = rot[d];
317c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
318c4762a1bSJed Brown           for (e = 0; e < cdim; ++e) {
3199371c9d4SSatish Balay             for (f = 0, rotM[d * cdim + e] = 0.0; f < cdim; ++f) { rotM[d * cdim + e] += R[d * cdim + f] * JExT[f * cdim + e]; }
320c4762a1bSJed Brown           }
321c4762a1bSJed Brown         }
322c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
3239371c9d4SSatish Balay           for (e = 0; e < cdim; ++e) { JExT[d * cdim + e] = rotM[d * cdim + e]; }
324c4762a1bSJed Brown         }
325c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
326c4762a1bSJed Brown           for (e = 0; e < cdim; ++e) {
3279371c9d4SSatish Balay             for (f = 0, rotM[d * cdim + e] = 0.0; f < cdim; ++f) { rotM[d * cdim + e] += invJExT[d * cdim + f] * R[e * cdim + f]; }
328c4762a1bSJed Brown           }
329c4762a1bSJed Brown         }
3309371c9d4SSatish Balay         for (d = 0; d < cdim; ++d) {
3319371c9d4SSatish Balay           for (e = 0; e < cdim; ++e) { invJExT[d * cdim + e] = rotM[d * cdim + e]; }
3329371c9d4SSatish Balay         }
333c4762a1bSJed Brown       }
334c4762a1bSJed Brown       if (centroidEx) {
335c4762a1bSJed Brown         volExT = volEx;
336c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
337c4762a1bSJed Brown           centroidExT[d] = centroidEx[d];
338c4762a1bSJed Brown           normalExT[d]   = normalEx[d];
339c4762a1bSJed Brown         }
340c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
341c4762a1bSJed Brown           centroidExT[d] *= scale;
342c4762a1bSJed Brown           centroidExT[d] += PetscRealPart(trans[d]);
343c4762a1bSJed Brown           normalExT[d] /= scale;
344c4762a1bSJed Brown           /* Only scale dimensions in the manifold */
345c4762a1bSJed Brown           if (d < dim) volExT *= scale;
346c4762a1bSJed Brown         }
347c4762a1bSJed Brown         /* Do scaling and translation before rotation, so that we can leave out the normal dimension for lower dimensional manifolds */
348c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
3499371c9d4SSatish Balay           for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * centroidExT[e]; }
350c4762a1bSJed Brown         }
351c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) centroidExT[d] = rot[d];
352c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
3539371c9d4SSatish Balay           for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * normalExT[e]; }
354c4762a1bSJed Brown         }
355c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) normalExT[d] = rot[d];
356c4762a1bSJed Brown         for (d = 0, norm = 0.0; d < cdim; ++d) norm += PetscSqr(normalExT[d]);
357c4762a1bSJed Brown         norm = PetscSqrtReal(norm);
3589371c9d4SSatish Balay         if (norm != 0.)
3599371c9d4SSatish Balay           for (d = 0; d < cdim; ++d) normalExT[d] /= norm;
360c4762a1bSJed Brown       }
361c4762a1bSJed Brown       for (d = 0; d < cdim; ++d) {
362c4762a1bSJed Brown         for (p = 0; p < numCorners; ++p) {
363c4762a1bSJed Brown           newCoords[p * cdim + d] *= scale;
364c4762a1bSJed Brown           newCoords[p * cdim + d] += trans[d];
365c4762a1bSJed Brown         }
366c4762a1bSJed Brown       }
367c4762a1bSJed Brown       for (p = 0; p < numCorners; ++p) {
368c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) {
3699371c9d4SSatish Balay           for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * PetscRealPart(newCoords[p * cdim + e]); }
370c4762a1bSJed Brown         }
371c4762a1bSJed Brown         for (d = 0; d < cdim; ++d) newCoords[p * cdim + d] = rot[d];
372c4762a1bSJed Brown       }
373c4762a1bSJed Brown 
3749566063dSJacob Faibussowitsch       PetscCall(ChangeCoordinates(dm, cdim, newCoords));
3751baa6e33SBarry Smith       if (v0Ex) PetscCall(CheckFEMGeometry(dm, 0, cdim, v0ExT, JExT, invJExT, detJExT));
376c4762a1bSJed Brown       if (dim == depth && centroidEx) {
3779566063dSJacob Faibussowitsch         PetscCall(CheckFVMGeometry(dm, cell, cdim, centroidExT, normalExT, volExT));
3789566063dSJacob Faibussowitsch         PetscCall(CheckGaussLaw(dm, cell));
379c4762a1bSJed Brown         if (faceCentroidEx) {
3809566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
3819566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, cell, &cone));
382c4762a1bSJed Brown           for (c = 0; c < coneSize; ++c) {
383c4762a1bSJed Brown             PetscInt off = c * cdim;
384c4762a1bSJed Brown 
385c4762a1bSJed Brown             faceVolExT = faceVolEx[c];
386c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) {
387c4762a1bSJed Brown               faceCentroidExT[d] = faceCentroidEx[off + d];
388c4762a1bSJed Brown               faceNormalExT[d]   = faceNormalEx[off + d];
389c4762a1bSJed Brown             }
390c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) {
391c4762a1bSJed Brown               faceCentroidExT[d] *= scale;
392c4762a1bSJed Brown               faceCentroidExT[d] += PetscRealPart(trans[d]);
393c4762a1bSJed Brown               faceNormalExT[d] /= scale;
394c4762a1bSJed Brown               /* Only scale dimensions in the manifold */
3959371c9d4SSatish Balay               if (d < dim - 1) { faceVolExT *= scale; }
396c4762a1bSJed Brown             }
397c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) {
3989371c9d4SSatish Balay               for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * faceCentroidExT[e]; }
399c4762a1bSJed Brown             }
400c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) faceCentroidExT[d] = rot[d];
401c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) {
4029371c9d4SSatish Balay               for (e = 0, rot[d] = 0.0; e < cdim; ++e) { rot[d] += R[d * cdim + e] * faceNormalExT[e]; }
403c4762a1bSJed Brown             }
404c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) faceNormalExT[d] = rot[d];
405c4762a1bSJed Brown             for (d = 0, norm = 0.0; d < cdim; ++d) norm += PetscSqr(faceNormalExT[d]);
406c4762a1bSJed Brown             norm = PetscSqrtReal(norm);
407c4762a1bSJed Brown             for (d = 0; d < cdim; ++d) faceNormalExT[d] /= norm;
408c4762a1bSJed Brown 
4099566063dSJacob Faibussowitsch             PetscCall(CheckFVMGeometry(dm, cone[c], cdim, faceCentroidExT, faceNormalExT, faceVolExT));
410c4762a1bSJed Brown           }
411c4762a1bSJed Brown         }
412c4762a1bSJed Brown       }
413c4762a1bSJed Brown     }
4149566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&r));
4159566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&ang));
4169566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&ang2));
4179566063dSJacob Faibussowitsch     PetscCall(PetscFree2(origCoords, newCoords));
4189566063dSJacob Faibussowitsch     PetscCall(PetscFree5(v0ExT, JExT, invJExT, centroidExT, normalExT));
4199566063dSJacob Faibussowitsch     PetscCall(PetscFree2(faceCentroidExT, faceNormalExT));
420c4762a1bSJed Brown   }
421c4762a1bSJed Brown   PetscFunctionReturn(0);
422c4762a1bSJed Brown }
423c4762a1bSJed Brown 
4249371c9d4SSatish Balay static PetscErrorCode TestTriangle(MPI_Comm comm, PetscBool transform) {
425c4762a1bSJed Brown   DM dm;
426c4762a1bSJed Brown 
427c4762a1bSJed Brown   PetscFunctionBegin;
4289566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TRIANGLE, &dm));
4299566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
430c4762a1bSJed Brown   /* Check reference geometry: determinant is scaled by reference volume (2.0) */
431c4762a1bSJed Brown   {
432c4762a1bSJed Brown     PetscReal v0Ex[2]       = {-1.0, -1.0};
433c4762a1bSJed Brown     PetscReal JEx[4]        = {1.0, 0.0, 0.0, 1.0};
434c4762a1bSJed Brown     PetscReal invJEx[4]     = {1.0, 0.0, 0.0, 1.0};
435c4762a1bSJed Brown     PetscReal detJEx        = 1.0;
436c4762a1bSJed Brown     PetscReal centroidEx[2] = {-((PetscReal)1.) / ((PetscReal)3.), -((PetscReal)1.) / ((PetscReal)3.)};
437c4762a1bSJed Brown     PetscReal normalEx[2]   = {0.0, 0.0};
438c4762a1bSJed Brown     PetscReal volEx         = 2.0;
439c4762a1bSJed Brown 
4409566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
441c4762a1bSJed Brown   }
442c4762a1bSJed Brown   /* Move to 3D: Check reference geometry: determinant is scaled by reference volume (2.0) */
443c4762a1bSJed Brown   {
444c4762a1bSJed Brown     PetscScalar vertexCoords[9] = {-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0};
445c4762a1bSJed Brown     PetscReal   v0Ex[3]         = {-1.0, -1.0, 0.0};
446c4762a1bSJed Brown     PetscReal   JEx[9]          = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
447c4762a1bSJed Brown     PetscReal   invJEx[9]       = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
448c4762a1bSJed Brown     PetscReal   detJEx          = 1.0;
449c4762a1bSJed Brown     PetscReal   centroidEx[3]   = {-((PetscReal)1.) / ((PetscReal)3.), -((PetscReal)1.) / ((PetscReal)3.), 0.0};
450c4762a1bSJed Brown     PetscReal   normalEx[3]     = {0.0, 0.0, 1.0};
451c4762a1bSJed Brown     PetscReal   volEx           = 2.0;
452c4762a1bSJed Brown 
4539566063dSJacob Faibussowitsch     PetscCall(ChangeCoordinates(dm, 3, vertexCoords));
4549566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
455c4762a1bSJed Brown   }
456c4762a1bSJed Brown   /* Cleanup */
4579566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
458c4762a1bSJed Brown   PetscFunctionReturn(0);
459c4762a1bSJed Brown }
460c4762a1bSJed Brown 
4619371c9d4SSatish Balay static PetscErrorCode TestQuadrilateral(MPI_Comm comm, PetscBool transform) {
462c4762a1bSJed Brown   DM dm;
463c4762a1bSJed Brown 
464c4762a1bSJed Brown   PetscFunctionBegin;
4659566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_QUADRILATERAL, &dm));
4669566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
467c4762a1bSJed Brown   /* Check reference geometry: determinant is scaled by reference volume (2.0) */
468c4762a1bSJed Brown   {
469c4762a1bSJed Brown     PetscReal v0Ex[2]       = {-1.0, -1.0};
470c4762a1bSJed Brown     PetscReal JEx[4]        = {1.0, 0.0, 0.0, 1.0};
471c4762a1bSJed Brown     PetscReal invJEx[4]     = {1.0, 0.0, 0.0, 1.0};
472c4762a1bSJed Brown     PetscReal detJEx        = 1.0;
473c4762a1bSJed Brown     PetscReal centroidEx[2] = {0.0, 0.0};
474c4762a1bSJed Brown     PetscReal normalEx[2]   = {0.0, 0.0};
475c4762a1bSJed Brown     PetscReal volEx         = 4.0;
476c4762a1bSJed Brown 
4779566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
478c4762a1bSJed Brown   }
479c4762a1bSJed Brown   /* Move to 3D: Check reference geometry: determinant is scaled by reference volume (4.0) */
480c4762a1bSJed Brown   {
481c4762a1bSJed Brown     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};
482c4762a1bSJed Brown     PetscReal   v0Ex[3]          = {-1.0, -1.0, 0.0};
483c4762a1bSJed Brown     PetscReal   JEx[9]           = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
484c4762a1bSJed Brown     PetscReal   invJEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
485c4762a1bSJed Brown     PetscReal   detJEx           = 1.0;
486c4762a1bSJed Brown     PetscReal   centroidEx[3]    = {0.0, 0.0, 0.0};
487c4762a1bSJed Brown     PetscReal   normalEx[3]      = {0.0, 0.0, 1.0};
488c4762a1bSJed Brown     PetscReal   volEx            = 4.0;
489c4762a1bSJed Brown 
4909566063dSJacob Faibussowitsch     PetscCall(ChangeCoordinates(dm, 3, vertexCoords));
4919566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
492c4762a1bSJed Brown   }
493c4762a1bSJed Brown   /* Cleanup */
4949566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
495c4762a1bSJed Brown   PetscFunctionReturn(0);
496c4762a1bSJed Brown }
497c4762a1bSJed Brown 
4989371c9d4SSatish Balay static PetscErrorCode TestTetrahedron(MPI_Comm comm, PetscBool transform) {
499c4762a1bSJed Brown   DM dm;
500c4762a1bSJed Brown 
501c4762a1bSJed Brown   PetscFunctionBegin;
5029566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TETRAHEDRON, &dm));
5039566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
504c4762a1bSJed Brown   /* Check reference geometry: determinant is scaled by reference volume (4/3) */
505c4762a1bSJed Brown   {
506c4762a1bSJed Brown     PetscReal v0Ex[3]       = {-1.0, -1.0, -1.0};
507c4762a1bSJed Brown     PetscReal JEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
508c4762a1bSJed Brown     PetscReal invJEx[9]     = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
509c4762a1bSJed Brown     PetscReal detJEx        = 1.0;
510c4762a1bSJed Brown     PetscReal centroidEx[3] = {-0.5, -0.5, -0.5};
511c4762a1bSJed Brown     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
512c4762a1bSJed Brown     PetscReal volEx         = (PetscReal)4.0 / (PetscReal)3.0;
513c4762a1bSJed Brown 
5149566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
515c4762a1bSJed Brown   }
516c4762a1bSJed Brown   /* Cleanup */
5179566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
518c4762a1bSJed Brown   PetscFunctionReturn(0);
519c4762a1bSJed Brown }
520c4762a1bSJed Brown 
5219371c9d4SSatish Balay static PetscErrorCode TestHexahedron(MPI_Comm comm, PetscBool transform) {
522c4762a1bSJed Brown   DM dm;
523c4762a1bSJed Brown 
524c4762a1bSJed Brown   PetscFunctionBegin;
5259566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_HEXAHEDRON, &dm));
5269566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
527c4762a1bSJed Brown   /* Check reference geometry: determinant is scaled by reference volume 8.0 */
528c4762a1bSJed Brown   {
529c4762a1bSJed Brown     PetscReal v0Ex[3]       = {-1.0, -1.0, -1.0};
530c4762a1bSJed Brown     PetscReal JEx[9]        = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
531c4762a1bSJed Brown     PetscReal invJEx[9]     = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
532c4762a1bSJed Brown     PetscReal detJEx        = 1.0;
533c4762a1bSJed Brown     PetscReal centroidEx[3] = {0.0, 0.0, 0.0};
534c4762a1bSJed Brown     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
535c4762a1bSJed Brown     PetscReal volEx         = 8.0;
536c4762a1bSJed Brown 
5379566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, transform, v0Ex, JEx, invJEx, detJEx, centroidEx, normalEx, volEx, NULL, NULL, NULL));
538c4762a1bSJed Brown   }
539c4762a1bSJed Brown   /* Cleanup */
5409566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
541c4762a1bSJed Brown   PetscFunctionReturn(0);
542c4762a1bSJed Brown }
543c4762a1bSJed Brown 
5449371c9d4SSatish Balay static PetscErrorCode TestHexahedronCurved(MPI_Comm comm) {
545c4762a1bSJed Brown   DM          dm;
5469371c9d4SSatish Balay   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, -1.0, -1.0, 1.1, 1.0, -1.0, 1.0, 1.0, 1.0, 1.1, -1.0, 1.0, 1.0};
547c4762a1bSJed Brown 
548c4762a1bSJed Brown   PetscFunctionBegin;
5499566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_HEXAHEDRON, &dm));
5509566063dSJacob Faibussowitsch   PetscCall(ChangeCoordinates(dm, 3, coords));
5519566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
5524f99dae5SMatthew G. Knepley   {
5534f99dae5SMatthew G. Knepley     PetscReal centroidEx[3] = {0.0, 0.0, 0.016803278688524603};
5544f99dae5SMatthew G. Knepley     PetscReal normalEx[3]   = {0.0, 0.0, 0.0};
5554f99dae5SMatthew G. Knepley     PetscReal volEx         = 8.1333333333333346;
5564f99dae5SMatthew G. Knepley 
5579566063dSJacob Faibussowitsch     PetscCall(CheckCell(dm, 0, PETSC_FALSE, NULL, NULL, NULL, 0.0, centroidEx, normalEx, volEx, NULL, NULL, NULL));
558c4762a1bSJed Brown   }
5599566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
5604f99dae5SMatthew G. Knepley   PetscFunctionReturn(0);
5614f99dae5SMatthew G. Knepley }
5624f99dae5SMatthew G. Knepley 
5634f99dae5SMatthew G. Knepley /* This wedge is a tensor product cell, rather than a normal wedge */
5649371c9d4SSatish Balay static PetscErrorCode TestWedge(MPI_Comm comm, PetscBool transform) {
5654f99dae5SMatthew G. Knepley   DM dm;
5664f99dae5SMatthew G. Knepley 
5674f99dae5SMatthew G. Knepley   PetscFunctionBegin;
5689566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DM_POLYTOPE_TRI_PRISM_TENSOR, &dm));
5699566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(dm, NULL, "-dm_view"));
570c4762a1bSJed Brown   /* Check reference geometry: determinant is scaled by reference volume 4.0 */
571c4762a1bSJed Brown   {
572c4762a1bSJed Brown #if 0
573c4762a1bSJed Brown     /* FEM geometry is not functional for wedges */
574c4762a1bSJed Brown     PetscReal v0Ex[3]   = {-1.0, -1.0, -1.0};
575c4762a1bSJed Brown     PetscReal JEx[9]    = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
576c4762a1bSJed Brown     PetscReal invJEx[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
577c4762a1bSJed Brown     PetscReal detJEx    = 1.0;
578c4762a1bSJed Brown #endif
579c4762a1bSJed Brown 
5804f99dae5SMatthew G. Knepley     {
581c4762a1bSJed Brown       PetscReal centroidEx[3]      = {-((PetscReal)1.) / ((PetscReal)3.), -((PetscReal)1.) / ((PetscReal)3.), 0.0};
582c4762a1bSJed Brown       PetscReal normalEx[3]        = {0.0, 0.0, 0.0};
583c4762a1bSJed Brown       PetscReal volEx              = 4.0;
584c4762a1bSJed Brown       PetscReal faceVolEx[5]       = {2.0, 2.0, 4.0, PETSC_SQRT2 * 4.0, 4.0};
585c4762a1bSJed Brown       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};
5869371c9d4SSatish Balay       PetscReal faceCentroidEx[15] = {-((PetscReal)1.) / ((PetscReal)3.), -((PetscReal)1.) / ((PetscReal)3.), -1.0, -((PetscReal)1.) / ((PetscReal)3.), -((PetscReal)1.) / ((PetscReal)3.), 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0};
587c4762a1bSJed Brown 
5889566063dSJacob Faibussowitsch       PetscCall(CheckCell(dm, 0, transform, NULL, NULL, NULL, 0.0, centroidEx, normalEx, volEx, faceCentroidEx, faceNormalEx, faceVolEx));
589c4762a1bSJed Brown     }
590c4762a1bSJed Brown   }
591c4762a1bSJed Brown   /* Cleanup */
5929566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
593c4762a1bSJed Brown   PetscFunctionReturn(0);
594c4762a1bSJed Brown }
595c4762a1bSJed Brown 
5969371c9d4SSatish Balay int main(int argc, char **argv) {
597c4762a1bSJed Brown   AppCtx user;
598c4762a1bSJed Brown 
599327415f7SBarry Smith   PetscFunctionBeginUser;
6009566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
6019566063dSJacob Faibussowitsch   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
602c4762a1bSJed Brown   if (user.runType == RUN_REFERENCE) {
6039566063dSJacob Faibussowitsch     PetscCall(TestTriangle(PETSC_COMM_SELF, user.transform));
6049566063dSJacob Faibussowitsch     PetscCall(TestQuadrilateral(PETSC_COMM_SELF, user.transform));
6059566063dSJacob Faibussowitsch     PetscCall(TestTetrahedron(PETSC_COMM_SELF, user.transform));
6069566063dSJacob Faibussowitsch     PetscCall(TestHexahedron(PETSC_COMM_SELF, user.transform));
6079566063dSJacob Faibussowitsch     PetscCall(TestWedge(PETSC_COMM_SELF, user.transform));
6084f99dae5SMatthew G. Knepley   } else if (user.runType == RUN_HEX_CURVED) {
6099566063dSJacob Faibussowitsch     PetscCall(TestHexahedronCurved(PETSC_COMM_SELF));
610c4762a1bSJed Brown   } else if (user.runType == RUN_FILE) {
611c4762a1bSJed Brown     PetscInt dim, cStart, cEnd, c;
612c4762a1bSJed Brown 
6139566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(user.dm, &dim));
6149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(user.dm, 0, &cStart, &cEnd));
615c4762a1bSJed Brown     for (c = 0; c < cEnd - cStart; ++c) {
6164f99dae5SMatthew G. Knepley       PetscReal *v0       = user.v0 ? &user.v0[c * dim] : NULL;
6174f99dae5SMatthew G. Knepley       PetscReal *J        = user.J ? &user.J[c * dim * dim] : NULL;
6184f99dae5SMatthew G. Knepley       PetscReal *invJ     = user.invJ ? &user.invJ[c * dim * dim] : NULL;
6194f99dae5SMatthew G. Knepley       PetscReal  detJ     = user.detJ ? user.detJ[c] : 0.0;
6204f99dae5SMatthew G. Knepley       PetscReal *centroid = user.centroid ? &user.centroid[c * dim] : NULL;
6214f99dae5SMatthew G. Knepley       PetscReal *normal   = user.normal ? &user.normal[c * dim] : NULL;
6224f99dae5SMatthew G. Knepley       PetscReal  vol      = user.vol ? user.vol[c] : 0.0;
6234f99dae5SMatthew G. Knepley 
6249566063dSJacob Faibussowitsch       PetscCall(CheckCell(user.dm, c + cStart, PETSC_FALSE, v0, J, invJ, detJ, centroid, normal, vol, NULL, NULL, NULL));
625c4762a1bSJed Brown     }
6269566063dSJacob Faibussowitsch     PetscCall(PetscFree4(user.v0, user.J, user.invJ, user.detJ));
6279566063dSJacob Faibussowitsch     PetscCall(PetscFree(user.centroid));
6289566063dSJacob Faibussowitsch     PetscCall(PetscFree(user.normal));
6299566063dSJacob Faibussowitsch     PetscCall(PetscFree(user.vol));
6309566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&user.dm));
631c4762a1bSJed Brown   } else if (user.runType == RUN_DISPLAY) {
632c4762a1bSJed Brown     DM                 gdm, dmCell;
633c4762a1bSJed Brown     Vec                cellgeom, facegeom;
634c4762a1bSJed Brown     const PetscScalar *cgeom;
635c4762a1bSJed Brown     PetscInt           dim, d, cStart, cEnd, cEndInterior, c;
636c4762a1bSJed Brown 
6379566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(user.dm, &dim));
6389566063dSJacob Faibussowitsch     PetscCall(DMPlexConstructGhostCells(user.dm, NULL, NULL, &gdm));
639c4762a1bSJed Brown     if (gdm) {
6409566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&user.dm));
641c4762a1bSJed Brown       user.dm = gdm;
642c4762a1bSJed Brown     }
6439566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(user.dm, &cellgeom, &facegeom));
6449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(user.dm, 0, &cStart, &cEnd));
6459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(user.dm, &cEndInterior, NULL));
646c4762a1bSJed Brown     if (cEndInterior >= 0) cEnd = cEndInterior;
6479566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellgeom, &dmCell));
6489566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellgeom, &cgeom));
649c4762a1bSJed Brown     for (c = 0; c < cEnd - cStart; ++c) {
650c4762a1bSJed Brown       PetscFVCellGeom *cg;
651c4762a1bSJed Brown 
6529566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
65363a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %4" PetscInt_FMT ": Centroid (", c));
654c4762a1bSJed Brown       for (d = 0; d < dim; ++d) {
6559566063dSJacob Faibussowitsch         if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
65663a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "%12.2g", (double)cg->centroid[d]));
657c4762a1bSJed Brown       }
65863a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, ") Vol %12.2g\n", (double)cg->volume));
659c4762a1bSJed Brown     }
6609566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(cellgeom, &cgeom));
6619566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellgeom));
6629566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&facegeom));
6639566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&user.dm));
664c4762a1bSJed Brown   }
6659566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
666b122ec5aSJacob Faibussowitsch   return 0;
667c4762a1bSJed Brown }
668c4762a1bSJed Brown 
669c4762a1bSJed Brown /*TEST
670c4762a1bSJed Brown 
671c4762a1bSJed Brown   test:
6724f99dae5SMatthew G. Knepley     suffix: 1
673c4762a1bSJed Brown     args: -dm_view ascii::ascii_info_detail
674c4762a1bSJed Brown   test:
675c4762a1bSJed Brown     suffix: 2
6764f99dae5SMatthew G. Knepley     args: -run_type hex_curved
677c4762a1bSJed Brown   test:
678c4762a1bSJed Brown     suffix: 3
6794f99dae5SMatthew G. Knepley     args: -transform
680c4762a1bSJed Brown   test:
681c4762a1bSJed Brown     suffix: 4
682c4762a1bSJed Brown     requires: exodusii
6834f99dae5SMatthew G. Knepley     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
684c4762a1bSJed Brown   test:
685c4762a1bSJed Brown     suffix: 5
6864f99dae5SMatthew G. Knepley     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
6879bf2564aSMatt McGurn   test:
6889bf2564aSMatt McGurn     suffix: 6
6899bf2564aSMatt McGurn     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
690c4762a1bSJed Brown TEST*/
691