xref: /petsc/src/dm/impls/plex/plexgeometry.c (revision 2b6f951b86ef7b05845d41fe0f67a3222cfc0c15)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>  /*I      "petscdmplex.h"   I*/
29d150b73SToby Isaac #include <petsc/private/petscfeimpl.h> /*I      "petscfe.h"       I*/
39d150b73SToby Isaac #include <petscblaslapack.h>
4af74b616SDave May #include <petsctime.h>
5ccd2543fSMatthew G Knepley 
63985bb02SVaclav Hapla /*@
73985bb02SVaclav Hapla   DMPlexFindVertices - Try to find DAG points based on their coordinates.
83985bb02SVaclav Hapla 
920f4b53cSBarry Smith   Not Collective (provided `DMGetCoordinatesLocalSetUp()` has been already called)
103985bb02SVaclav Hapla 
113985bb02SVaclav Hapla   Input Parameters:
1220f4b53cSBarry Smith + dm - The `DMPLEX` object
1320f4b53cSBarry Smith . coordinates - The `Vec` of coordinates of the sought points
1420f4b53cSBarry Smith - eps - The tolerance or `PETSC_DEFAULT`
153985bb02SVaclav Hapla 
162fe279fdSBarry Smith   Output Parameter:
1720f4b53cSBarry Smith . points - The `IS` of found DAG points or -1
183985bb02SVaclav Hapla 
193985bb02SVaclav Hapla   Level: intermediate
203985bb02SVaclav Hapla 
213985bb02SVaclav Hapla   Notes:
2220f4b53cSBarry Smith   The length of `Vec` coordinates must be npoints * dim where dim is the spatial dimension returned by `DMGetCoordinateDim()` and npoints is the number of sought points.
233985bb02SVaclav Hapla 
2420f4b53cSBarry Smith   The output `IS` is living on `PETSC_COMM_SELF` and its length is npoints.
25d3e1f4ccSVaclav Hapla   Each rank does the search independently.
2620f4b53cSBarry Smith   If this rank's local `DMPLEX` portion contains the DAG point corresponding to the i-th tuple of coordinates, the i-th entry of the output `IS` is set to that DAG point, otherwise to -1.
273985bb02SVaclav Hapla 
2820f4b53cSBarry Smith   The output `IS` must be destroyed by user.
293985bb02SVaclav Hapla 
303985bb02SVaclav Hapla   The tolerance is interpreted as the maximum Euclidean (L2) distance of the sought point from the specified coordinates.
313985bb02SVaclav Hapla 
32d3e1f4ccSVaclav Hapla   Complexity of this function is currently O(mn) with m number of vertices to find and n number of vertices in the local mesh. This could probably be improved if needed.
33335ef845SVaclav Hapla 
3420f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexCreate()`, `DMGetCoordinatesLocal()`
353985bb02SVaclav Hapla @*/
36d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexFindVertices(DM dm, Vec coordinates, PetscReal eps, IS *points)
37d71ae5a4SJacob Faibussowitsch {
3837900f7dSMatthew G. Knepley   PetscInt           c, cdim, i, j, o, p, vStart, vEnd;
39d3e1f4ccSVaclav Hapla   PetscInt           npoints;
40d3e1f4ccSVaclav Hapla   const PetscScalar *coord;
413985bb02SVaclav Hapla   Vec                allCoordsVec;
423985bb02SVaclav Hapla   const PetscScalar *allCoords;
43d3e1f4ccSVaclav Hapla   PetscInt          *dagPoints;
443985bb02SVaclav Hapla 
453985bb02SVaclav Hapla   PetscFunctionBegin;
463985bb02SVaclav Hapla   if (eps < 0) eps = PETSC_SQRT_MACHINE_EPSILON;
479566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
48d3e1f4ccSVaclav Hapla   {
49d3e1f4ccSVaclav Hapla     PetscInt n;
50d3e1f4ccSVaclav Hapla 
519566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(coordinates, &n));
5263a3b9bcSJacob Faibussowitsch     PetscCheck(n % cdim == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Given coordinates Vec has local length %" PetscInt_FMT " not divisible by coordinate dimension %" PetscInt_FMT " of given DM", n, cdim);
53d3e1f4ccSVaclav Hapla     npoints = n / cdim;
54d3e1f4ccSVaclav Hapla   }
559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &allCoordsVec));
569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(allCoordsVec, &allCoords));
579566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coord));
589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
60335ef845SVaclav Hapla     /* check coordinate section is consistent with DM dimension */
61335ef845SVaclav Hapla     PetscSection cs;
62335ef845SVaclav Hapla     PetscInt     ndof;
63335ef845SVaclav Hapla 
649566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &cs));
653985bb02SVaclav Hapla     for (p = vStart; p < vEnd; p++) {
669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cs, p, &ndof));
6763a3b9bcSJacob Faibussowitsch       PetscCheck(ndof == cdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "point %" PetscInt_FMT ": ndof = %" PetscInt_FMT " != %" PetscInt_FMT " = cdim", p, ndof, cdim);
68335ef845SVaclav Hapla     }
69335ef845SVaclav Hapla   }
709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(npoints, &dagPoints));
71eca9f518SVaclav Hapla   if (eps == 0.0) {
7237900f7dSMatthew G. Knepley     for (i = 0, j = 0; i < npoints; i++, j += cdim) {
73eca9f518SVaclav Hapla       dagPoints[i] = -1;
7437900f7dSMatthew G. Knepley       for (p = vStart, o = 0; p < vEnd; p++, o += cdim) {
7537900f7dSMatthew G. Knepley         for (c = 0; c < cdim; c++) {
76d3e1f4ccSVaclav Hapla           if (coord[j + c] != allCoords[o + c]) break;
77eca9f518SVaclav Hapla         }
7837900f7dSMatthew G. Knepley         if (c == cdim) {
79eca9f518SVaclav Hapla           dagPoints[i] = p;
80eca9f518SVaclav Hapla           break;
81eca9f518SVaclav Hapla         }
82eca9f518SVaclav Hapla       }
83eca9f518SVaclav Hapla     }
84d3e1f4ccSVaclav Hapla   } else {
8537900f7dSMatthew G. Knepley     for (i = 0, j = 0; i < npoints; i++, j += cdim) {
86d3e1f4ccSVaclav Hapla       PetscReal norm;
87d3e1f4ccSVaclav Hapla 
88335ef845SVaclav Hapla       dagPoints[i] = -1;
8937900f7dSMatthew G. Knepley       for (p = vStart, o = 0; p < vEnd; p++, o += cdim) {
903985bb02SVaclav Hapla         norm = 0.0;
91ad540459SPierre Jolivet         for (c = 0; c < cdim; c++) norm += PetscRealPart(PetscSqr(coord[j + c] - allCoords[o + c]));
923985bb02SVaclav Hapla         norm = PetscSqrtReal(norm);
933985bb02SVaclav Hapla         if (norm <= eps) {
943985bb02SVaclav Hapla           dagPoints[i] = p;
953985bb02SVaclav Hapla           break;
963985bb02SVaclav Hapla         }
973985bb02SVaclav Hapla       }
983985bb02SVaclav Hapla     }
99d3e1f4ccSVaclav Hapla   }
1009566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(allCoordsVec, &allCoords));
1019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coord));
1029566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npoints, dagPoints, PETSC_OWN_POINTER, points));
1033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043985bb02SVaclav Hapla }
1053985bb02SVaclav Hapla 
106d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetLineIntersection_2D_Internal(const PetscReal segmentA[], const PetscReal segmentB[], PetscReal intersection[], PetscBool *hasIntersection)
107d71ae5a4SJacob Faibussowitsch {
108fea14342SMatthew G. Knepley   const PetscReal p0_x  = segmentA[0 * 2 + 0];
109fea14342SMatthew G. Knepley   const PetscReal p0_y  = segmentA[0 * 2 + 1];
110fea14342SMatthew G. Knepley   const PetscReal p1_x  = segmentA[1 * 2 + 0];
111fea14342SMatthew G. Knepley   const PetscReal p1_y  = segmentA[1 * 2 + 1];
112fea14342SMatthew G. Knepley   const PetscReal p2_x  = segmentB[0 * 2 + 0];
113fea14342SMatthew G. Knepley   const PetscReal p2_y  = segmentB[0 * 2 + 1];
114fea14342SMatthew G. Knepley   const PetscReal p3_x  = segmentB[1 * 2 + 0];
115fea14342SMatthew G. Knepley   const PetscReal p3_y  = segmentB[1 * 2 + 1];
116fea14342SMatthew G. Knepley   const PetscReal s1_x  = p1_x - p0_x;
117fea14342SMatthew G. Knepley   const PetscReal s1_y  = p1_y - p0_y;
118fea14342SMatthew G. Knepley   const PetscReal s2_x  = p3_x - p2_x;
119fea14342SMatthew G. Knepley   const PetscReal s2_y  = p3_y - p2_y;
120fea14342SMatthew G. Knepley   const PetscReal denom = (-s2_x * s1_y + s1_x * s2_y);
121fea14342SMatthew G. Knepley 
122fea14342SMatthew G. Knepley   PetscFunctionBegin;
123fea14342SMatthew G. Knepley   *hasIntersection = PETSC_FALSE;
124fea14342SMatthew G. Knepley   /* Non-parallel lines */
125fea14342SMatthew G. Knepley   if (denom != 0.0) {
126fea14342SMatthew G. Knepley     const PetscReal s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / denom;
127fea14342SMatthew G. Knepley     const PetscReal t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / denom;
128fea14342SMatthew G. Knepley 
129fea14342SMatthew G. Knepley     if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
130fea14342SMatthew G. Knepley       *hasIntersection = PETSC_TRUE;
131fea14342SMatthew G. Knepley       if (intersection) {
132fea14342SMatthew G. Knepley         intersection[0] = p0_x + (t * s1_x);
133fea14342SMatthew G. Knepley         intersection[1] = p0_y + (t * s1_y);
134fea14342SMatthew G. Knepley       }
135fea14342SMatthew G. Knepley     }
136fea14342SMatthew G. Knepley   }
1373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
138fea14342SMatthew G. Knepley }
139fea14342SMatthew G. Knepley 
140ddce0771SMatthew G. Knepley /* The plane is segmentB x segmentC: https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection */
141d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetLinePlaneIntersection_3D_Internal(const PetscReal segmentA[], const PetscReal segmentB[], const PetscReal segmentC[], PetscReal intersection[], PetscBool *hasIntersection)
142d71ae5a4SJacob Faibussowitsch {
143ddce0771SMatthew G. Knepley   const PetscReal p0_x  = segmentA[0 * 3 + 0];
144ddce0771SMatthew G. Knepley   const PetscReal p0_y  = segmentA[0 * 3 + 1];
145ddce0771SMatthew G. Knepley   const PetscReal p0_z  = segmentA[0 * 3 + 2];
146ddce0771SMatthew G. Knepley   const PetscReal p1_x  = segmentA[1 * 3 + 0];
147ddce0771SMatthew G. Knepley   const PetscReal p1_y  = segmentA[1 * 3 + 1];
148ddce0771SMatthew G. Knepley   const PetscReal p1_z  = segmentA[1 * 3 + 2];
149ddce0771SMatthew G. Knepley   const PetscReal q0_x  = segmentB[0 * 3 + 0];
150ddce0771SMatthew G. Knepley   const PetscReal q0_y  = segmentB[0 * 3 + 1];
151ddce0771SMatthew G. Knepley   const PetscReal q0_z  = segmentB[0 * 3 + 2];
152ddce0771SMatthew G. Knepley   const PetscReal q1_x  = segmentB[1 * 3 + 0];
153ddce0771SMatthew G. Knepley   const PetscReal q1_y  = segmentB[1 * 3 + 1];
154ddce0771SMatthew G. Knepley   const PetscReal q1_z  = segmentB[1 * 3 + 2];
155ddce0771SMatthew G. Knepley   const PetscReal r0_x  = segmentC[0 * 3 + 0];
156ddce0771SMatthew G. Knepley   const PetscReal r0_y  = segmentC[0 * 3 + 1];
157ddce0771SMatthew G. Knepley   const PetscReal r0_z  = segmentC[0 * 3 + 2];
158ddce0771SMatthew G. Knepley   const PetscReal r1_x  = segmentC[1 * 3 + 0];
159ddce0771SMatthew G. Knepley   const PetscReal r1_y  = segmentC[1 * 3 + 1];
160ddce0771SMatthew G. Knepley   const PetscReal r1_z  = segmentC[1 * 3 + 2];
161ddce0771SMatthew G. Knepley   const PetscReal s0_x  = p1_x - p0_x;
162ddce0771SMatthew G. Knepley   const PetscReal s0_y  = p1_y - p0_y;
163ddce0771SMatthew G. Knepley   const PetscReal s0_z  = p1_z - p0_z;
164ddce0771SMatthew G. Knepley   const PetscReal s1_x  = q1_x - q0_x;
165ddce0771SMatthew G. Knepley   const PetscReal s1_y  = q1_y - q0_y;
166ddce0771SMatthew G. Knepley   const PetscReal s1_z  = q1_z - q0_z;
167ddce0771SMatthew G. Knepley   const PetscReal s2_x  = r1_x - r0_x;
168ddce0771SMatthew G. Knepley   const PetscReal s2_y  = r1_y - r0_y;
169ddce0771SMatthew G. Knepley   const PetscReal s2_z  = r1_z - r0_z;
170ddce0771SMatthew G. Knepley   const PetscReal s3_x  = s1_y * s2_z - s1_z * s2_y; /* s1 x s2 */
171ddce0771SMatthew G. Knepley   const PetscReal s3_y  = s1_z * s2_x - s1_x * s2_z;
172ddce0771SMatthew G. Knepley   const PetscReal s3_z  = s1_x * s2_y - s1_y * s2_x;
173ddce0771SMatthew G. Knepley   const PetscReal s4_x  = s0_y * s2_z - s0_z * s2_y; /* s0 x s2 */
174ddce0771SMatthew G. Knepley   const PetscReal s4_y  = s0_z * s2_x - s0_x * s2_z;
175ddce0771SMatthew G. Knepley   const PetscReal s4_z  = s0_x * s2_y - s0_y * s2_x;
176ddce0771SMatthew G. Knepley   const PetscReal s5_x  = s1_y * s0_z - s1_z * s0_y; /* s1 x s0 */
177ddce0771SMatthew G. Knepley   const PetscReal s5_y  = s1_z * s0_x - s1_x * s0_z;
178ddce0771SMatthew G. Knepley   const PetscReal s5_z  = s1_x * s0_y - s1_y * s0_x;
179ddce0771SMatthew G. Knepley   const PetscReal denom = -(s0_x * s3_x + s0_y * s3_y + s0_z * s3_z); /* -s0 . (s1 x s2) */
180ddce0771SMatthew G. Knepley 
181ddce0771SMatthew G. Knepley   PetscFunctionBegin;
182ddce0771SMatthew G. Knepley   *hasIntersection = PETSC_FALSE;
183ddce0771SMatthew G. Knepley   /* Line not parallel to plane */
184ddce0771SMatthew G. Knepley   if (denom != 0.0) {
185ddce0771SMatthew G. Knepley     const PetscReal t = (s3_x * (p0_x - q0_x) + s3_y * (p0_y - q0_y) + s3_z * (p0_z - q0_z)) / denom;
186ddce0771SMatthew G. Knepley     const PetscReal u = (s4_x * (p0_x - q0_x) + s4_y * (p0_y - q0_y) + s4_z * (p0_z - q0_z)) / denom;
187ddce0771SMatthew G. Knepley     const PetscReal v = (s5_x * (p0_x - q0_x) + s5_y * (p0_y - q0_y) + s5_z * (p0_z - q0_z)) / denom;
188ddce0771SMatthew G. Knepley 
189ddce0771SMatthew G. Knepley     if (t >= 0 && t <= 1 && u >= 0 && u <= 1 && v >= 0 && v <= 1) {
190ddce0771SMatthew G. Knepley       *hasIntersection = PETSC_TRUE;
191ddce0771SMatthew G. Knepley       if (intersection) {
192ddce0771SMatthew G. Knepley         intersection[0] = p0_x + (t * s0_x);
193ddce0771SMatthew G. Knepley         intersection[1] = p0_y + (t * s0_y);
194ddce0771SMatthew G. Knepley         intersection[2] = p0_z + (t * s0_z);
195ddce0771SMatthew G. Knepley       }
196ddce0771SMatthew G. Knepley     }
197ddce0771SMatthew G. Knepley   }
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
199ddce0771SMatthew G. Knepley }
200ddce0771SMatthew G. Knepley 
201d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexLocatePoint_Simplex_1D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
202d71ae5a4SJacob Faibussowitsch {
20314bbb9f0SLawrence Mitchell   const PetscReal eps = PETSC_SQRT_MACHINE_EPSILON;
20414bbb9f0SLawrence Mitchell   const PetscReal x   = PetscRealPart(point[0]);
20514bbb9f0SLawrence Mitchell   PetscReal       v0, J, invJ, detJ;
20614bbb9f0SLawrence Mitchell   PetscReal       xi;
20714bbb9f0SLawrence Mitchell 
20814bbb9f0SLawrence Mitchell   PetscFunctionBegin;
2099566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
21014bbb9f0SLawrence Mitchell   xi = invJ * (x - v0);
21114bbb9f0SLawrence Mitchell 
21214bbb9f0SLawrence Mitchell   if ((xi >= -eps) && (xi <= 2. + eps)) *cell = c;
21314bbb9f0SLawrence Mitchell   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
2143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21514bbb9f0SLawrence Mitchell }
21614bbb9f0SLawrence Mitchell 
217d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexLocatePoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
218d71ae5a4SJacob Faibussowitsch {
219ccd2543fSMatthew G Knepley   const PetscInt  embedDim = 2;
220f5ebc837SMatthew G. Knepley   const PetscReal eps      = PETSC_SQRT_MACHINE_EPSILON;
221ccd2543fSMatthew G Knepley   PetscReal       x        = PetscRealPart(point[0]);
222ccd2543fSMatthew G Knepley   PetscReal       y        = PetscRealPart(point[1]);
223ccd2543fSMatthew G Knepley   PetscReal       v0[2], J[4], invJ[4], detJ;
224ccd2543fSMatthew G Knepley   PetscReal       xi, eta;
225ccd2543fSMatthew G Knepley 
226ccd2543fSMatthew G Knepley   PetscFunctionBegin;
2279566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
228ccd2543fSMatthew G Knepley   xi  = invJ[0 * embedDim + 0] * (x - v0[0]) + invJ[0 * embedDim + 1] * (y - v0[1]);
229ccd2543fSMatthew G Knepley   eta = invJ[1 * embedDim + 0] * (x - v0[0]) + invJ[1 * embedDim + 1] * (y - v0[1]);
230ccd2543fSMatthew G Knepley 
231f5ebc837SMatthew G. Knepley   if ((xi >= -eps) && (eta >= -eps) && (xi + eta <= 2.0 + eps)) *cell = c;
232c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
2333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
234ccd2543fSMatthew G Knepley }
235ccd2543fSMatthew G Knepley 
236d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexClosestPoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscReal cpoint[])
237d71ae5a4SJacob Faibussowitsch {
23862a38674SMatthew G. Knepley   const PetscInt embedDim = 2;
23962a38674SMatthew G. Knepley   PetscReal      x        = PetscRealPart(point[0]);
24062a38674SMatthew G. Knepley   PetscReal      y        = PetscRealPart(point[1]);
24162a38674SMatthew G. Knepley   PetscReal      v0[2], J[4], invJ[4], detJ;
24262a38674SMatthew G. Knepley   PetscReal      xi, eta, r;
24362a38674SMatthew G. Knepley 
24462a38674SMatthew G. Knepley   PetscFunctionBegin;
2459566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
24662a38674SMatthew G. Knepley   xi  = invJ[0 * embedDim + 0] * (x - v0[0]) + invJ[0 * embedDim + 1] * (y - v0[1]);
24762a38674SMatthew G. Knepley   eta = invJ[1 * embedDim + 0] * (x - v0[0]) + invJ[1 * embedDim + 1] * (y - v0[1]);
24862a38674SMatthew G. Knepley 
24962a38674SMatthew G. Knepley   xi  = PetscMax(xi, 0.0);
25062a38674SMatthew G. Knepley   eta = PetscMax(eta, 0.0);
25162a38674SMatthew G. Knepley   if (xi + eta > 2.0) {
25262a38674SMatthew G. Knepley     r = (xi + eta) / 2.0;
25362a38674SMatthew G. Knepley     xi /= r;
25462a38674SMatthew G. Knepley     eta /= r;
25562a38674SMatthew G. Knepley   }
25662a38674SMatthew G. Knepley   cpoint[0] = J[0 * embedDim + 0] * xi + J[0 * embedDim + 1] * eta + v0[0];
25762a38674SMatthew G. Knepley   cpoint[1] = J[1 * embedDim + 0] * xi + J[1 * embedDim + 1] * eta + v0[1];
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25962a38674SMatthew G. Knepley }
26062a38674SMatthew G. Knepley 
26161451c10SMatthew G. Knepley // This is the ray-casting, or even-odd algorithm: https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
262d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexLocatePoint_Quad_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
263d71ae5a4SJacob Faibussowitsch {
26476b3799dSMatthew G. Knepley   const PetscScalar *array;
265a1e44745SMatthew G. Knepley   PetscScalar       *coords    = NULL;
266ccd2543fSMatthew G Knepley   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
267ccd2543fSMatthew G Knepley   PetscReal          x         = PetscRealPart(point[0]);
268ccd2543fSMatthew G Knepley   PetscReal          y         = PetscRealPart(point[1]);
26976b3799dSMatthew G. Knepley   PetscInt           crossings = 0, numCoords, f;
27076b3799dSMatthew G. Knepley   PetscBool          isDG;
271ccd2543fSMatthew G Knepley 
272ccd2543fSMatthew G Knepley   PetscFunctionBegin;
27376b3799dSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &coords));
27476b3799dSMatthew G. Knepley   PetscCheck(numCoords == 8, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Quadrilateral should have 8 coordinates, not %" PetscInt_FMT, numCoords);
275ccd2543fSMatthew G Knepley   for (f = 0; f < 4; ++f) {
276ccd2543fSMatthew G Knepley     PetscReal x_i = PetscRealPart(coords[faces[2 * f + 0] * 2 + 0]);
277ccd2543fSMatthew G Knepley     PetscReal y_i = PetscRealPart(coords[faces[2 * f + 0] * 2 + 1]);
278ccd2543fSMatthew G Knepley     PetscReal x_j = PetscRealPart(coords[faces[2 * f + 1] * 2 + 0]);
279ccd2543fSMatthew G Knepley     PetscReal y_j = PetscRealPart(coords[faces[2 * f + 1] * 2 + 1]);
28061451c10SMatthew G. Knepley 
28161451c10SMatthew G. Knepley     if ((x == x_j) && (y == y_j)) {
28261451c10SMatthew G. Knepley       // point is a corner
28361451c10SMatthew G. Knepley       crossings = 1;
28461451c10SMatthew G. Knepley       break;
28561451c10SMatthew G. Knepley     }
28661451c10SMatthew G. Knepley     if ((y_j > y) != (y_i > y)) {
28761451c10SMatthew G. Knepley       PetscReal slope = (x - x_j) * (y_i - y_j) - (x_i - x_j) * (y - y_j);
28861451c10SMatthew G. Knepley       if (slope == 0) {
28961451c10SMatthew G. Knepley         // point is a corner
29061451c10SMatthew G. Knepley         crossings = 1;
29161451c10SMatthew G. Knepley         break;
29261451c10SMatthew G. Knepley       }
29361451c10SMatthew G. Knepley       if ((slope < 0) != (y_i < y_j)) ++crossings;
29461451c10SMatthew G. Knepley     }
295ccd2543fSMatthew G Knepley   }
296ccd2543fSMatthew G Knepley   if (crossings % 2) *cell = c;
297c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
29876b3799dSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &coords));
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300ccd2543fSMatthew G Knepley }
301ccd2543fSMatthew G Knepley 
302d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexLocatePoint_Simplex_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
303d71ae5a4SJacob Faibussowitsch {
304ccd2543fSMatthew G Knepley   const PetscInt  embedDim = 3;
30537900f7dSMatthew G. Knepley   const PetscReal eps      = PETSC_SQRT_MACHINE_EPSILON;
306ccd2543fSMatthew G Knepley   PetscReal       v0[3], J[9], invJ[9], detJ;
307ccd2543fSMatthew G Knepley   PetscReal       x = PetscRealPart(point[0]);
308ccd2543fSMatthew G Knepley   PetscReal       y = PetscRealPart(point[1]);
309ccd2543fSMatthew G Knepley   PetscReal       z = PetscRealPart(point[2]);
310ccd2543fSMatthew G Knepley   PetscReal       xi, eta, zeta;
311ccd2543fSMatthew G Knepley 
312ccd2543fSMatthew G Knepley   PetscFunctionBegin;
3139566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
314ccd2543fSMatthew G Knepley   xi   = invJ[0 * embedDim + 0] * (x - v0[0]) + invJ[0 * embedDim + 1] * (y - v0[1]) + invJ[0 * embedDim + 2] * (z - v0[2]);
315ccd2543fSMatthew G Knepley   eta  = invJ[1 * embedDim + 0] * (x - v0[0]) + invJ[1 * embedDim + 1] * (y - v0[1]) + invJ[1 * embedDim + 2] * (z - v0[2]);
316ccd2543fSMatthew G Knepley   zeta = invJ[2 * embedDim + 0] * (x - v0[0]) + invJ[2 * embedDim + 1] * (y - v0[1]) + invJ[2 * embedDim + 2] * (z - v0[2]);
317ccd2543fSMatthew G Knepley 
31837900f7dSMatthew G. Knepley   if ((xi >= -eps) && (eta >= -eps) && (zeta >= -eps) && (xi + eta + zeta <= 2.0 + eps)) *cell = c;
319c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
3203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
321ccd2543fSMatthew G Knepley }
322ccd2543fSMatthew G Knepley 
323d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexLocatePoint_General_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
324d71ae5a4SJacob Faibussowitsch {
32576b3799dSMatthew G. Knepley   const PetscScalar *array;
326872a9804SMatthew G. Knepley   PetscScalar       *coords    = NULL;
3279371c9d4SSatish Balay   const PetscInt     faces[24] = {0, 3, 2, 1, 5, 4, 7, 6, 3, 0, 4, 5, 1, 2, 6, 7, 3, 5, 6, 2, 0, 1, 7, 4};
328ccd2543fSMatthew G Knepley   PetscBool          found     = PETSC_TRUE;
32976b3799dSMatthew G. Knepley   PetscInt           numCoords, f;
33076b3799dSMatthew G. Knepley   PetscBool          isDG;
331ccd2543fSMatthew G Knepley 
332ccd2543fSMatthew G Knepley   PetscFunctionBegin;
33376b3799dSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &coords));
33476b3799dSMatthew G. Knepley   PetscCheck(numCoords == 24, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Quadrilateral should have 8 coordinates, not %" PetscInt_FMT, numCoords);
335ccd2543fSMatthew G Knepley   for (f = 0; f < 6; ++f) {
336ccd2543fSMatthew G Knepley     /* Check the point is under plane */
337ccd2543fSMatthew G Knepley     /*   Get face normal */
338ccd2543fSMatthew G Knepley     PetscReal v_i[3];
339ccd2543fSMatthew G Knepley     PetscReal v_j[3];
340ccd2543fSMatthew G Knepley     PetscReal normal[3];
341ccd2543fSMatthew G Knepley     PetscReal pp[3];
342ccd2543fSMatthew G Knepley     PetscReal dot;
343ccd2543fSMatthew G Knepley 
344ccd2543fSMatthew G Knepley     v_i[0]    = PetscRealPart(coords[faces[f * 4 + 3] * 3 + 0] - coords[faces[f * 4 + 0] * 3 + 0]);
345ccd2543fSMatthew G Knepley     v_i[1]    = PetscRealPart(coords[faces[f * 4 + 3] * 3 + 1] - coords[faces[f * 4 + 0] * 3 + 1]);
346ccd2543fSMatthew G Knepley     v_i[2]    = PetscRealPart(coords[faces[f * 4 + 3] * 3 + 2] - coords[faces[f * 4 + 0] * 3 + 2]);
347ccd2543fSMatthew G Knepley     v_j[0]    = PetscRealPart(coords[faces[f * 4 + 1] * 3 + 0] - coords[faces[f * 4 + 0] * 3 + 0]);
348ccd2543fSMatthew G Knepley     v_j[1]    = PetscRealPart(coords[faces[f * 4 + 1] * 3 + 1] - coords[faces[f * 4 + 0] * 3 + 1]);
349ccd2543fSMatthew G Knepley     v_j[2]    = PetscRealPart(coords[faces[f * 4 + 1] * 3 + 2] - coords[faces[f * 4 + 0] * 3 + 2]);
350ccd2543fSMatthew G Knepley     normal[0] = v_i[1] * v_j[2] - v_i[2] * v_j[1];
351ccd2543fSMatthew G Knepley     normal[1] = v_i[2] * v_j[0] - v_i[0] * v_j[2];
352ccd2543fSMatthew G Knepley     normal[2] = v_i[0] * v_j[1] - v_i[1] * v_j[0];
353ccd2543fSMatthew G Knepley     pp[0]     = PetscRealPart(coords[faces[f * 4 + 0] * 3 + 0] - point[0]);
354ccd2543fSMatthew G Knepley     pp[1]     = PetscRealPart(coords[faces[f * 4 + 0] * 3 + 1] - point[1]);
355ccd2543fSMatthew G Knepley     pp[2]     = PetscRealPart(coords[faces[f * 4 + 0] * 3 + 2] - point[2]);
356ccd2543fSMatthew G Knepley     dot       = normal[0] * pp[0] + normal[1] * pp[1] + normal[2] * pp[2];
357ccd2543fSMatthew G Knepley 
358ccd2543fSMatthew G Knepley     /* Check that projected point is in face (2D location problem) */
359ccd2543fSMatthew G Knepley     if (dot < 0.0) {
360ccd2543fSMatthew G Knepley       found = PETSC_FALSE;
361ccd2543fSMatthew G Knepley       break;
362ccd2543fSMatthew G Knepley     }
363ccd2543fSMatthew G Knepley   }
364ccd2543fSMatthew G Knepley   if (found) *cell = c;
365c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
36676b3799dSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &coords));
3673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
368ccd2543fSMatthew G Knepley }
369ccd2543fSMatthew G Knepley 
370d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscGridHashInitialize_Internal(PetscGridHash box, PetscInt dim, const PetscScalar point[])
371d71ae5a4SJacob Faibussowitsch {
372c4eade1cSMatthew G. Knepley   PetscInt d;
373c4eade1cSMatthew G. Knepley 
374c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
375c4eade1cSMatthew G. Knepley   box->dim = dim;
376378076f8SMatthew G. Knepley   for (d = 0; d < dim; ++d) box->lower[d] = box->upper[d] = point ? PetscRealPart(point[d]) : 0.;
3773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
378c4eade1cSMatthew G. Knepley }
379c4eade1cSMatthew G. Knepley 
380d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashCreate(MPI_Comm comm, PetscInt dim, const PetscScalar point[], PetscGridHash *box)
381d71ae5a4SJacob Faibussowitsch {
382c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
383*2b6f951bSStefano Zampini   PetscCall(PetscCalloc1(1, box));
3849566063dSJacob Faibussowitsch   PetscCall(PetscGridHashInitialize_Internal(*box, dim, point));
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
386c4eade1cSMatthew G. Knepley }
387c4eade1cSMatthew G. Knepley 
388d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashEnlarge(PetscGridHash box, const PetscScalar point[])
389d71ae5a4SJacob Faibussowitsch {
390c4eade1cSMatthew G. Knepley   PetscInt d;
391c4eade1cSMatthew G. Knepley 
392c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
393c4eade1cSMatthew G. Knepley   for (d = 0; d < box->dim; ++d) {
394c4eade1cSMatthew G. Knepley     box->lower[d] = PetscMin(box->lower[d], PetscRealPart(point[d]));
395c4eade1cSMatthew G. Knepley     box->upper[d] = PetscMax(box->upper[d], PetscRealPart(point[d]));
396c4eade1cSMatthew G. Knepley   }
3973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
398c4eade1cSMatthew G. Knepley }
399c4eade1cSMatthew G. Knepley 
40062a38674SMatthew G. Knepley /*
40162a38674SMatthew G. Knepley   PetscGridHashSetGrid - Divide the grid into boxes
40262a38674SMatthew G. Knepley 
40320f4b53cSBarry Smith   Not Collective
40462a38674SMatthew G. Knepley 
40562a38674SMatthew G. Knepley   Input Parameters:
40662a38674SMatthew G. Knepley + box - The grid hash object
40720f4b53cSBarry Smith . n   - The number of boxes in each dimension, or `PETSC_DETERMINE`
40820f4b53cSBarry Smith - h   - The box size in each dimension, only used if n[d] == `PETSC_DETERMINE`
40962a38674SMatthew G. Knepley 
41062a38674SMatthew G. Knepley   Level: developer
41162a38674SMatthew G. Knepley 
4122fe279fdSBarry Smith .seealso: `DMPLEX`, `PetscGridHashCreate()`
41362a38674SMatthew G. Knepley */
414d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashSetGrid(PetscGridHash box, const PetscInt n[], const PetscReal h[])
415d71ae5a4SJacob Faibussowitsch {
416c4eade1cSMatthew G. Knepley   PetscInt d;
417c4eade1cSMatthew G. Knepley 
418c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
419c4eade1cSMatthew G. Knepley   for (d = 0; d < box->dim; ++d) {
420c4eade1cSMatthew G. Knepley     box->extent[d] = box->upper[d] - box->lower[d];
421c4eade1cSMatthew G. Knepley     if (n[d] == PETSC_DETERMINE) {
422c4eade1cSMatthew G. Knepley       box->h[d] = h[d];
423c4eade1cSMatthew G. Knepley       box->n[d] = PetscCeilReal(box->extent[d] / h[d]);
424c4eade1cSMatthew G. Knepley     } else {
425c4eade1cSMatthew G. Knepley       box->n[d] = n[d];
426c4eade1cSMatthew G. Knepley       box->h[d] = box->extent[d] / n[d];
427c4eade1cSMatthew G. Knepley     }
428c4eade1cSMatthew G. Knepley   }
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
430c4eade1cSMatthew G. Knepley }
431c4eade1cSMatthew G. Knepley 
43262a38674SMatthew G. Knepley /*
43362a38674SMatthew G. Knepley   PetscGridHashGetEnclosingBox - Find the grid boxes containing each input point
43462a38674SMatthew G. Knepley 
43520f4b53cSBarry Smith   Not Collective
43662a38674SMatthew G. Knepley 
43762a38674SMatthew G. Knepley   Input Parameters:
43862a38674SMatthew G. Knepley + box       - The grid hash object
43962a38674SMatthew G. Knepley . numPoints - The number of input points
44062a38674SMatthew G. Knepley - points    - The input point coordinates
44162a38674SMatthew G. Knepley 
44262a38674SMatthew G. Knepley   Output Parameters:
44362a38674SMatthew G. Knepley + dboxes    - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim)
44462a38674SMatthew G. Knepley - boxes     - An array of numPoints integers expressing the enclosing box as single number, or NULL
44562a38674SMatthew G. Knepley 
44662a38674SMatthew G. Knepley   Level: developer
44762a38674SMatthew G. Knepley 
448f5867de0SMatthew G. Knepley   Note:
449f5867de0SMatthew G. Knepley   This only guarantees that a box contains a point, not that a cell does.
450f5867de0SMatthew G. Knepley 
4512fe279fdSBarry Smith .seealso: `DMPLEX`, `PetscGridHashCreate()`
45262a38674SMatthew G. Knepley */
453d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashGetEnclosingBox(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[])
454d71ae5a4SJacob Faibussowitsch {
455c4eade1cSMatthew G. Knepley   const PetscReal *lower = box->lower;
456c4eade1cSMatthew G. Knepley   const PetscReal *upper = box->upper;
457c4eade1cSMatthew G. Knepley   const PetscReal *h     = box->h;
458c4eade1cSMatthew G. Knepley   const PetscInt  *n     = box->n;
459c4eade1cSMatthew G. Knepley   const PetscInt   dim   = box->dim;
460c4eade1cSMatthew G. Knepley   PetscInt         d, p;
461c4eade1cSMatthew G. Knepley 
462c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
463c4eade1cSMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
464c4eade1cSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
4651c6dfc3eSMatthew G. Knepley       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p * dim + d]) - lower[d]) / h[d]);
466c4eade1cSMatthew G. Knepley 
4671c6dfc3eSMatthew G. Knepley       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p * dim + d]) - upper[d]) < 1.0e-9) dbox = n[d] - 1;
4682a705cacSMatthew G. Knepley       if (dbox == -1 && PetscAbsReal(PetscRealPart(points[p * dim + d]) - lower[d]) < 1.0e-9) dbox = 0;
4699371c9d4SSatish Balay       PetscCheck(dbox >= 0 && dbox<n[d], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input point %" PetscInt_FMT " (%g, %g, %g) is outside of our bounding box", p, (double)PetscRealPart(points[p * dim + 0]), dim> 1 ? (double)PetscRealPart(points[p * dim + 1]) : 0.0, dim > 2 ? (double)PetscRealPart(points[p * dim + 2]) : 0.0);
470c4eade1cSMatthew G. Knepley       dboxes[p * dim + d] = dbox;
471c4eade1cSMatthew G. Knepley     }
4729371c9d4SSatish Balay     if (boxes)
4739371c9d4SSatish Balay       for (d = dim - 2, boxes[p] = dboxes[p * dim + dim - 1]; d >= 0; --d) boxes[p] = boxes[p] * n[d] + dboxes[p * dim + d];
474c4eade1cSMatthew G. Knepley   }
4753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
476c4eade1cSMatthew G. Knepley }
477c4eade1cSMatthew G. Knepley 
478af74b616SDave May /*
479af74b616SDave May  PetscGridHashGetEnclosingBoxQuery - Find the grid boxes containing each input point
480af74b616SDave May 
48120f4b53cSBarry Smith  Not Collective
482af74b616SDave May 
483af74b616SDave May   Input Parameters:
484af74b616SDave May + box         - The grid hash object
485f5867de0SMatthew G. Knepley . cellSection - The PetscSection mapping cells to boxes
486af74b616SDave May . numPoints   - The number of input points
487af74b616SDave May - points      - The input point coordinates
488af74b616SDave May 
489af74b616SDave May   Output Parameters:
49020f4b53cSBarry Smith + dboxes - An array of `numPoints`*`dim` integers expressing the enclosing box as (i_0, i_1, ..., i_dim)
49120f4b53cSBarry Smith . boxes  - An array of `numPoints` integers expressing the enclosing box as single number, or `NULL`
492af74b616SDave May - found  - Flag indicating if point was located within a box
493af74b616SDave May 
494af74b616SDave May   Level: developer
495af74b616SDave May 
496f5867de0SMatthew G. Knepley   Note:
49720f4b53cSBarry Smith   This does an additional check that a cell actually contains the point, and found is `PETSC_FALSE` if no cell does. Thus, this function requires that `cellSection` is already constructed.
498f5867de0SMatthew G. Knepley 
4992fe279fdSBarry Smith .seealso: `DMPLEX`, `PetscGridHashGetEnclosingBox()`
500af74b616SDave May */
501d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashGetEnclosingBoxQuery(PetscGridHash box, PetscSection cellSection, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[], PetscBool *found)
502d71ae5a4SJacob Faibussowitsch {
503af74b616SDave May   const PetscReal *lower = box->lower;
504af74b616SDave May   const PetscReal *upper = box->upper;
505af74b616SDave May   const PetscReal *h     = box->h;
506af74b616SDave May   const PetscInt  *n     = box->n;
507af74b616SDave May   const PetscInt   dim   = box->dim;
508f5867de0SMatthew G. Knepley   PetscInt         bStart, bEnd, d, p;
509af74b616SDave May 
510af74b616SDave May   PetscFunctionBegin;
511f5867de0SMatthew G. Knepley   PetscValidHeaderSpecific(cellSection, PETSC_SECTION_CLASSID, 2);
512af74b616SDave May   *found = PETSC_FALSE;
513f5867de0SMatthew G. Knepley   PetscCall(PetscSectionGetChart(box->cellSection, &bStart, &bEnd));
514af74b616SDave May   for (p = 0; p < numPoints; ++p) {
515af74b616SDave May     for (d = 0; d < dim; ++d) {
516af74b616SDave May       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p * dim + d]) - lower[d]) / h[d]);
517af74b616SDave May 
518af74b616SDave May       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p * dim + d]) - upper[d]) < 1.0e-9) dbox = n[d] - 1;
5193ba16761SJacob Faibussowitsch       if (dbox < 0 || dbox >= n[d]) PetscFunctionReturn(PETSC_SUCCESS);
520af74b616SDave May       dboxes[p * dim + d] = dbox;
521af74b616SDave May     }
5229371c9d4SSatish Balay     if (boxes)
5239371c9d4SSatish Balay       for (d = dim - 2, boxes[p] = dboxes[p * dim + dim - 1]; d >= 0; --d) boxes[p] = boxes[p] * n[d] + dboxes[p * dim + d];
524f5867de0SMatthew G. Knepley     // It is possible for a box to overlap no grid cells
5253ba16761SJacob Faibussowitsch     if (boxes[p] < bStart || boxes[p] >= bEnd) PetscFunctionReturn(PETSC_SUCCESS);
526af74b616SDave May   }
527af74b616SDave May   *found = PETSC_TRUE;
5283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
529af74b616SDave May }
530af74b616SDave May 
531d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGridHashDestroy(PetscGridHash *box)
532d71ae5a4SJacob Faibussowitsch {
533c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
534c4eade1cSMatthew G. Knepley   if (*box) {
5359566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(*box)->cellSection));
5369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&(*box)->cells));
5379566063dSJacob Faibussowitsch     PetscCall(DMLabelDestroy(&(*box)->cellsSparse));
538c4eade1cSMatthew G. Knepley   }
5399566063dSJacob Faibussowitsch   PetscCall(PetscFree(*box));
5403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
541c4eade1cSMatthew G. Knepley }
542c4eade1cSMatthew G. Knepley 
543d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocatePoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cellStart, PetscInt *cell)
544d71ae5a4SJacob Faibussowitsch {
545ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
546cafe43deSMatthew G. Knepley 
547cafe43deSMatthew G. Knepley   PetscFunctionBegin;
5489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cellStart, &ct));
549ba2698f1SMatthew G. Knepley   switch (ct) {
550d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_SEGMENT:
551d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_1D_Internal(dm, point, cellStart, cell));
552d71ae5a4SJacob Faibussowitsch     break;
553d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_TRIANGLE:
554d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_2D_Internal(dm, point, cellStart, cell));
555d71ae5a4SJacob Faibussowitsch     break;
556d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_QUADRILATERAL:
557d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Quad_2D_Internal(dm, point, cellStart, cell));
558d71ae5a4SJacob Faibussowitsch     break;
559d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_TETRAHEDRON:
560d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_3D_Internal(dm, point, cellStart, cell));
561d71ae5a4SJacob Faibussowitsch     break;
562d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_HEXAHEDRON:
563d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_General_3D_Internal(dm, point, cellStart, cell));
564d71ae5a4SJacob Faibussowitsch     break;
565d71ae5a4SJacob Faibussowitsch   default:
566d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell %" PetscInt_FMT " with type %s", cellStart, DMPolytopeTypes[ct]);
567cafe43deSMatthew G. Knepley   }
5683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
569cafe43deSMatthew G. Knepley }
570cafe43deSMatthew G. Knepley 
57162a38674SMatthew G. Knepley /*
57262a38674SMatthew G. Knepley   DMPlexClosestPoint_Internal - Returns the closest point in the cell to the given point
57362a38674SMatthew G. Knepley */
574d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexClosestPoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cell, PetscReal cpoint[])
575d71ae5a4SJacob Faibussowitsch {
576ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
57762a38674SMatthew G. Knepley 
57862a38674SMatthew G. Knepley   PetscFunctionBegin;
5799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
580ba2698f1SMatthew G. Knepley   switch (ct) {
581d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_TRIANGLE:
582d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_2D_Internal(dm, point, cell, cpoint));
583d71ae5a4SJacob Faibussowitsch     break;
58462a38674SMatthew G. Knepley #if 0
585ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
5869566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_2D_Internal(dm, point, cell, cpoint));break;
587ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
5889566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_3D_Internal(dm, point, cell, cpoint));break;
589ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
5909566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_3D_Internal(dm, point, cell, cpoint));break;
59162a38674SMatthew G. Knepley #endif
592d71ae5a4SJacob Faibussowitsch   default:
593d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No closest point location for cell %" PetscInt_FMT " with type %s", cell, DMPolytopeTypes[ct]);
59462a38674SMatthew G. Knepley   }
5953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59662a38674SMatthew G. Knepley }
59762a38674SMatthew G. Knepley 
59862a38674SMatthew G. Knepley /*
59920f4b53cSBarry Smith   DMPlexComputeGridHash_Internal - Create a grid hash structure covering the `DMPLEX`
60062a38674SMatthew G. Knepley 
60120f4b53cSBarry Smith   Collective
60262a38674SMatthew G. Knepley 
60362a38674SMatthew G. Knepley   Input Parameter:
60420f4b53cSBarry Smith . dm - The `DMPLEX`
60562a38674SMatthew G. Knepley 
60662a38674SMatthew G. Knepley   Output Parameter:
60762a38674SMatthew G. Knepley . localBox - The grid hash object
60862a38674SMatthew G. Knepley 
60962a38674SMatthew G. Knepley   Level: developer
61062a38674SMatthew G. Knepley 
61120f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscGridHashCreate()`, `PetscGridHashGetEnclosingBox()`
61262a38674SMatthew G. Knepley */
613d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGridHash_Internal(DM dm, PetscGridHash *localBox)
614d71ae5a4SJacob Faibussowitsch {
615f5867de0SMatthew G. Knepley   PetscInt           debug = ((DM_Plex *)dm->data)->printLocate;
616cafe43deSMatthew G. Knepley   MPI_Comm           comm;
617cafe43deSMatthew G. Knepley   PetscGridHash      lbox;
61896217254SMatthew G. Knepley   PetscSF            sf;
619cafe43deSMatthew G. Knepley   Vec                coordinates;
620cafe43deSMatthew G. Knepley   PetscSection       coordSection;
621cafe43deSMatthew G. Knepley   Vec                coordsLocal;
622cafe43deSMatthew G. Knepley   const PetscScalar *coords;
623ddce0771SMatthew G. Knepley   PetscScalar       *edgeCoords;
624722d0f5cSMatthew G. Knepley   PetscInt          *dboxes, *boxes;
62596217254SMatthew G. Knepley   const PetscInt    *leaves;
626ddce0771SMatthew G. Knepley   PetscInt           n[3] = {2, 2, 2};
62796217254SMatthew G. Knepley   PetscInt           dim, N, Nl = 0, maxConeSize, cStart, cEnd, c, eStart, eEnd, i;
628ddce0771SMatthew G. Knepley   PetscBool          flg;
629cafe43deSMatthew G. Knepley 
630cafe43deSMatthew G. Knepley   PetscFunctionBegin;
6319566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
6329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
6339566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
6349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
6359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
6369566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
6379566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
6389566063dSJacob Faibussowitsch   PetscCall(PetscGridHashCreate(comm, dim, coords, &lbox));
6399566063dSJacob Faibussowitsch   for (i = 0; i < N; i += dim) PetscCall(PetscGridHashEnlarge(lbox, &coords[i]));
6409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
641ddce0771SMatthew G. Knepley   c = dim;
6429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, "-dm_plex_hash_box_faces", n, &c, &flg));
6439371c9d4SSatish Balay   if (flg) {
6449371c9d4SSatish Balay     for (i = c; i < dim; ++i) n[i] = n[c - 1];
6459371c9d4SSatish Balay   } else {
6469371c9d4SSatish Balay     for (i = 0; i < dim; ++i) n[i] = PetscMax(2, PetscFloorReal(PetscPowReal((PetscReal)(cEnd - cStart), 1.0 / dim) * 0.8));
6479371c9d4SSatish Balay   }
6489566063dSJacob Faibussowitsch   PetscCall(PetscGridHashSetGrid(lbox, n, NULL));
6499371c9d4SSatish Balay   if (debug)
6509371c9d4SSatish Balay     PetscCall(PetscPrintf(PETSC_COMM_SELF, "GridHash:\n  (%g, %g, %g) -- (%g, %g, %g)\n  n %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n  h %g %g %g\n", (double)lbox->lower[0], (double)lbox->lower[1], (double)lbox->lower[2], (double)lbox->upper[0],
6519371c9d4SSatish Balay                           (double)lbox->upper[1], (double)lbox->upper[2], n[0], n[1], n[2], (double)lbox->h[0], (double)lbox->h[1], (double)lbox->h[2]));
652cafe43deSMatthew G. Knepley #if 0
653cafe43deSMatthew G. Knepley   /* Could define a custom reduction to merge these */
6541c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->lower, gbox->lower, 3, MPIU_REAL, MPI_MIN, comm));
6551c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->upper, gbox->upper, 3, MPIU_REAL, MPI_MAX, comm));
656cafe43deSMatthew G. Knepley #endif
657cafe43deSMatthew G. Knepley   /* Is there a reason to snap the local bounding box to a division of the global box? */
658cafe43deSMatthew G. Knepley   /* Should we compute all overlaps of local boxes? We could do this with a rendevouz scheme partitioning the global box */
659cafe43deSMatthew G. Knepley   /* Create label */
6609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
661b26b5bf9SMatthew G. Knepley   if (dim < 2) eStart = eEnd = -1;
6629566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "cells", &lbox->cellsSparse));
6639566063dSJacob Faibussowitsch   PetscCall(DMLabelCreateIndex(lbox->cellsSparse, cStart, cEnd));
664a8d69d7bSBarry Smith   /* Compute boxes which overlap each cell: https://stackoverflow.com/questions/13790208/triangle-square-intersection-test-in-2d */
6659566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
6669566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
66796217254SMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
66896217254SMatthew G. Knepley   if (sf) PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
66996217254SMatthew G. Knepley   Nl = PetscMax(Nl, 0);
6709566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(16 * dim, &dboxes, 16, &boxes, PetscPowInt(maxConeSize, dim) * dim, &edgeCoords));
671cafe43deSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
672cafe43deSMatthew G. Knepley     const PetscReal *h       = lbox->h;
673cafe43deSMatthew G. Knepley     PetscScalar     *ccoords = NULL;
67438353de4SMatthew G. Knepley     PetscInt         csize   = 0;
675ddce0771SMatthew G. Knepley     PetscInt        *closure = NULL;
67696217254SMatthew G. Knepley     PetscInt         Ncl, cl, Ne = 0, idx;
677cafe43deSMatthew G. Knepley     PetscScalar      point[3];
678cafe43deSMatthew G. Knepley     PetscInt         dlim[6], d, e, i, j, k;
679cafe43deSMatthew G. Knepley 
68096217254SMatthew G. Knepley     PetscCall(PetscFindInt(c, Nl, leaves, &idx));
68196217254SMatthew G. Knepley     if (idx >= 0) continue;
682ddce0771SMatthew G. Knepley     /* Get all edges in cell */
6839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
684ddce0771SMatthew G. Knepley     for (cl = 0; cl < Ncl * 2; ++cl) {
685ddce0771SMatthew G. Knepley       if ((closure[cl] >= eStart) && (closure[cl] < eEnd)) {
686ddce0771SMatthew G. Knepley         PetscScalar *ecoords = &edgeCoords[Ne * dim * 2];
687ddce0771SMatthew G. Knepley         PetscInt     ecsize  = dim * 2;
688ddce0771SMatthew G. Knepley 
6899566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, closure[cl], &ecsize, &ecoords));
69063a3b9bcSJacob Faibussowitsch         PetscCheck(ecsize == dim * 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Got %" PetscInt_FMT " coords for edge, instead of %" PetscInt_FMT, ecsize, dim * 2);
691ddce0771SMatthew G. Knepley         ++Ne;
692ddce0771SMatthew G. Knepley       }
693ddce0771SMatthew G. Knepley     }
6949566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
695cafe43deSMatthew G. Knepley     /* Find boxes enclosing each vertex */
6969566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &csize, &ccoords));
6979566063dSJacob Faibussowitsch     PetscCall(PetscGridHashGetEnclosingBox(lbox, csize / dim, ccoords, dboxes, boxes));
698722d0f5cSMatthew G. Knepley     /* Mark cells containing the vertices */
699ddce0771SMatthew G. Knepley     for (e = 0; e < csize / dim; ++e) {
7009371c9d4SSatish Balay       if (debug)
7019d67f9e5SMatthew G. Knepley         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " has vertex (%g, %g, %g) in box %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", c, (double)PetscRealPart(ccoords[e * dim + 0]), dim > 1 ? (double)PetscRealPart(ccoords[e * dim + 1]) : 0., dim > 2 ? (double)PetscRealPart(ccoords[e * dim + 2]) : 0., boxes[e], dboxes[e * dim + 0], dim > 1 ? dboxes[e * dim + 1] : -1, dim > 2 ? dboxes[e * dim + 2] : -1));
7029566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(lbox->cellsSparse, c, boxes[e]));
703ddce0771SMatthew G. Knepley     }
704cafe43deSMatthew G. Knepley     /* Get grid of boxes containing these */
705ad540459SPierre Jolivet     for (d = 0; d < dim; ++d) dlim[d * 2 + 0] = dlim[d * 2 + 1] = dboxes[d];
706ad540459SPierre Jolivet     for (d = dim; d < 3; ++d) dlim[d * 2 + 0] = dlim[d * 2 + 1] = 0;
707cafe43deSMatthew G. Knepley     for (e = 1; e < dim + 1; ++e) {
708cafe43deSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
709cafe43deSMatthew G. Knepley         dlim[d * 2 + 0] = PetscMin(dlim[d * 2 + 0], dboxes[e * dim + d]);
710cafe43deSMatthew G. Knepley         dlim[d * 2 + 1] = PetscMax(dlim[d * 2 + 1], dboxes[e * dim + d]);
711cafe43deSMatthew G. Knepley       }
712cafe43deSMatthew G. Knepley     }
713fea14342SMatthew G. Knepley     /* Check for intersection of box with cell */
714cafe43deSMatthew G. Knepley     for (k = dlim[2 * 2 + 0], point[2] = lbox->lower[2] + k * h[2]; k <= dlim[2 * 2 + 1]; ++k, point[2] += h[2]) {
715cafe43deSMatthew G. Knepley       for (j = dlim[1 * 2 + 0], point[1] = lbox->lower[1] + j * h[1]; j <= dlim[1 * 2 + 1]; ++j, point[1] += h[1]) {
716cafe43deSMatthew G. Knepley         for (i = dlim[0 * 2 + 0], point[0] = lbox->lower[0] + i * h[0]; i <= dlim[0 * 2 + 1]; ++i, point[0] += h[0]) {
717cafe43deSMatthew G. Knepley           const PetscInt box = (k * lbox->n[1] + j) * lbox->n[0] + i;
718cafe43deSMatthew G. Knepley           PetscScalar    cpoint[3];
719fea14342SMatthew G. Knepley           PetscInt       cell, edge, ii, jj, kk;
720cafe43deSMatthew G. Knepley 
7219371c9d4SSatish Balay           if (debug)
7229371c9d4SSatish Balay             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Box %" PetscInt_FMT ": (%.2g, %.2g, %.2g) -- (%.2g, %.2g, %.2g)\n", box, (double)PetscRealPart(point[0]), (double)PetscRealPart(point[1]), (double)PetscRealPart(point[2]), (double)PetscRealPart(point[0] + h[0]), (double)PetscRealPart(point[1] + h[1]), (double)PetscRealPart(point[2] + h[2])));
723ddce0771SMatthew G. Knepley           /* Check whether cell contains any vertex of this subbox TODO vectorize this */
724cafe43deSMatthew G. Knepley           for (kk = 0, cpoint[2] = point[2]; kk < (dim > 2 ? 2 : 1); ++kk, cpoint[2] += h[2]) {
725cafe43deSMatthew G. Knepley             for (jj = 0, cpoint[1] = point[1]; jj < (dim > 1 ? 2 : 1); ++jj, cpoint[1] += h[1]) {
726cafe43deSMatthew G. Knepley               for (ii = 0, cpoint[0] = point[0]; ii < 2; ++ii, cpoint[0] += h[0]) {
7279566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(dm, dim, cpoint, c, &cell));
7280b6bfacdSStefano Zampini                 if (cell >= 0) {
7299371c9d4SSatish Balay                   if (debug)
7309371c9d4SSatish Balay                     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Cell %" PetscInt_FMT " contains vertex (%.2g, %.2g, %.2g) of box %" PetscInt_FMT "\n", c, (double)PetscRealPart(cpoint[0]), (double)PetscRealPart(cpoint[1]), (double)PetscRealPart(cpoint[2]), box));
7319566063dSJacob Faibussowitsch                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box));
7320b6bfacdSStefano Zampini                   jj = kk = 2;
7330b6bfacdSStefano Zampini                   break;
7340b6bfacdSStefano Zampini                 }
735cafe43deSMatthew G. Knepley               }
736cafe43deSMatthew G. Knepley             }
737cafe43deSMatthew G. Knepley           }
738ddce0771SMatthew G. Knepley           /* Check whether cell edge intersects any face of these subboxes TODO vectorize this */
739ddce0771SMatthew G. Knepley           for (edge = 0; edge < Ne; ++edge) {
740a5cae605SSatish Balay             PetscReal segA[6] = {0., 0., 0., 0., 0., 0.};
741a5cae605SSatish Balay             PetscReal segB[6] = {0., 0., 0., 0., 0., 0.};
742a5cae605SSatish Balay             PetscReal segC[6] = {0., 0., 0., 0., 0., 0.};
743fea14342SMatthew G. Knepley 
74463a3b9bcSJacob Faibussowitsch             PetscCheck(dim <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected dim %" PetscInt_FMT " > 3", dim);
745ddce0771SMatthew G. Knepley             for (d = 0; d < dim * 2; ++d) segA[d] = PetscRealPart(edgeCoords[edge * dim * 2 + d]);
746ddce0771SMatthew G. Knepley             /* 1D: (x) -- (x+h)               0 -- 1
747ddce0771SMatthew G. Knepley                2D: (x,   y)   -- (x,   y+h)   (0, 0) -- (0, 1)
748ddce0771SMatthew G. Knepley                    (x+h, y)   -- (x+h, y+h)   (1, 0) -- (1, 1)
749ddce0771SMatthew G. Knepley                    (x,   y)   -- (x+h, y)     (0, 0) -- (1, 0)
750ddce0771SMatthew G. Knepley                    (x,   y+h) -- (x+h, y+h)   (0, 1) -- (1, 1)
751ddce0771SMatthew G. Knepley                3D: (x,   y,   z)   -- (x,   y+h, z),   (x,   y,   z)   -- (x,   y,   z+h) (0, 0, 0) -- (0, 1, 0), (0, 0, 0) -- (0, 0, 1)
752ddce0771SMatthew G. Knepley                    (x+h, y,   z)   -- (x+h, y+h, z),   (x+h, y,   z)   -- (x+h, y,   z+h) (1, 0, 0) -- (1, 1, 0), (1, 0, 0) -- (1, 0, 1)
753ddce0771SMatthew G. Knepley                    (x,   y,   z)   -- (x+h, y,   z),   (x,   y,   z)   -- (x,   y,   z+h) (0, 0, 0) -- (1, 0, 0), (0, 0, 0) -- (0, 0, 1)
754ddce0771SMatthew G. Knepley                    (x,   y+h, z)   -- (x+h, y+h, z),   (x,   y+h, z)   -- (x,   y+h, z+h) (0, 1, 0) -- (1, 1, 0), (0, 1, 0) -- (0, 1, 1)
755ddce0771SMatthew G. Knepley                    (x,   y,   z)   -- (x+h, y,   z),   (x,   y,   z)   -- (x,   y+h, z)   (0, 0, 0) -- (1, 0, 0), (0, 0, 0) -- (0, 1, 0)
756ddce0771SMatthew G. Knepley                    (x,   y,   z+h) -- (x+h, y,   z+h), (x,   y,   z+h) -- (x,   y+h, z+h) (0, 0, 1) -- (1, 0, 1), (0, 0, 1) -- (0, 1, 1)
757ddce0771SMatthew G. Knepley              */
758ddce0771SMatthew G. Knepley             /* Loop over faces with normal in direction d */
759ddce0771SMatthew G. Knepley             for (d = 0; d < dim; ++d) {
760ddce0771SMatthew G. Knepley               PetscBool intersects = PETSC_FALSE;
761ddce0771SMatthew G. Knepley               PetscInt  e          = (d + 1) % dim;
762ddce0771SMatthew G. Knepley               PetscInt  f          = (d + 2) % dim;
763ddce0771SMatthew G. Knepley 
764ddce0771SMatthew G. Knepley               /* There are two faces in each dimension */
765ddce0771SMatthew G. Knepley               for (ii = 0; ii < 2; ++ii) {
766ddce0771SMatthew G. Knepley                 segB[d]       = PetscRealPart(point[d] + ii * h[d]);
767ddce0771SMatthew G. Knepley                 segB[dim + d] = PetscRealPart(point[d] + ii * h[d]);
768ddce0771SMatthew G. Knepley                 segC[d]       = PetscRealPart(point[d] + ii * h[d]);
769ddce0771SMatthew G. Knepley                 segC[dim + d] = PetscRealPart(point[d] + ii * h[d]);
770ddce0771SMatthew G. Knepley                 if (dim > 1) {
771ddce0771SMatthew G. Knepley                   segB[e]       = PetscRealPart(point[e] + 0 * h[e]);
772ddce0771SMatthew G. Knepley                   segB[dim + e] = PetscRealPart(point[e] + 1 * h[e]);
773ddce0771SMatthew G. Knepley                   segC[e]       = PetscRealPart(point[e] + 0 * h[e]);
774ddce0771SMatthew G. Knepley                   segC[dim + e] = PetscRealPart(point[e] + 0 * h[e]);
775ddce0771SMatthew G. Knepley                 }
776ddce0771SMatthew G. Knepley                 if (dim > 2) {
777ddce0771SMatthew G. Knepley                   segB[f]       = PetscRealPart(point[f] + 0 * h[f]);
778ddce0771SMatthew G. Knepley                   segB[dim + f] = PetscRealPart(point[f] + 0 * h[f]);
779ddce0771SMatthew G. Knepley                   segC[f]       = PetscRealPart(point[f] + 0 * h[f]);
780ddce0771SMatthew G. Knepley                   segC[dim + f] = PetscRealPart(point[f] + 1 * h[f]);
781ddce0771SMatthew G. Knepley                 }
782ddce0771SMatthew G. Knepley                 if (dim == 2) {
7839566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLineIntersection_2D_Internal(segA, segB, NULL, &intersects));
784ddce0771SMatthew G. Knepley                 } else if (dim == 3) {
7859566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLinePlaneIntersection_3D_Internal(segA, segB, segC, NULL, &intersects));
786ddce0771SMatthew G. Knepley                 }
787ddce0771SMatthew G. Knepley                 if (intersects) {
7889371c9d4SSatish Balay                   if (debug)
7899371c9d4SSatish Balay                     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Cell %" PetscInt_FMT " edge %" PetscInt_FMT " (%.2g, %.2g, %.2g)--(%.2g, %.2g, %.2g) intersects box %" PetscInt_FMT ", face (%.2g, %.2g, %.2g)--(%.2g, %.2g, %.2g) (%.2g, %.2g, %.2g)--(%.2g, %.2g, %.2g)\n", c, edge, (double)segA[0], (double)segA[1], (double)segA[2], (double)segA[3], (double)segA[4], (double)segA[5], box, (double)segB[0], (double)segB[1], (double)segB[2], (double)segB[3], (double)segB[4], (double)segB[5], (double)segC[0], (double)segC[1], (double)segC[2], (double)segC[3], (double)segC[4], (double)segC[5]));
7909371c9d4SSatish Balay                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box));
7919371c9d4SSatish Balay                   edge = Ne;
7929371c9d4SSatish Balay                   break;
793ddce0771SMatthew G. Knepley                 }
794ddce0771SMatthew G. Knepley               }
795ddce0771SMatthew G. Knepley             }
796cafe43deSMatthew G. Knepley           }
797fea14342SMatthew G. Knepley         }
798fea14342SMatthew G. Knepley       }
799fea14342SMatthew G. Knepley     }
8009566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &ccoords));
801fea14342SMatthew G. Knepley   }
8029566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dboxes, boxes, edgeCoords));
8039566063dSJacob Faibussowitsch   if (debug) PetscCall(DMLabelView(lbox->cellsSparse, PETSC_VIEWER_STDOUT_SELF));
8049566063dSJacob Faibussowitsch   PetscCall(DMLabelConvertToSection(lbox->cellsSparse, &lbox->cellSection, &lbox->cells));
8059566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lbox->cellsSparse));
806cafe43deSMatthew G. Knepley   *localBox = lbox;
8073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
808cafe43deSMatthew G. Knepley }
809cafe43deSMatthew G. Knepley 
810d71ae5a4SJacob Faibussowitsch PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, DMPointLocationType ltype, PetscSF cellSF)
811d71ae5a4SJacob Faibussowitsch {
812f5867de0SMatthew G. Knepley   PetscInt        debug = ((DM_Plex *)dm->data)->printLocate;
813cafe43deSMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
814af74b616SDave May   PetscBool       hash = mesh->useHashLocation, reuse = PETSC_FALSE;
8153a93e3b7SToby Isaac   PetscInt        bs, numPoints, p, numFound, *found = NULL;
816d8206211SMatthew G. Knepley   PetscInt        dim, Nl = 0, cStart, cEnd, numCells, c, d;
817d8206211SMatthew G. Knepley   PetscSF         sf;
818d8206211SMatthew G. Knepley   const PetscInt *leaves;
819cafe43deSMatthew G. Knepley   const PetscInt *boxCells;
8203a93e3b7SToby Isaac   PetscSFNode    *cells;
821ccd2543fSMatthew G Knepley   PetscScalar    *a;
8223a93e3b7SToby Isaac   PetscMPIInt     result;
823af74b616SDave May   PetscLogDouble  t0, t1;
8249cb35068SDave May   PetscReal       gmin[3], gmax[3];
8259cb35068SDave May   PetscInt        terminating_query_type[] = {0, 0, 0};
826ccd2543fSMatthew G Knepley 
827ccd2543fSMatthew G Knepley   PetscFunctionBegin;
8289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocatePoints, 0, 0, 0, 0));
8299566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t0));
8301dca8a05SBarry Smith   PetscCheck(ltype != DM_POINTLOCATION_NEAREST || hash, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Nearest point location only supported with grid hashing. Use -dm_plex_hash_location to enable it.");
8319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
8329566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
8339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)cellSF), PETSC_COMM_SELF, &result));
8341dca8a05SBarry Smith   PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT, PetscObjectComm((PetscObject)cellSF), PETSC_ERR_SUP, "Trying parallel point location: only local point location supported");
83563a3b9bcSJacob Faibussowitsch   PetscCheck(bs == dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %" PetscInt_FMT " must be the mesh coordinate dimension %" PetscInt_FMT, bs, dim);
8366858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
8379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
838d8206211SMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sf));
839d8206211SMatthew G. Knepley   if (sf) PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
840d8206211SMatthew G. Knepley   Nl = PetscMax(Nl, 0);
8419566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &numPoints));
8429566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
843ccd2543fSMatthew G Knepley   numPoints /= bs;
844af74b616SDave May   {
845af74b616SDave May     const PetscSFNode *sf_cells;
846af74b616SDave May 
8479566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(cellSF, NULL, NULL, NULL, &sf_cells));
848af74b616SDave May     if (sf_cells) {
8499566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "[DMLocatePoints_Plex] Re-using existing StarForest node list\n"));
850af74b616SDave May       cells = (PetscSFNode *)sf_cells;
851af74b616SDave May       reuse = PETSC_TRUE;
852af74b616SDave May     } else {
8539566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "[DMLocatePoints_Plex] Creating and initializing new StarForest node list\n"));
8549566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numPoints, &cells));
855af74b616SDave May       /* initialize cells if created */
856af74b616SDave May       for (p = 0; p < numPoints; p++) {
857af74b616SDave May         cells[p].rank  = 0;
858af74b616SDave May         cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
859af74b616SDave May       }
860af74b616SDave May     }
861af74b616SDave May   }
86276b3799dSMatthew G. Knepley   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
863953fc75cSMatthew G. Knepley   if (hash) {
8649371c9d4SSatish Balay     if (!mesh->lbox) {
86596217254SMatthew G. Knepley       PetscCall(PetscInfo(dm, "Initializing grid hashing\n"));
8669371c9d4SSatish Balay       PetscCall(DMPlexComputeGridHash_Internal(dm, &mesh->lbox));
8679371c9d4SSatish Balay     }
868cafe43deSMatthew G. Knepley     /* Designate the local box for each point */
869cafe43deSMatthew G. Knepley     /* Send points to correct process */
870cafe43deSMatthew G. Knepley     /* Search cells that lie in each subbox */
871cafe43deSMatthew G. Knepley     /*   Should we bin points before doing search? */
8729566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(mesh->lbox->cells, &boxCells));
873953fc75cSMatthew G. Knepley   }
8743a93e3b7SToby Isaac   for (p = 0, numFound = 0; p < numPoints; ++p) {
875ccd2543fSMatthew G Knepley     const PetscScalar *point   = &a[p * bs];
876e56f9228SJed Brown     PetscInt           dbin[3] = {-1, -1, -1}, bin, cell = -1, cellOffset;
8779cb35068SDave May     PetscBool          point_outside_domain = PETSC_FALSE;
878ccd2543fSMatthew G Knepley 
8799cb35068SDave May     /* check bounding box of domain */
8809cb35068SDave May     for (d = 0; d < dim; d++) {
8819371c9d4SSatish Balay       if (PetscRealPart(point[d]) < gmin[d]) {
8829371c9d4SSatish Balay         point_outside_domain = PETSC_TRUE;
8839371c9d4SSatish Balay         break;
8849371c9d4SSatish Balay       }
8859371c9d4SSatish Balay       if (PetscRealPart(point[d]) > gmax[d]) {
8869371c9d4SSatish Balay         point_outside_domain = PETSC_TRUE;
8879371c9d4SSatish Balay         break;
8889371c9d4SSatish Balay       }
8899cb35068SDave May     }
8909cb35068SDave May     if (point_outside_domain) {
891e9b685f5SMatthew G. Knepley       cells[p].rank  = 0;
892e9b685f5SMatthew G. Knepley       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
8939cb35068SDave May       terminating_query_type[0]++;
8949cb35068SDave May       continue;
8959cb35068SDave May     }
896ccd2543fSMatthew G Knepley 
897af74b616SDave May     /* check initial values in cells[].index - abort early if found */
898af74b616SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
899af74b616SDave May       c              = cells[p].index;
9003a93e3b7SToby Isaac       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
9019566063dSJacob Faibussowitsch       PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
902af74b616SDave May       if (cell >= 0) {
903af74b616SDave May         cells[p].rank  = 0;
904af74b616SDave May         cells[p].index = cell;
905af74b616SDave May         numFound++;
906af74b616SDave May       }
907af74b616SDave May     }
9089cb35068SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
9099cb35068SDave May       terminating_query_type[1]++;
9109cb35068SDave May       continue;
9119cb35068SDave May     }
912af74b616SDave May 
913953fc75cSMatthew G. Knepley     if (hash) {
914af74b616SDave May       PetscBool found_box;
915af74b616SDave May 
91663a3b9bcSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Checking point %" PetscInt_FMT " (%.2g, %.2g, %.2g)\n", p, (double)PetscRealPart(point[0]), (double)PetscRealPart(point[1]), (double)PetscRealPart(point[2])));
917af74b616SDave May       /* allow for case that point is outside box - abort early */
918f5867de0SMatthew G. Knepley       PetscCall(PetscGridHashGetEnclosingBoxQuery(mesh->lbox, mesh->lbox->cellSection, 1, point, dbin, &bin, &found_box));
919af74b616SDave May       if (found_box) {
92063a3b9bcSJacob Faibussowitsch         if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Found point in box %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", bin, dbin[0], dbin[1], dbin[2]));
921cafe43deSMatthew G. Knepley         /* TODO Lay an interface over this so we can switch between Section (dense) and Label (sparse) */
9229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
9239566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
924cafe43deSMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
92563a3b9bcSJacob Faibussowitsch           if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Checking for point in cell %" PetscInt_FMT "\n", boxCells[c]));
9269566063dSJacob Faibussowitsch           PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, boxCells[c], &cell));
9273a93e3b7SToby Isaac           if (cell >= 0) {
92863a3b9bcSJacob Faibussowitsch             if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      FOUND in cell %" PetscInt_FMT "\n", cell));
9293a93e3b7SToby Isaac             cells[p].rank  = 0;
9303a93e3b7SToby Isaac             cells[p].index = cell;
9313a93e3b7SToby Isaac             numFound++;
9329cb35068SDave May             terminating_query_type[2]++;
9333a93e3b7SToby Isaac             break;
934ccd2543fSMatthew G Knepley           }
9353a93e3b7SToby Isaac         }
936af74b616SDave May       }
937953fc75cSMatthew G. Knepley     } else {
938953fc75cSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
939d8206211SMatthew G. Knepley         PetscInt idx;
940d8206211SMatthew G. Knepley 
941d8206211SMatthew G. Knepley         PetscCall(PetscFindInt(c, Nl, leaves, &idx));
942d8206211SMatthew G. Knepley         if (idx >= 0) continue;
9439566063dSJacob Faibussowitsch         PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
9443a93e3b7SToby Isaac         if (cell >= 0) {
9453a93e3b7SToby Isaac           cells[p].rank  = 0;
9463a93e3b7SToby Isaac           cells[p].index = cell;
9473a93e3b7SToby Isaac           numFound++;
9489cb35068SDave May           terminating_query_type[2]++;
9493a93e3b7SToby Isaac           break;
950953fc75cSMatthew G. Knepley         }
951953fc75cSMatthew G. Knepley       }
9523a93e3b7SToby Isaac     }
953ccd2543fSMatthew G Knepley   }
9549566063dSJacob Faibussowitsch   if (hash) PetscCall(ISRestoreIndices(mesh->lbox->cells, &boxCells));
95562a38674SMatthew G. Knepley   if (ltype == DM_POINTLOCATION_NEAREST && hash && numFound < numPoints) {
95662a38674SMatthew G. Knepley     for (p = 0; p < numPoints; p++) {
95762a38674SMatthew G. Knepley       const PetscScalar *point = &a[p * bs];
958d92c4b9fSToby Isaac       PetscReal          cpoint[3], diff[3], best[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}, dist, distMax = PETSC_MAX_REAL;
959d92c4b9fSToby Isaac       PetscInt           dbin[3] = {-1, -1, -1}, bin, cellOffset, d, bestc = -1;
96062a38674SMatthew G. Knepley 
961e9b685f5SMatthew G. Knepley       if (cells[p].index < 0) {
9629566063dSJacob Faibussowitsch         PetscCall(PetscGridHashGetEnclosingBox(mesh->lbox, 1, point, dbin, &bin));
9639566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
9649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
96562a38674SMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
9669566063dSJacob Faibussowitsch           PetscCall(DMPlexClosestPoint_Internal(dm, dim, point, boxCells[c], cpoint));
967b716b415SMatthew G. Knepley           for (d = 0; d < dim; ++d) diff[d] = cpoint[d] - PetscRealPart(point[d]);
96862a38674SMatthew G. Knepley           dist = DMPlex_NormD_Internal(dim, diff);
96962a38674SMatthew G. Knepley           if (dist < distMax) {
970d92c4b9fSToby Isaac             for (d = 0; d < dim; ++d) best[d] = cpoint[d];
971d92c4b9fSToby Isaac             bestc   = boxCells[c];
97262a38674SMatthew G. Knepley             distMax = dist;
97362a38674SMatthew G. Knepley           }
97462a38674SMatthew G. Knepley         }
975d92c4b9fSToby Isaac         if (distMax < PETSC_MAX_REAL) {
976d92c4b9fSToby Isaac           ++numFound;
977d92c4b9fSToby Isaac           cells[p].rank  = 0;
978d92c4b9fSToby Isaac           cells[p].index = bestc;
979d92c4b9fSToby Isaac           for (d = 0; d < dim; ++d) a[p * bs + d] = best[d];
980d92c4b9fSToby Isaac         }
98162a38674SMatthew G. Knepley       }
98262a38674SMatthew G. Knepley     }
98362a38674SMatthew G. Knepley   }
98462a38674SMatthew G. Knepley   /* This code is only be relevant when interfaced to parallel point location */
985cafe43deSMatthew G. Knepley   /* Check for highest numbered proc that claims a point (do we care?) */
9862d1fa6caSMatthew G. Knepley   if (ltype == DM_POINTLOCATION_REMOVE && numFound < numPoints) {
9879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFound, &found));
9883a93e3b7SToby Isaac     for (p = 0, numFound = 0; p < numPoints; p++) {
9893a93e3b7SToby Isaac       if (cells[p].rank >= 0 && cells[p].index >= 0) {
990ad540459SPierre Jolivet         if (numFound < p) cells[numFound] = cells[p];
9913a93e3b7SToby Isaac         found[numFound++] = p;
9923a93e3b7SToby Isaac       }
9933a93e3b7SToby Isaac     }
9943a93e3b7SToby Isaac   }
9959566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
99648a46eb9SPierre Jolivet   if (!reuse) PetscCall(PetscSFSetGraph(cellSF, cEnd - cStart, numFound, found, PETSC_OWN_POINTER, cells, PETSC_OWN_POINTER));
9979566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t1));
9989cb35068SDave May   if (hash) {
99963a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "[DMLocatePoints_Plex] terminating_query_type : %" PetscInt_FMT " [outside domain] : %" PetscInt_FMT " [inside initial cell] : %" PetscInt_FMT " [hash]\n", terminating_query_type[0], terminating_query_type[1], terminating_query_type[2]));
10009cb35068SDave May   } else {
100163a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(dm, "[DMLocatePoints_Plex] terminating_query_type : %" PetscInt_FMT " [outside domain] : %" PetscInt_FMT " [inside initial cell] : %" PetscInt_FMT " [brute-force]\n", terminating_query_type[0], terminating_query_type[1], terminating_query_type[2]));
10029cb35068SDave May   }
100363a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(dm, "[DMLocatePoints_Plex] npoints %" PetscInt_FMT " : time(rank0) %1.2e (sec): points/sec %1.4e\n", numPoints, t1 - t0, (double)((double)numPoints / (t1 - t0))));
10049566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocatePoints, 0, 0, 0, 0));
10053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1006ccd2543fSMatthew G Knepley }
1007ccd2543fSMatthew G Knepley 
1008741bfc07SMatthew G. Knepley /*@C
1009741bfc07SMatthew G. Knepley   DMPlexComputeProjection2Dto1D - Rewrite coordinates to be the 1D projection of the 2D coordinates
1010741bfc07SMatthew G. Knepley 
101120f4b53cSBarry Smith   Not Collective
1012741bfc07SMatthew G. Knepley 
10136b867d5aSJose E. Roman   Input/Output Parameter:
10146b867d5aSJose E. Roman . coords - The coordinates of a segment, on output the new y-coordinate, and 0 for x
1015741bfc07SMatthew G. Knepley 
10166b867d5aSJose E. Roman   Output Parameter:
10176b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
1018741bfc07SMatthew G. Knepley 
1019741bfc07SMatthew G. Knepley   Level: developer
1020741bfc07SMatthew G. Knepley 
10212fe279fdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeProjection3Dto1D()`, `DMPlexComputeProjection3Dto2D()`
1022741bfc07SMatthew G. Knepley @*/
1023d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeProjection2Dto1D(PetscScalar coords[], PetscReal R[])
1024d71ae5a4SJacob Faibussowitsch {
102517fe8556SMatthew G. Knepley   const PetscReal x = PetscRealPart(coords[2] - coords[0]);
102617fe8556SMatthew G. Knepley   const PetscReal y = PetscRealPart(coords[3] - coords[1]);
10278b49ba18SBarry Smith   const PetscReal r = PetscSqrtReal(x * x + y * y), c = x / r, s = y / r;
102817fe8556SMatthew G. Knepley 
102917fe8556SMatthew G. Knepley   PetscFunctionBegin;
10309371c9d4SSatish Balay   R[0]      = c;
10319371c9d4SSatish Balay   R[1]      = -s;
10329371c9d4SSatish Balay   R[2]      = s;
10339371c9d4SSatish Balay   R[3]      = c;
103417fe8556SMatthew G. Knepley   coords[0] = 0.0;
10357f07f362SMatthew G. Knepley   coords[1] = r;
10363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103717fe8556SMatthew G. Knepley }
103817fe8556SMatthew G. Knepley 
1039741bfc07SMatthew G. Knepley /*@C
1040741bfc07SMatthew G. Knepley   DMPlexComputeProjection3Dto1D - Rewrite coordinates to be the 1D projection of the 3D coordinates
104128dbe442SToby Isaac 
104220f4b53cSBarry Smith   Not Collective
104328dbe442SToby Isaac 
10446b867d5aSJose E. Roman   Input/Output Parameter:
10456b867d5aSJose E. Roman . coords - The coordinates of a segment; on output, the new y-coordinate, and 0 for x and z
1046741bfc07SMatthew G. Knepley 
10476b867d5aSJose E. Roman   Output Parameter:
10486b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
1049741bfc07SMatthew G. Knepley 
105020f4b53cSBarry Smith   Note:
105120f4b53cSBarry Smith   This uses the basis completion described by Frisvad in http://www.imm.dtu.dk/~jerf/papers/abstracts/onb.html, DOI:10.1080/2165347X.2012.689606
1052741bfc07SMatthew G. Knepley 
1053741bfc07SMatthew G. Knepley   Level: developer
1054741bfc07SMatthew G. Knepley 
10552fe279fdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto2D()`
1056741bfc07SMatthew G. Knepley @*/
1057d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeProjection3Dto1D(PetscScalar coords[], PetscReal R[])
1058d71ae5a4SJacob Faibussowitsch {
105928dbe442SToby Isaac   PetscReal x    = PetscRealPart(coords[3] - coords[0]);
106028dbe442SToby Isaac   PetscReal y    = PetscRealPart(coords[4] - coords[1]);
106128dbe442SToby Isaac   PetscReal z    = PetscRealPart(coords[5] - coords[2]);
106228dbe442SToby Isaac   PetscReal r    = PetscSqrtReal(x * x + y * y + z * z);
106328dbe442SToby Isaac   PetscReal rinv = 1. / r;
106428dbe442SToby Isaac   PetscFunctionBegin;
106528dbe442SToby Isaac 
10669371c9d4SSatish Balay   x *= rinv;
10679371c9d4SSatish Balay   y *= rinv;
10689371c9d4SSatish Balay   z *= rinv;
106928dbe442SToby Isaac   if (x > 0.) {
107028dbe442SToby Isaac     PetscReal inv1pX = 1. / (1. + x);
107128dbe442SToby Isaac 
10729371c9d4SSatish Balay     R[0] = x;
10739371c9d4SSatish Balay     R[1] = -y;
10749371c9d4SSatish Balay     R[2] = -z;
10759371c9d4SSatish Balay     R[3] = y;
10769371c9d4SSatish Balay     R[4] = 1. - y * y * inv1pX;
10779371c9d4SSatish Balay     R[5] = -y * z * inv1pX;
10789371c9d4SSatish Balay     R[6] = z;
10799371c9d4SSatish Balay     R[7] = -y * z * inv1pX;
10809371c9d4SSatish Balay     R[8] = 1. - z * z * inv1pX;
10819371c9d4SSatish Balay   } else {
108228dbe442SToby Isaac     PetscReal inv1mX = 1. / (1. - x);
108328dbe442SToby Isaac 
10849371c9d4SSatish Balay     R[0] = x;
10859371c9d4SSatish Balay     R[1] = z;
10869371c9d4SSatish Balay     R[2] = y;
10879371c9d4SSatish Balay     R[3] = y;
10889371c9d4SSatish Balay     R[4] = -y * z * inv1mX;
10899371c9d4SSatish Balay     R[5] = 1. - y * y * inv1mX;
10909371c9d4SSatish Balay     R[6] = z;
10919371c9d4SSatish Balay     R[7] = 1. - z * z * inv1mX;
10929371c9d4SSatish Balay     R[8] = -y * z * inv1mX;
109328dbe442SToby Isaac   }
109428dbe442SToby Isaac   coords[0] = 0.0;
109528dbe442SToby Isaac   coords[1] = r;
10963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
109728dbe442SToby Isaac }
109828dbe442SToby Isaac 
1099741bfc07SMatthew G. Knepley /*@
1100c871b86eSJed Brown   DMPlexComputeProjection3Dto2D - Rewrite coordinates of 3 or more coplanar 3D points to a common 2D basis for the
1101c871b86eSJed Brown     plane.  The normal is defined by positive orientation of the first 3 points.
1102741bfc07SMatthew G. Knepley 
110320f4b53cSBarry Smith   Not Collective
1104741bfc07SMatthew G. Knepley 
1105741bfc07SMatthew G. Knepley   Input Parameter:
11066b867d5aSJose E. Roman . coordSize - Length of coordinate array (3x number of points); must be at least 9 (3 points)
1107741bfc07SMatthew G. Knepley 
11086b867d5aSJose E. Roman   Input/Output Parameter:
11096b867d5aSJose E. Roman . coords - The interlaced coordinates of each coplanar 3D point; on output the first
11106b867d5aSJose E. Roman            2*coordSize/3 entries contain interlaced 2D points, with the rest undefined
11116b867d5aSJose E. Roman 
11126b867d5aSJose E. Roman   Output Parameter:
11136b867d5aSJose E. Roman . R - 3x3 row-major rotation matrix whose columns are the tangent basis [t1, t2, n].  Multiplying by R^T transforms from original frame to tangent frame.
1114741bfc07SMatthew G. Knepley 
1115741bfc07SMatthew G. Knepley   Level: developer
1116741bfc07SMatthew G. Knepley 
11172fe279fdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto1D()`
1118741bfc07SMatthew G. Knepley @*/
1119d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeProjection3Dto2D(PetscInt coordSize, PetscScalar coords[], PetscReal R[])
1120d71ae5a4SJacob Faibussowitsch {
1121c871b86eSJed Brown   PetscReal      x1[3], x2[3], n[3], c[3], norm;
1122ccd2543fSMatthew G Knepley   const PetscInt dim = 3;
1123c871b86eSJed Brown   PetscInt       d, p;
1124ccd2543fSMatthew G Knepley 
1125ccd2543fSMatthew G Knepley   PetscFunctionBegin;
1126ccd2543fSMatthew G Knepley   /* 0) Calculate normal vector */
1127ccd2543fSMatthew G Knepley   for (d = 0; d < dim; ++d) {
11281ee9d5ecSMatthew G. Knepley     x1[d] = PetscRealPart(coords[1 * dim + d] - coords[0 * dim + d]);
11291ee9d5ecSMatthew G. Knepley     x2[d] = PetscRealPart(coords[2 * dim + d] - coords[0 * dim + d]);
1130ccd2543fSMatthew G Knepley   }
1131c871b86eSJed Brown   // n = x1 \otimes x2
1132ccd2543fSMatthew G Knepley   n[0] = x1[1] * x2[2] - x1[2] * x2[1];
1133ccd2543fSMatthew G Knepley   n[1] = x1[2] * x2[0] - x1[0] * x2[2];
1134ccd2543fSMatthew G Knepley   n[2] = x1[0] * x2[1] - x1[1] * x2[0];
11358b49ba18SBarry Smith   norm = PetscSqrtReal(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
1136c871b86eSJed Brown   for (d = 0; d < dim; d++) n[d] /= norm;
1137c871b86eSJed Brown   norm = PetscSqrtReal(x1[0] * x1[0] + x1[1] * x1[1] + x1[2] * x1[2]);
1138c871b86eSJed Brown   for (d = 0; d < dim; d++) x1[d] /= norm;
1139c871b86eSJed Brown   // x2 = n \otimes x1
1140c871b86eSJed Brown   x2[0] = n[1] * x1[2] - n[2] * x1[1];
1141c871b86eSJed Brown   x2[1] = n[2] * x1[0] - n[0] * x1[2];
1142c871b86eSJed Brown   x2[2] = n[0] * x1[1] - n[1] * x1[0];
1143c871b86eSJed Brown   for (d = 0; d < dim; d++) {
1144c871b86eSJed Brown     R[d * dim + 0] = x1[d];
1145c871b86eSJed Brown     R[d * dim + 1] = x2[d];
1146c871b86eSJed Brown     R[d * dim + 2] = n[d];
1147c871b86eSJed Brown     c[d]           = PetscRealPart(coords[0 * dim + d]);
114873868372SMatthew G. Knepley   }
1149c871b86eSJed Brown   for (p = 0; p < coordSize / dim; p++) {
1150c871b86eSJed Brown     PetscReal y[3];
1151c871b86eSJed Brown     for (d = 0; d < dim; d++) y[d] = PetscRealPart(coords[p * dim + d]) - c[d];
1152c871b86eSJed Brown     for (d = 0; d < 2; d++) coords[p * 2 + d] = R[0 * dim + d] * y[0] + R[1 * dim + d] * y[1] + R[2 * dim + d] * y[2];
11537f07f362SMatthew G. Knepley   }
11543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1155ccd2543fSMatthew G Knepley }
1156ccd2543fSMatthew G Knepley 
1157d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static inline void Volume_Triangle_Internal(PetscReal *vol, PetscReal coords[])
1158d71ae5a4SJacob Faibussowitsch {
1159834e62ceSMatthew G. Knepley   /* Signed volume is 1/2 the determinant
1160834e62ceSMatthew G. Knepley 
1161834e62ceSMatthew G. Knepley    |  1  1  1 |
1162834e62ceSMatthew G. Knepley    | x0 x1 x2 |
1163834e62ceSMatthew G. Knepley    | y0 y1 y2 |
1164834e62ceSMatthew G. Knepley 
1165834e62ceSMatthew G. Knepley      but if x0,y0 is the origin, we have
1166834e62ceSMatthew G. Knepley 
1167834e62ceSMatthew G. Knepley    | x1 x2 |
1168834e62ceSMatthew G. Knepley    | y1 y2 |
1169834e62ceSMatthew G. Knepley   */
1170834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[2] - coords[0], y1 = coords[3] - coords[1];
1171834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[4] - coords[0], y2 = coords[5] - coords[1];
1172834e62ceSMatthew G. Knepley   PetscReal       M[4], detM;
11739371c9d4SSatish Balay   M[0] = x1;
11749371c9d4SSatish Balay   M[1] = x2;
11759371c9d4SSatish Balay   M[2] = y1;
11769371c9d4SSatish Balay   M[3] = y2;
1177923591dfSMatthew G. Knepley   DMPlex_Det2D_Internal(&detM, M);
1178834e62ceSMatthew G. Knepley   *vol = 0.5 * detM;
11793bc0b13bSBarry Smith   (void)PetscLogFlops(5.0);
1180834e62ceSMatthew G. Knepley }
1181834e62ceSMatthew G. Knepley 
1182d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static inline void Volume_Tetrahedron_Internal(PetscReal *vol, PetscReal coords[])
1183d71ae5a4SJacob Faibussowitsch {
1184834e62ceSMatthew G. Knepley   /* Signed volume is 1/6th of the determinant
1185834e62ceSMatthew G. Knepley 
1186834e62ceSMatthew G. Knepley    |  1  1  1  1 |
1187834e62ceSMatthew G. Knepley    | x0 x1 x2 x3 |
1188834e62ceSMatthew G. Knepley    | y0 y1 y2 y3 |
1189834e62ceSMatthew G. Knepley    | z0 z1 z2 z3 |
1190834e62ceSMatthew G. Knepley 
1191834e62ceSMatthew G. Knepley      but if x0,y0,z0 is the origin, we have
1192834e62ceSMatthew G. Knepley 
1193834e62ceSMatthew G. Knepley    | x1 x2 x3 |
1194834e62ceSMatthew G. Knepley    | y1 y2 y3 |
1195834e62ceSMatthew G. Knepley    | z1 z2 z3 |
1196834e62ceSMatthew G. Knepley   */
1197834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[3] - coords[0], y1 = coords[4] - coords[1], z1 = coords[5] - coords[2];
1198834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[6] - coords[0], y2 = coords[7] - coords[1], z2 = coords[8] - coords[2];
1199834e62ceSMatthew G. Knepley   const PetscReal x3 = coords[9] - coords[0], y3 = coords[10] - coords[1], z3 = coords[11] - coords[2];
12000a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1. / (PetscReal)6.);
1201834e62ceSMatthew G. Knepley   PetscReal       M[9], detM;
12029371c9d4SSatish Balay   M[0] = x1;
12039371c9d4SSatish Balay   M[1] = x2;
12049371c9d4SSatish Balay   M[2] = x3;
12059371c9d4SSatish Balay   M[3] = y1;
12069371c9d4SSatish Balay   M[4] = y2;
12079371c9d4SSatish Balay   M[5] = y3;
12089371c9d4SSatish Balay   M[6] = z1;
12099371c9d4SSatish Balay   M[7] = z2;
12109371c9d4SSatish Balay   M[8] = z3;
1211923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(&detM, M);
12120a3da2c2SToby Isaac   *vol = -onesixth * detM;
12133bc0b13bSBarry Smith   (void)PetscLogFlops(10.0);
1214834e62ceSMatthew G. Knepley }
1215834e62ceSMatthew G. Knepley 
1216d71ae5a4SJacob Faibussowitsch static inline void Volume_Tetrahedron_Origin_Internal(PetscReal *vol, PetscReal coords[])
1217d71ae5a4SJacob Faibussowitsch {
12180a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1. / (PetscReal)6.);
1219923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(vol, coords);
12200a3da2c2SToby Isaac   *vol *= -onesixth;
12210ec8681fSMatthew G. Knepley }
12220ec8681fSMatthew G. Knepley 
1223d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputePointGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1224d71ae5a4SJacob Faibussowitsch {
1225cb92db44SToby Isaac   PetscSection       coordSection;
1226cb92db44SToby Isaac   Vec                coordinates;
1227cb92db44SToby Isaac   const PetscScalar *coords;
1228cb92db44SToby Isaac   PetscInt           dim, d, off;
1229cb92db44SToby Isaac 
1230cb92db44SToby Isaac   PetscFunctionBegin;
12319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
12329566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
12339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(coordSection, e, &dim));
12343ba16761SJacob Faibussowitsch   if (!dim) PetscFunctionReturn(PETSC_SUCCESS);
12359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(coordSection, e, &off));
12369566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
12379371c9d4SSatish Balay   if (v0) {
12389371c9d4SSatish Balay     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[off + d]);
12399371c9d4SSatish Balay   }
12409566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
1241cb92db44SToby Isaac   *detJ = 1.;
1242cb92db44SToby Isaac   if (J) {
1243cb92db44SToby Isaac     for (d = 0; d < dim * dim; d++) J[d] = 0.;
1244cb92db44SToby Isaac     for (d = 0; d < dim; d++) J[d * dim + d] = 1.;
1245cb92db44SToby Isaac     if (invJ) {
1246cb92db44SToby Isaac       for (d = 0; d < dim * dim; d++) invJ[d] = 0.;
1247cb92db44SToby Isaac       for (d = 0; d < dim; d++) invJ[d * dim + d] = 1.;
1248cb92db44SToby Isaac     }
1249cb92db44SToby Isaac   }
12503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1251cb92db44SToby Isaac }
1252cb92db44SToby Isaac 
12536858538eSMatthew G. Knepley /*@C
12546858538eSMatthew G. Knepley   DMPlexGetCellCoordinates - Get coordinates for a cell, taking into account periodicity
12556858538eSMatthew G. Knepley 
125620f4b53cSBarry Smith   Not Collective
12576858538eSMatthew G. Knepley 
12586858538eSMatthew G. Knepley   Input Parameters:
125920f4b53cSBarry Smith + dm   - The `DMPLEX`
12606858538eSMatthew G. Knepley - cell - The cell number
12616858538eSMatthew G. Knepley 
12626858538eSMatthew G. Knepley   Output Parameters:
12636858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
12646858538eSMatthew G. Knepley . Nc     - The number of coordinates
12656858538eSMatthew G. Knepley . array  - The coordinate array
12666858538eSMatthew G. Knepley - coords - The cell coordinates
12676858538eSMatthew G. Knepley 
12686858538eSMatthew G. Knepley   Level: developer
12696858538eSMatthew G. Knepley 
127020f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexRestoreCellCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCellCoordinatesLocal()`
12716858538eSMatthew G. Knepley @*/
1272d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
1273d71ae5a4SJacob Faibussowitsch {
12746858538eSMatthew G. Knepley   DM                 cdm;
12756858538eSMatthew G. Knepley   Vec                coordinates;
12766858538eSMatthew G. Knepley   PetscSection       cs;
12776858538eSMatthew G. Knepley   const PetscScalar *ccoords;
12786858538eSMatthew G. Knepley   PetscInt           pStart, pEnd;
12796858538eSMatthew G. Knepley 
12806858538eSMatthew G. Knepley   PetscFunctionBeginHot;
12816858538eSMatthew G. Knepley   *isDG   = PETSC_FALSE;
12826858538eSMatthew G. Knepley   *Nc     = 0;
12836858538eSMatthew G. Knepley   *array  = NULL;
12846858538eSMatthew G. Knepley   *coords = NULL;
12856858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12866858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateSection(dm, &cs));
12876858538eSMatthew G. Knepley   if (!cs) goto cg;
12886858538eSMatthew G. Knepley   /* Check that the cell exists in the cellwise section */
12896858538eSMatthew G. Knepley   PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd));
12906858538eSMatthew G. Knepley   if (cell < pStart || cell >= pEnd) goto cg;
12916858538eSMatthew G. Knepley   /* Check for cellwise coordinates for this cell */
12926858538eSMatthew G. Knepley   PetscCall(PetscSectionGetDof(cs, cell, Nc));
12936858538eSMatthew G. Knepley   if (!*Nc) goto cg;
12946858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12956858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocalNoncollective(dm, &coordinates));
12966858538eSMatthew G. Knepley   if (!coordinates) goto cg;
12976858538eSMatthew G. Knepley   /* Get cellwise coordinates */
12986858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12996858538eSMatthew G. Knepley   PetscCall(VecGetArrayRead(coordinates, array));
13006858538eSMatthew G. Knepley   PetscCall(DMPlexPointLocalRead(cdm, cell, *array, &ccoords));
13016858538eSMatthew G. Knepley   PetscCall(DMGetWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
13026858538eSMatthew G. Knepley   PetscCall(PetscArraycpy(*coords, ccoords, *Nc));
13036858538eSMatthew G. Knepley   PetscCall(VecRestoreArrayRead(coordinates, array));
13046858538eSMatthew G. Knepley   *isDG = PETSC_TRUE;
13053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13066858538eSMatthew G. Knepley cg:
13076858538eSMatthew G. Knepley   /* Use continuous coordinates */
13086858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
13096858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &cs));
13106858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
13116858538eSMatthew G. Knepley   PetscCall(DMPlexVecGetClosure(cdm, cs, coordinates, cell, Nc, coords));
13123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13136858538eSMatthew G. Knepley }
13146858538eSMatthew G. Knepley 
13156858538eSMatthew G. Knepley /*@C
13166858538eSMatthew G. Knepley   DMPlexRestoreCellCoordinates - Get coordinates for a cell, taking into account periodicity
13176858538eSMatthew G. Knepley 
131820f4b53cSBarry Smith   Not Collective
13196858538eSMatthew G. Knepley 
13206858538eSMatthew G. Knepley   Input Parameters:
132120f4b53cSBarry Smith + dm   - The `DMPLEX`
13226858538eSMatthew G. Knepley - cell - The cell number
13236858538eSMatthew G. Knepley 
13246858538eSMatthew G. Knepley   Output Parameters:
13256858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
13266858538eSMatthew G. Knepley . Nc     - The number of coordinates
13276858538eSMatthew G. Knepley . array  - The coordinate array
13286858538eSMatthew G. Knepley - coords - The cell coordinates
13296858538eSMatthew G. Knepley 
13306858538eSMatthew G. Knepley   Level: developer
13316858538eSMatthew G. Knepley 
133220f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexGetCellCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCellCoordinatesLocal()`
13336858538eSMatthew G. Knepley @*/
1334d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
1335d71ae5a4SJacob Faibussowitsch {
13366858538eSMatthew G. Knepley   DM           cdm;
13376858538eSMatthew G. Knepley   PetscSection cs;
13386858538eSMatthew G. Knepley   Vec          coordinates;
13396858538eSMatthew G. Knepley 
13406858538eSMatthew G. Knepley   PetscFunctionBeginHot;
13416858538eSMatthew G. Knepley   if (*isDG) {
13426858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
13436858538eSMatthew G. Knepley     PetscCall(DMRestoreWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
13446858538eSMatthew G. Knepley   } else {
13456858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
13466858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &cs));
13476858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
13486858538eSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(cdm, cs, coordinates, cell, Nc, (PetscScalar **)coords));
13496858538eSMatthew G. Knepley   }
13503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13516858538eSMatthew G. Knepley }
13526858538eSMatthew G. Knepley 
1353d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeLineGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1354d71ae5a4SJacob Faibussowitsch {
13556858538eSMatthew G. Knepley   const PetscScalar *array;
1356a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
13576858538eSMatthew G. Knepley   PetscInt           numCoords, d;
13586858538eSMatthew G. Knepley   PetscBool          isDG;
135917fe8556SMatthew G. Knepley 
136017fe8556SMatthew G. Knepley   PetscFunctionBegin;
13616858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
136208401ef6SPierre Jolivet   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
13637f07f362SMatthew G. Knepley   *detJ = 0.0;
136428dbe442SToby Isaac   if (numCoords == 6) {
136528dbe442SToby Isaac     const PetscInt dim = 3;
136628dbe442SToby Isaac     PetscReal      R[9], J0;
136728dbe442SToby Isaac 
13689371c9d4SSatish Balay     if (v0) {
13699371c9d4SSatish Balay       for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
13709371c9d4SSatish Balay     }
13719566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto1D(coords, R));
137228dbe442SToby Isaac     if (J) {
137328dbe442SToby Isaac       J0   = 0.5 * PetscRealPart(coords[1]);
13749371c9d4SSatish Balay       J[0] = R[0] * J0;
13759371c9d4SSatish Balay       J[1] = R[1];
13769371c9d4SSatish Balay       J[2] = R[2];
13779371c9d4SSatish Balay       J[3] = R[3] * J0;
13789371c9d4SSatish Balay       J[4] = R[4];
13799371c9d4SSatish Balay       J[5] = R[5];
13809371c9d4SSatish Balay       J[6] = R[6] * J0;
13819371c9d4SSatish Balay       J[7] = R[7];
13829371c9d4SSatish Balay       J[8] = R[8];
138328dbe442SToby Isaac       DMPlex_Det3D_Internal(detJ, J);
1384*2b6f951bSStefano Zampini       if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
1385adac9986SMatthew G. Knepley     }
138628dbe442SToby Isaac   } else if (numCoords == 4) {
13877f07f362SMatthew G. Knepley     const PetscInt dim = 2;
13887f07f362SMatthew G. Knepley     PetscReal      R[4], J0;
13897f07f362SMatthew G. Knepley 
13909371c9d4SSatish Balay     if (v0) {
13919371c9d4SSatish Balay       for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
13929371c9d4SSatish Balay     }
13939566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection2Dto1D(coords, R));
139417fe8556SMatthew G. Knepley     if (J) {
13957f07f362SMatthew G. Knepley       J0   = 0.5 * PetscRealPart(coords[1]);
13969371c9d4SSatish Balay       J[0] = R[0] * J0;
13979371c9d4SSatish Balay       J[1] = R[1];
13989371c9d4SSatish Balay       J[2] = R[2] * J0;
13999371c9d4SSatish Balay       J[3] = R[3];
1400923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1401ad540459SPierre Jolivet       if (invJ) DMPlex_Invert2D_Internal(invJ, J, *detJ);
1402adac9986SMatthew G. Knepley     }
14037f07f362SMatthew G. Knepley   } else if (numCoords == 2) {
14047f07f362SMatthew G. Knepley     const PetscInt dim = 1;
14057f07f362SMatthew G. Knepley 
14069371c9d4SSatish Balay     if (v0) {
14079371c9d4SSatish Balay       for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
14089371c9d4SSatish Balay     }
14097f07f362SMatthew G. Knepley     if (J) {
14107f07f362SMatthew G. Knepley       J[0]  = 0.5 * (PetscRealPart(coords[1]) - PetscRealPart(coords[0]));
141117fe8556SMatthew G. Knepley       *detJ = J[0];
14129566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(2.0));
14139371c9d4SSatish Balay       if (invJ) {
14149371c9d4SSatish Balay         invJ[0] = 1.0 / J[0];
14159371c9d4SSatish Balay         PetscCall(PetscLogFlops(1.0));
14169371c9d4SSatish Balay       }
1417adac9986SMatthew G. Knepley     }
14186858538eSMatthew G. Knepley   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for segment %" PetscInt_FMT " is %" PetscInt_FMT " != 2 or 4 or 6", e, numCoords);
14196858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
14203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
142117fe8556SMatthew G. Knepley }
142217fe8556SMatthew G. Knepley 
1423d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeTriangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1424d71ae5a4SJacob Faibussowitsch {
14256858538eSMatthew G. Knepley   const PetscScalar *array;
1426a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
14276858538eSMatthew G. Knepley   PetscInt           numCoords, d;
14286858538eSMatthew G. Knepley   PetscBool          isDG;
1429ccd2543fSMatthew G Knepley 
1430ccd2543fSMatthew G Knepley   PetscFunctionBegin;
14316858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
14326858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
14337f07f362SMatthew G. Knepley   *detJ = 0.0;
1434ccd2543fSMatthew G Knepley   if (numCoords == 9) {
14357f07f362SMatthew G. Knepley     const PetscInt dim = 3;
14367f07f362SMatthew G. Knepley     PetscReal      R[9], J0[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
14377f07f362SMatthew G. Knepley 
14389371c9d4SSatish Balay     if (v0) {
14399371c9d4SSatish Balay       for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
14409371c9d4SSatish Balay     }
14419566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
14427f07f362SMatthew G. Knepley     if (J) {
1443b7ad821dSMatthew G. Knepley       const PetscInt pdim = 2;
1444b7ad821dSMatthew G. Knepley 
1445b7ad821dSMatthew G. Knepley       for (d = 0; d < pdim; d++) {
1446ad540459SPierre Jolivet         for (PetscInt f = 0; f < pdim; f++) J0[d * dim + f] = 0.5 * (PetscRealPart(coords[(f + 1) * pdim + d]) - PetscRealPart(coords[0 * pdim + d]));
14477f07f362SMatthew G. Knepley       }
14489566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1449923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J0);
14507f07f362SMatthew G. Knepley       for (d = 0; d < dim; d++) {
14516858538eSMatthew G. Knepley         for (PetscInt f = 0; f < dim; f++) {
14527f07f362SMatthew G. Knepley           J[d * dim + f] = 0.0;
1453ad540459SPierre Jolivet           for (PetscInt g = 0; g < dim; g++) J[d * dim + f] += R[d * dim + g] * J0[g * dim + f];
14547f07f362SMatthew G. Knepley         }
14557f07f362SMatthew G. Knepley       }
14569566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
14577f07f362SMatthew G. Knepley     }
1458ad540459SPierre Jolivet     if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
14597f07f362SMatthew G. Knepley   } else if (numCoords == 6) {
14607f07f362SMatthew G. Knepley     const PetscInt dim = 2;
14617f07f362SMatthew G. Knepley 
14629371c9d4SSatish Balay     if (v0) {
14639371c9d4SSatish Balay       for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
14649371c9d4SSatish Balay     }
1465ccd2543fSMatthew G Knepley     if (J) {
1466ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
1467ad540459SPierre Jolivet         for (PetscInt f = 0; f < dim; f++) J[d * dim + f] = 0.5 * (PetscRealPart(coords[(f + 1) * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1468ccd2543fSMatthew G Knepley       }
14699566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1470923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1471ccd2543fSMatthew G Knepley     }
1472ad540459SPierre Jolivet     if (invJ) DMPlex_Invert2D_Internal(invJ, J, *detJ);
147363a3b9bcSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this triangle is %" PetscInt_FMT " != 6 or 9", numCoords);
14746858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
14753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1476ccd2543fSMatthew G Knepley }
1477ccd2543fSMatthew G Knepley 
1478d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeRectangleGeometry_Internal(DM dm, PetscInt e, PetscBool isTensor, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1479d71ae5a4SJacob Faibussowitsch {
14806858538eSMatthew G. Knepley   const PetscScalar *array;
1481a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
14826858538eSMatthew G. Knepley   PetscInt           numCoords, d;
14836858538eSMatthew G. Knepley   PetscBool          isDG;
1484ccd2543fSMatthew G Knepley 
1485ccd2543fSMatthew G Knepley   PetscFunctionBegin;
14866858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
14876858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1488dfccc68fSToby Isaac   if (!Nq) {
1489412e9a14SMatthew G. Knepley     PetscInt vorder[4] = {0, 1, 2, 3};
1490412e9a14SMatthew G. Knepley 
14919371c9d4SSatish Balay     if (isTensor) {
14929371c9d4SSatish Balay       vorder[2] = 3;
14939371c9d4SSatish Balay       vorder[3] = 2;
14949371c9d4SSatish Balay     }
14957f07f362SMatthew G. Knepley     *detJ = 0.0;
149699dec3a6SMatthew G. Knepley     if (numCoords == 12) {
149799dec3a6SMatthew G. Knepley       const PetscInt dim = 3;
149899dec3a6SMatthew G. Knepley       PetscReal      R[9], J0[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
149999dec3a6SMatthew G. Knepley 
15009371c9d4SSatish Balay       if (v) {
15019371c9d4SSatish Balay         for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);
15029371c9d4SSatish Balay       }
15039566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
150499dec3a6SMatthew G. Knepley       if (J) {
150599dec3a6SMatthew G. Knepley         const PetscInt pdim = 2;
150699dec3a6SMatthew G. Knepley 
150799dec3a6SMatthew G. Knepley         for (d = 0; d < pdim; d++) {
1508412e9a14SMatthew G. Knepley           J0[d * dim + 0] = 0.5 * (PetscRealPart(coords[vorder[1] * pdim + d]) - PetscRealPart(coords[vorder[0] * pdim + d]));
1509412e9a14SMatthew G. Knepley           J0[d * dim + 1] = 0.5 * (PetscRealPart(coords[vorder[2] * pdim + d]) - PetscRealPart(coords[vorder[1] * pdim + d]));
151099dec3a6SMatthew G. Knepley         }
15119566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1512923591dfSMatthew G. Knepley         DMPlex_Det3D_Internal(detJ, J0);
151399dec3a6SMatthew G. Knepley         for (d = 0; d < dim; d++) {
15146858538eSMatthew G. Knepley           for (PetscInt f = 0; f < dim; f++) {
151599dec3a6SMatthew G. Knepley             J[d * dim + f] = 0.0;
1516ad540459SPierre Jolivet             for (PetscInt g = 0; g < dim; g++) J[d * dim + f] += R[d * dim + g] * J0[g * dim + f];
151799dec3a6SMatthew G. Knepley           }
151899dec3a6SMatthew G. Knepley         }
15199566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(18.0));
152099dec3a6SMatthew G. Knepley       }
1521ad540459SPierre Jolivet       if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
152271f58de1SToby Isaac     } else if (numCoords == 8) {
152399dec3a6SMatthew G. Knepley       const PetscInt dim = 2;
152499dec3a6SMatthew G. Knepley 
15259371c9d4SSatish Balay       if (v) {
15269371c9d4SSatish Balay         for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);
15279371c9d4SSatish Balay       }
1528ccd2543fSMatthew G Knepley       if (J) {
1529ccd2543fSMatthew G Knepley         for (d = 0; d < dim; d++) {
1530412e9a14SMatthew G. Knepley           J[d * dim + 0] = 0.5 * (PetscRealPart(coords[vorder[1] * dim + d]) - PetscRealPart(coords[vorder[0] * dim + d]));
1531412e9a14SMatthew G. Knepley           J[d * dim + 1] = 0.5 * (PetscRealPart(coords[vorder[3] * dim + d]) - PetscRealPart(coords[vorder[0] * dim + d]));
1532ccd2543fSMatthew G Knepley         }
15339566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1534923591dfSMatthew G. Knepley         DMPlex_Det2D_Internal(detJ, J);
1535ccd2543fSMatthew G Knepley       }
1536ad540459SPierre Jolivet       if (invJ) DMPlex_Invert2D_Internal(invJ, J, *detJ);
153763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1538dfccc68fSToby Isaac   } else {
1539dfccc68fSToby Isaac     const PetscInt Nv         = 4;
1540dfccc68fSToby Isaac     const PetscInt dimR       = 2;
1541412e9a14SMatthew G. Knepley     PetscInt       zToPlex[4] = {0, 1, 3, 2};
1542dfccc68fSToby Isaac     PetscReal      zOrder[12];
1543dfccc68fSToby Isaac     PetscReal      zCoeff[12];
1544dfccc68fSToby Isaac     PetscInt       i, j, k, l, dim;
1545dfccc68fSToby Isaac 
15469371c9d4SSatish Balay     if (isTensor) {
15479371c9d4SSatish Balay       zToPlex[2] = 2;
15489371c9d4SSatish Balay       zToPlex[3] = 3;
15499371c9d4SSatish Balay     }
1550dfccc68fSToby Isaac     if (numCoords == 12) {
1551dfccc68fSToby Isaac       dim = 3;
1552dfccc68fSToby Isaac     } else if (numCoords == 8) {
1553dfccc68fSToby Isaac       dim = 2;
155463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1555dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1556dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1557dfccc68fSToby Isaac 
1558ad540459SPierre Jolivet       for (j = 0; j < dim; j++) zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1559dfccc68fSToby Isaac     }
1560dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
15612df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: (1 \mp xi) (1 \mp eta):
15622df84da0SMatthew G. Knepley            \phi^0 = (1 - xi - eta + xi eta) --> 1      = 1/4 ( \phi^0 + \phi^1 + \phi^2 + \phi^3)
15632df84da0SMatthew G. Knepley            \phi^1 = (1 + xi - eta - xi eta) --> xi     = 1/4 (-\phi^0 + \phi^1 - \phi^2 + \phi^3)
15642df84da0SMatthew G. Knepley            \phi^2 = (1 - xi + eta - xi eta) --> eta    = 1/4 (-\phi^0 - \phi^1 + \phi^2 + \phi^3)
15652df84da0SMatthew G. Knepley            \phi^3 = (1 + xi + eta + xi eta) --> xi eta = 1/4 ( \phi^0 - \phi^1 - \phi^2 + \phi^3)
15662df84da0SMatthew G. Knepley       */
1567dfccc68fSToby Isaac       zCoeff[dim * 0 + j] = 0.25 * (zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1568dfccc68fSToby Isaac       zCoeff[dim * 1 + j] = 0.25 * (-zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1569dfccc68fSToby Isaac       zCoeff[dim * 2 + j] = 0.25 * (-zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1570dfccc68fSToby Isaac       zCoeff[dim * 3 + j] = 0.25 * (zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1571dfccc68fSToby Isaac     }
1572dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1573dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1];
1574dfccc68fSToby Isaac 
1575dfccc68fSToby Isaac       if (v) {
1576dfccc68fSToby Isaac         PetscReal extPoint[4];
1577dfccc68fSToby Isaac 
1578dfccc68fSToby Isaac         extPoint[0] = 1.;
1579dfccc68fSToby Isaac         extPoint[1] = xi;
1580dfccc68fSToby Isaac         extPoint[2] = eta;
1581dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1582dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1583dfccc68fSToby Isaac           PetscReal val = 0.;
1584dfccc68fSToby Isaac 
1585ad540459SPierre Jolivet           for (k = 0; k < Nv; k++) val += extPoint[k] * zCoeff[dim * k + j];
1586dfccc68fSToby Isaac           v[i * dim + j] = val;
1587dfccc68fSToby Isaac         }
1588dfccc68fSToby Isaac       }
1589dfccc68fSToby Isaac       if (J) {
1590dfccc68fSToby Isaac         PetscReal extJ[8];
1591dfccc68fSToby Isaac 
1592dfccc68fSToby Isaac         extJ[0] = 0.;
1593dfccc68fSToby Isaac         extJ[1] = 0.;
1594dfccc68fSToby Isaac         extJ[2] = 1.;
1595dfccc68fSToby Isaac         extJ[3] = 0.;
1596dfccc68fSToby Isaac         extJ[4] = 0.;
1597dfccc68fSToby Isaac         extJ[5] = 1.;
1598dfccc68fSToby Isaac         extJ[6] = eta;
1599dfccc68fSToby Isaac         extJ[7] = xi;
1600dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1601dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1602dfccc68fSToby Isaac             PetscReal val = 0.;
1603dfccc68fSToby Isaac 
1604ad540459SPierre Jolivet             for (l = 0; l < Nv; l++) val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1605dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1606dfccc68fSToby Isaac           }
1607dfccc68fSToby Isaac         }
1608dfccc68fSToby Isaac         if (dim == 3) { /* put the cross product in the third component of the Jacobian */
1609dfccc68fSToby Isaac           PetscReal  x, y, z;
1610dfccc68fSToby Isaac           PetscReal *iJ = &J[i * dim * dim];
1611dfccc68fSToby Isaac           PetscReal  norm;
1612dfccc68fSToby Isaac 
1613dfccc68fSToby Isaac           x     = iJ[1 * dim + 0] * iJ[2 * dim + 1] - iJ[1 * dim + 1] * iJ[2 * dim + 0];
1614dfccc68fSToby Isaac           y     = iJ[0 * dim + 1] * iJ[2 * dim + 0] - iJ[0 * dim + 0] * iJ[2 * dim + 1];
1615dfccc68fSToby Isaac           z     = iJ[0 * dim + 0] * iJ[1 * dim + 1] - iJ[0 * dim + 1] * iJ[1 * dim + 0];
1616dfccc68fSToby Isaac           norm  = PetscSqrtReal(x * x + y * y + z * z);
1617dfccc68fSToby Isaac           iJ[2] = x / norm;
1618dfccc68fSToby Isaac           iJ[5] = y / norm;
1619dfccc68fSToby Isaac           iJ[8] = z / norm;
1620dfccc68fSToby Isaac           DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1621ad540459SPierre Jolivet           if (invJ) DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);
1622dfccc68fSToby Isaac         } else {
1623dfccc68fSToby Isaac           DMPlex_Det2D_Internal(&detJ[i], &J[i * dim * dim]);
1624ad540459SPierre Jolivet           if (invJ) DMPlex_Invert2D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);
1625dfccc68fSToby Isaac         }
1626dfccc68fSToby Isaac       }
1627dfccc68fSToby Isaac     }
1628dfccc68fSToby Isaac   }
16296858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1631ccd2543fSMatthew G Knepley }
1632ccd2543fSMatthew G Knepley 
1633d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeTetrahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1634d71ae5a4SJacob Faibussowitsch {
16356858538eSMatthew G. Knepley   const PetscScalar *array;
1636a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1637ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
16386858538eSMatthew G. Knepley   PetscInt           numCoords, d;
16396858538eSMatthew G. Knepley   PetscBool          isDG;
1640ccd2543fSMatthew G Knepley 
1641ccd2543fSMatthew G Knepley   PetscFunctionBegin;
16426858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16436858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
16447f07f362SMatthew G. Knepley   *detJ = 0.0;
16459371c9d4SSatish Balay   if (v0) {
16469371c9d4SSatish Balay     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
16479371c9d4SSatish Balay   }
1648ccd2543fSMatthew G Knepley   if (J) {
1649ccd2543fSMatthew G Knepley     for (d = 0; d < dim; d++) {
1650f0df753eSMatthew G. Knepley       /* I orient with outward face normals */
1651f0df753eSMatthew G. Knepley       J[d * dim + 0] = 0.5 * (PetscRealPart(coords[2 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1652f0df753eSMatthew G. Knepley       J[d * dim + 1] = 0.5 * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1653f0df753eSMatthew G. Knepley       J[d * dim + 2] = 0.5 * (PetscRealPart(coords[3 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1654ccd2543fSMatthew G Knepley     }
16559566063dSJacob Faibussowitsch     PetscCall(PetscLogFlops(18.0));
1656923591dfSMatthew G. Knepley     DMPlex_Det3D_Internal(detJ, J);
1657ccd2543fSMatthew G Knepley   }
1658ad540459SPierre Jolivet   if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
16596858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1661ccd2543fSMatthew G Knepley }
1662ccd2543fSMatthew G Knepley 
1663d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeHexahedronGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1664d71ae5a4SJacob Faibussowitsch {
16656858538eSMatthew G. Knepley   const PetscScalar *array;
1666a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1667ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
16686858538eSMatthew G. Knepley   PetscInt           numCoords, d;
16696858538eSMatthew G. Knepley   PetscBool          isDG;
1670ccd2543fSMatthew G Knepley 
1671ccd2543fSMatthew G Knepley   PetscFunctionBegin;
16726858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16736858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1674dfccc68fSToby Isaac   if (!Nq) {
16757f07f362SMatthew G. Knepley     *detJ = 0.0;
16769371c9d4SSatish Balay     if (v) {
16779371c9d4SSatish Balay       for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);
16789371c9d4SSatish Balay     }
1679ccd2543fSMatthew G Knepley     if (J) {
1680ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
1681f0df753eSMatthew G. Knepley         J[d * dim + 0] = 0.5 * (PetscRealPart(coords[3 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1682f0df753eSMatthew G. Knepley         J[d * dim + 1] = 0.5 * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1683f0df753eSMatthew G. Knepley         J[d * dim + 2] = 0.5 * (PetscRealPart(coords[4 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
1684ccd2543fSMatthew G Knepley       }
16859566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
1686923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
1687ccd2543fSMatthew G Knepley     }
1688ad540459SPierre Jolivet     if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
1689dfccc68fSToby Isaac   } else {
1690dfccc68fSToby Isaac     const PetscInt Nv         = 8;
1691dfccc68fSToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
1692dfccc68fSToby Isaac     const PetscInt dim        = 3;
1693dfccc68fSToby Isaac     const PetscInt dimR       = 3;
1694dfccc68fSToby Isaac     PetscReal      zOrder[24];
1695dfccc68fSToby Isaac     PetscReal      zCoeff[24];
1696dfccc68fSToby Isaac     PetscInt       i, j, k, l;
1697dfccc68fSToby Isaac 
1698dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1699dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1700dfccc68fSToby Isaac 
1701ad540459SPierre Jolivet       for (j = 0; j < dim; j++) zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1702dfccc68fSToby Isaac     }
1703dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
1704dfccc68fSToby Isaac       zCoeff[dim * 0 + j] = 0.125 * (zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j] + zOrder[dim * 4 + j] + zOrder[dim * 5 + j] + zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1705dfccc68fSToby Isaac       zCoeff[dim * 1 + j] = 0.125 * (-zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j] - zOrder[dim * 4 + j] + zOrder[dim * 5 + j] - zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1706dfccc68fSToby Isaac       zCoeff[dim * 2 + j] = 0.125 * (-zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j] - zOrder[dim * 4 + j] - zOrder[dim * 5 + j] + zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1707dfccc68fSToby Isaac       zCoeff[dim * 3 + j] = 0.125 * (zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j] + zOrder[dim * 4 + j] - zOrder[dim * 5 + j] - zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1708dfccc68fSToby Isaac       zCoeff[dim * 4 + j] = 0.125 * (-zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] - zOrder[dim * 3 + j] + zOrder[dim * 4 + j] + zOrder[dim * 5 + j] + zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1709dfccc68fSToby Isaac       zCoeff[dim * 5 + j] = 0.125 * (+zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] - zOrder[dim * 3 + j] - zOrder[dim * 4 + j] + zOrder[dim * 5 + j] - zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1710dfccc68fSToby Isaac       zCoeff[dim * 6 + j] = 0.125 * (+zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] - zOrder[dim * 3 + j] - zOrder[dim * 4 + j] - zOrder[dim * 5 + j] + zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1711dfccc68fSToby Isaac       zCoeff[dim * 7 + j] = 0.125 * (-zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] - zOrder[dim * 3 + j] + zOrder[dim * 4 + j] - zOrder[dim * 5 + j] - zOrder[dim * 6 + j] + zOrder[dim * 7 + j]);
1712dfccc68fSToby Isaac     }
1713dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1714dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], theta = points[dimR * i + 2];
1715dfccc68fSToby Isaac 
1716dfccc68fSToby Isaac       if (v) {
171791d2b7ceSToby Isaac         PetscReal extPoint[8];
1718dfccc68fSToby Isaac 
1719dfccc68fSToby Isaac         extPoint[0] = 1.;
1720dfccc68fSToby Isaac         extPoint[1] = xi;
1721dfccc68fSToby Isaac         extPoint[2] = eta;
1722dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1723dfccc68fSToby Isaac         extPoint[4] = theta;
1724dfccc68fSToby Isaac         extPoint[5] = theta * xi;
1725dfccc68fSToby Isaac         extPoint[6] = theta * eta;
1726dfccc68fSToby Isaac         extPoint[7] = theta * eta * xi;
1727dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1728dfccc68fSToby Isaac           PetscReal val = 0.;
1729dfccc68fSToby Isaac 
1730ad540459SPierre Jolivet           for (k = 0; k < Nv; k++) val += extPoint[k] * zCoeff[dim * k + j];
1731dfccc68fSToby Isaac           v[i * dim + j] = val;
1732dfccc68fSToby Isaac         }
1733dfccc68fSToby Isaac       }
1734dfccc68fSToby Isaac       if (J) {
1735dfccc68fSToby Isaac         PetscReal extJ[24];
1736dfccc68fSToby Isaac 
17379371c9d4SSatish Balay         extJ[0]  = 0.;
17389371c9d4SSatish Balay         extJ[1]  = 0.;
17399371c9d4SSatish Balay         extJ[2]  = 0.;
17409371c9d4SSatish Balay         extJ[3]  = 1.;
17419371c9d4SSatish Balay         extJ[4]  = 0.;
17429371c9d4SSatish Balay         extJ[5]  = 0.;
17439371c9d4SSatish Balay         extJ[6]  = 0.;
17449371c9d4SSatish Balay         extJ[7]  = 1.;
17459371c9d4SSatish Balay         extJ[8]  = 0.;
17469371c9d4SSatish Balay         extJ[9]  = eta;
17479371c9d4SSatish Balay         extJ[10] = xi;
17489371c9d4SSatish Balay         extJ[11] = 0.;
17499371c9d4SSatish Balay         extJ[12] = 0.;
17509371c9d4SSatish Balay         extJ[13] = 0.;
17519371c9d4SSatish Balay         extJ[14] = 1.;
17529371c9d4SSatish Balay         extJ[15] = theta;
17539371c9d4SSatish Balay         extJ[16] = 0.;
17549371c9d4SSatish Balay         extJ[17] = xi;
17559371c9d4SSatish Balay         extJ[18] = 0.;
17569371c9d4SSatish Balay         extJ[19] = theta;
17579371c9d4SSatish Balay         extJ[20] = eta;
17589371c9d4SSatish Balay         extJ[21] = theta * eta;
17599371c9d4SSatish Balay         extJ[22] = theta * xi;
17609371c9d4SSatish Balay         extJ[23] = eta * xi;
1761dfccc68fSToby Isaac 
1762dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1763dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1764dfccc68fSToby Isaac             PetscReal val = 0.;
1765dfccc68fSToby Isaac 
1766ad540459SPierre Jolivet             for (l = 0; l < Nv; l++) val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1767dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1768dfccc68fSToby Isaac           }
1769dfccc68fSToby Isaac         }
1770dfccc68fSToby Isaac         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1771ad540459SPierre Jolivet         if (invJ) DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);
1772dfccc68fSToby Isaac       }
1773dfccc68fSToby Isaac     }
1774dfccc68fSToby Isaac   }
17756858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
17763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1777ccd2543fSMatthew G Knepley }
1778ccd2543fSMatthew G Knepley 
1779d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeTriangularPrismGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1780d71ae5a4SJacob Faibussowitsch {
17816858538eSMatthew G. Knepley   const PetscScalar *array;
17822df84da0SMatthew G. Knepley   PetscScalar       *coords = NULL;
17832df84da0SMatthew G. Knepley   const PetscInt     dim    = 3;
17846858538eSMatthew G. Knepley   PetscInt           numCoords, d;
17856858538eSMatthew G. Knepley   PetscBool          isDG;
17862df84da0SMatthew G. Knepley 
17872df84da0SMatthew G. Knepley   PetscFunctionBegin;
17886858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
17896858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
17902df84da0SMatthew G. Knepley   if (!Nq) {
17912df84da0SMatthew G. Knepley     /* Assume that the map to the reference is affine */
17922df84da0SMatthew G. Knepley     *detJ = 0.0;
17939371c9d4SSatish Balay     if (v) {
17949371c9d4SSatish Balay       for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);
17959371c9d4SSatish Balay     }
17962df84da0SMatthew G. Knepley     if (J) {
17972df84da0SMatthew G. Knepley       for (d = 0; d < dim; d++) {
17982df84da0SMatthew G. Knepley         J[d * dim + 0] = 0.5 * (PetscRealPart(coords[2 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
17992df84da0SMatthew G. Knepley         J[d * dim + 1] = 0.5 * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
18002df84da0SMatthew G. Knepley         J[d * dim + 2] = 0.5 * (PetscRealPart(coords[4 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
18012df84da0SMatthew G. Knepley       }
18029566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
18032df84da0SMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
18042df84da0SMatthew G. Knepley     }
1805ad540459SPierre Jolivet     if (invJ) DMPlex_Invert3D_Internal(invJ, J, *detJ);
18062df84da0SMatthew G. Knepley   } else {
18072df84da0SMatthew G. Knepley     const PetscInt dim  = 3;
18082df84da0SMatthew G. Knepley     const PetscInt dimR = 3;
18092df84da0SMatthew G. Knepley     const PetscInt Nv   = 6;
18102df84da0SMatthew G. Knepley     PetscReal      verts[18];
18112df84da0SMatthew G. Knepley     PetscReal      coeff[18];
18122df84da0SMatthew G. Knepley     PetscInt       i, j, k, l;
18132df84da0SMatthew G. Knepley 
18149371c9d4SSatish Balay     for (i = 0; i < Nv; ++i)
18159371c9d4SSatish Balay       for (j = 0; j < dim; ++j) verts[dim * i + j] = PetscRealPart(coords[dim * i + j]);
18162df84da0SMatthew G. Knepley     for (j = 0; j < dim; ++j) {
18172df84da0SMatthew G. Knepley       /* Check for triangle,
18182df84da0SMatthew G. Knepley            phi^0 = -1/2 (xi + eta)  chi^0 = delta(-1, -1)   x(xi) = \sum_k x_k phi^k(xi) = \sum_k chi^k(x) phi^k(xi)
18192df84da0SMatthew G. Knepley            phi^1 =  1/2 (1 + xi)    chi^1 = delta( 1, -1)   y(xi) = \sum_k y_k phi^k(xi) = \sum_k chi^k(y) phi^k(xi)
18202df84da0SMatthew G. Knepley            phi^2 =  1/2 (1 + eta)   chi^2 = delta(-1,  1)
18212df84da0SMatthew G. Knepley 
18222df84da0SMatthew G. Knepley            phi^0 + phi^1 + phi^2 = 1    coef_1   = 1/2 (         chi^1 + chi^2)
18232df84da0SMatthew G. Knepley           -phi^0 + phi^1 - phi^2 = xi   coef_xi  = 1/2 (-chi^0 + chi^1)
18242df84da0SMatthew G. Knepley           -phi^0 - phi^1 + phi^2 = eta  coef_eta = 1/2 (-chi^0         + chi^2)
18252df84da0SMatthew G. Knepley 
18262df84da0SMatthew G. Knepley           < chi_0 chi_1 chi_2> A /  1  1  1 \ / phi_0 \   <chi> I <phi>^T  so we need the inverse transpose
18272df84da0SMatthew G. Knepley                                  | -1  1 -1 | | phi_1 | =
18282df84da0SMatthew G. Knepley                                  \ -1 -1  1 / \ phi_2 /
18292df84da0SMatthew G. Knepley 
18302df84da0SMatthew G. Knepley           Check phi^0: 1/2 (phi^0 chi^1 + phi^0 chi^2 + phi^0 chi^0 - phi^0 chi^1 + phi^0 chi^0 - phi^0 chi^2) = phi^0 chi^0
18312df84da0SMatthew G. Knepley       */
18322df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: {-xi - eta, 1 + xi, 1 + eta} (1 \mp zeta):
18332df84da0SMatthew G. Knepley            \phi^0 = 1/4 (   -xi - eta        + xi zeta + eta zeta) --> /  1  1  1  1  1  1 \ 1
18342df84da0SMatthew G. Knepley            \phi^1 = 1/4 (1      + eta - zeta           - eta zeta) --> | -1  1 -1 -1 -1  1 | eta
18352df84da0SMatthew G. Knepley            \phi^2 = 1/4 (1 + xi       - zeta - xi zeta)            --> | -1 -1  1 -1  1 -1 | xi
18362df84da0SMatthew G. Knepley            \phi^3 = 1/4 (   -xi - eta        - xi zeta - eta zeta) --> | -1 -1 -1  1  1  1 | zeta
18372df84da0SMatthew G. Knepley            \phi^4 = 1/4 (1 + xi       + zeta + xi zeta)            --> |  1  1 -1 -1  1 -1 | xi zeta
18382df84da0SMatthew G. Knepley            \phi^5 = 1/4 (1      + eta + zeta           + eta zeta) --> \  1 -1  1 -1 -1  1 / eta zeta
18392df84da0SMatthew G. Knepley            1/4 /  0  1  1  0  1  1 \
18402df84da0SMatthew G. Knepley                | -1  1  0 -1  0  1 |
18412df84da0SMatthew G. Knepley                | -1  0  1 -1  1  0 |
18422df84da0SMatthew G. Knepley                |  0 -1 -1  0  1  1 |
18432df84da0SMatthew G. Knepley                |  1  0 -1 -1  1  0 |
18442df84da0SMatthew G. Knepley                \  1 -1  0 -1  0  1 /
18452df84da0SMatthew G. Knepley       */
18462df84da0SMatthew G. Knepley       coeff[dim * 0 + j] = (1. / 4.) * (verts[dim * 1 + j] + verts[dim * 2 + j] + verts[dim * 4 + j] + verts[dim * 5 + j]);
18472df84da0SMatthew G. Knepley       coeff[dim * 1 + j] = (1. / 4.) * (-verts[dim * 0 + j] + verts[dim * 1 + j] - verts[dim * 3 + j] + verts[dim * 5 + j]);
18482df84da0SMatthew G. Knepley       coeff[dim * 2 + j] = (1. / 4.) * (-verts[dim * 0 + j] + verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
18492df84da0SMatthew G. Knepley       coeff[dim * 3 + j] = (1. / 4.) * (-verts[dim * 1 + j] - verts[dim * 2 + j] + verts[dim * 4 + j] + verts[dim * 5 + j]);
18502df84da0SMatthew G. Knepley       coeff[dim * 4 + j] = (1. / 4.) * (verts[dim * 0 + j] - verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
18512df84da0SMatthew G. Knepley       coeff[dim * 5 + j] = (1. / 4.) * (verts[dim * 0 + j] - verts[dim * 1 + j] - verts[dim * 3 + j] + verts[dim * 5 + j]);
18522df84da0SMatthew G. Knepley       /* For reference prism:
18532df84da0SMatthew G. Knepley       {0, 0, 0}
18542df84da0SMatthew G. Knepley       {0, 1, 0}
18552df84da0SMatthew G. Knepley       {1, 0, 0}
18562df84da0SMatthew G. Knepley       {0, 0, 1}
18572df84da0SMatthew G. Knepley       {0, 0, 0}
18582df84da0SMatthew G. Knepley       {0, 0, 0}
18592df84da0SMatthew G. Knepley       */
18602df84da0SMatthew G. Knepley     }
18612df84da0SMatthew G. Knepley     for (i = 0; i < Nq; ++i) {
18622df84da0SMatthew G. Knepley       const PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], zeta = points[dimR * i + 2];
18632df84da0SMatthew G. Knepley 
18642df84da0SMatthew G. Knepley       if (v) {
18652df84da0SMatthew G. Knepley         PetscReal extPoint[6];
18662df84da0SMatthew G. Knepley         PetscInt  c;
18672df84da0SMatthew G. Knepley 
18682df84da0SMatthew G. Knepley         extPoint[0] = 1.;
18692df84da0SMatthew G. Knepley         extPoint[1] = eta;
18702df84da0SMatthew G. Knepley         extPoint[2] = xi;
18712df84da0SMatthew G. Knepley         extPoint[3] = zeta;
18722df84da0SMatthew G. Knepley         extPoint[4] = xi * zeta;
18732df84da0SMatthew G. Knepley         extPoint[5] = eta * zeta;
18742df84da0SMatthew G. Knepley         for (c = 0; c < dim; ++c) {
18752df84da0SMatthew G. Knepley           PetscReal val = 0.;
18762df84da0SMatthew G. Knepley 
1877ad540459SPierre Jolivet           for (k = 0; k < Nv; ++k) val += extPoint[k] * coeff[k * dim + c];
18782df84da0SMatthew G. Knepley           v[i * dim + c] = val;
18792df84da0SMatthew G. Knepley         }
18802df84da0SMatthew G. Knepley       }
18812df84da0SMatthew G. Knepley       if (J) {
18822df84da0SMatthew G. Knepley         PetscReal extJ[18];
18832df84da0SMatthew G. Knepley 
18849371c9d4SSatish Balay         extJ[0]  = 0.;
18859371c9d4SSatish Balay         extJ[1]  = 0.;
18869371c9d4SSatish Balay         extJ[2]  = 0.;
18879371c9d4SSatish Balay         extJ[3]  = 0.;
18889371c9d4SSatish Balay         extJ[4]  = 1.;
18899371c9d4SSatish Balay         extJ[5]  = 0.;
18909371c9d4SSatish Balay         extJ[6]  = 1.;
18919371c9d4SSatish Balay         extJ[7]  = 0.;
18929371c9d4SSatish Balay         extJ[8]  = 0.;
18939371c9d4SSatish Balay         extJ[9]  = 0.;
18949371c9d4SSatish Balay         extJ[10] = 0.;
18959371c9d4SSatish Balay         extJ[11] = 1.;
18969371c9d4SSatish Balay         extJ[12] = zeta;
18979371c9d4SSatish Balay         extJ[13] = 0.;
18989371c9d4SSatish Balay         extJ[14] = xi;
18999371c9d4SSatish Balay         extJ[15] = 0.;
19009371c9d4SSatish Balay         extJ[16] = zeta;
19019371c9d4SSatish Balay         extJ[17] = eta;
19022df84da0SMatthew G. Knepley 
19032df84da0SMatthew G. Knepley         for (j = 0; j < dim; j++) {
19042df84da0SMatthew G. Knepley           for (k = 0; k < dimR; k++) {
19052df84da0SMatthew G. Knepley             PetscReal val = 0.;
19062df84da0SMatthew G. Knepley 
1907ad540459SPierre Jolivet             for (l = 0; l < Nv; l++) val += coeff[dim * l + j] * extJ[dimR * l + k];
19082df84da0SMatthew G. Knepley             J[i * dim * dim + dim * j + k] = val;
19092df84da0SMatthew G. Knepley           }
19102df84da0SMatthew G. Knepley         }
19112df84da0SMatthew G. Knepley         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1912ad540459SPierre Jolivet         if (invJ) DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);
19132df84da0SMatthew G. Knepley       }
19142df84da0SMatthew G. Knepley     }
19152df84da0SMatthew G. Knepley   }
19166858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
19173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19182df84da0SMatthew G. Knepley }
19192df84da0SMatthew G. Knepley 
1920d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeCellGeometryFEM_Implicit(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
1921d71ae5a4SJacob Faibussowitsch {
1922ba2698f1SMatthew G. Knepley   DMPolytopeType   ct;
1923dfccc68fSToby Isaac   PetscInt         depth, dim, coordDim, coneSize, i;
1924dfccc68fSToby Isaac   PetscInt         Nq     = 0;
1925dfccc68fSToby Isaac   const PetscReal *points = NULL;
1926dfccc68fSToby Isaac   DMLabel          depthLabel;
1927c330f8ffSToby Isaac   PetscReal        xi0[3]   = {-1., -1., -1.}, v0[3], J0[9], detJ0;
1928dfccc68fSToby Isaac   PetscBool        isAffine = PETSC_TRUE;
1929dfccc68fSToby Isaac 
1930dfccc68fSToby Isaac   PetscFunctionBegin;
19319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
19329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
19339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
19349566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(depthLabel, cell, &dim));
193548a46eb9SPierre Jolivet   if (depth == 1 && dim == 1) PetscCall(DMGetDimension(dm, &dim));
19369566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
193763a3b9bcSJacob Faibussowitsch   PetscCheck(coordDim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported coordinate dimension %" PetscInt_FMT " > 3", coordDim);
19389566063dSJacob Faibussowitsch   if (quad) PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &points, NULL));
19399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1940ba2698f1SMatthew G. Knepley   switch (ct) {
1941ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_POINT:
19429566063dSJacob Faibussowitsch     PetscCall(DMPlexComputePointGeometry_Internal(dm, cell, v, J, invJ, detJ));
1943dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1944dfccc68fSToby Isaac     break;
1945ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
1946412e9a14SMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
19479566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
19489566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v, J, invJ, detJ));
1949dfccc68fSToby Isaac     break;
1950ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
19519566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
19529566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v, J, invJ, detJ));
1953dfccc68fSToby Isaac     break;
1954ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
19559566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_FALSE, Nq, points, v, J, invJ, detJ));
1956412e9a14SMatthew G. Knepley     isAffine = PETSC_FALSE;
1957412e9a14SMatthew G. Knepley     break;
1958412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
19599566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_TRUE, Nq, points, v, J, invJ, detJ));
1960dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1961dfccc68fSToby Isaac     break;
1962ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_TETRAHEDRON:
19639566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
19649566063dSJacob Faibussowitsch     else PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v, J, invJ, detJ));
1965dfccc68fSToby Isaac     break;
1966ba2698f1SMatthew G. Knepley   case DM_POLYTOPE_HEXAHEDRON:
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeHexahedronGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
1968dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1969dfccc68fSToby Isaac     break;
19702df84da0SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM:
19719566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeTriangularPrismGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
19722df84da0SMatthew G. Knepley     isAffine = PETSC_FALSE;
19732df84da0SMatthew G. Knepley     break;
1974d71ae5a4SJacob Faibussowitsch   default:
1975d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No element geometry for cell %" PetscInt_FMT " with type %s", cell, DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
1976dfccc68fSToby Isaac   }
19777318780aSToby Isaac   if (isAffine && Nq) {
1978dfccc68fSToby Isaac     if (v) {
1979ad540459SPierre Jolivet       for (i = 0; i < Nq; i++) CoordinatesRefToReal(coordDim, dim, xi0, v0, J0, &points[dim * i], &v[coordDim * i]);
1980dfccc68fSToby Isaac     }
19817318780aSToby Isaac     if (detJ) {
1982ad540459SPierre Jolivet       for (i = 0; i < Nq; i++) detJ[i] = detJ0;
19837318780aSToby Isaac     }
19847318780aSToby Isaac     if (J) {
19857318780aSToby Isaac       PetscInt k;
19867318780aSToby Isaac 
19877318780aSToby Isaac       for (i = 0, k = 0; i < Nq; i++) {
1988dfccc68fSToby Isaac         PetscInt j;
1989dfccc68fSToby Isaac 
1990ad540459SPierre Jolivet         for (j = 0; j < coordDim * coordDim; j++, k++) J[k] = J0[j];
19917318780aSToby Isaac       }
19927318780aSToby Isaac     }
19937318780aSToby Isaac     if (invJ) {
19947318780aSToby Isaac       PetscInt k;
19957318780aSToby Isaac       switch (coordDim) {
1996d71ae5a4SJacob Faibussowitsch       case 0:
1997d71ae5a4SJacob Faibussowitsch         break;
1998d71ae5a4SJacob Faibussowitsch       case 1:
1999d71ae5a4SJacob Faibussowitsch         invJ[0] = 1. / J0[0];
2000d71ae5a4SJacob Faibussowitsch         break;
2001d71ae5a4SJacob Faibussowitsch       case 2:
2002d71ae5a4SJacob Faibussowitsch         DMPlex_Invert2D_Internal(invJ, J0, detJ0);
2003d71ae5a4SJacob Faibussowitsch         break;
2004d71ae5a4SJacob Faibussowitsch       case 3:
2005d71ae5a4SJacob Faibussowitsch         DMPlex_Invert3D_Internal(invJ, J0, detJ0);
2006d71ae5a4SJacob Faibussowitsch         break;
20077318780aSToby Isaac       }
20087318780aSToby Isaac       for (i = 1, k = coordDim * coordDim; i < Nq; i++) {
20097318780aSToby Isaac         PetscInt j;
20107318780aSToby Isaac 
2011ad540459SPierre Jolivet         for (j = 0; j < coordDim * coordDim; j++, k++) invJ[k] = invJ[j];
2012dfccc68fSToby Isaac       }
2013dfccc68fSToby Isaac     }
2014dfccc68fSToby Isaac   }
20153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2016dfccc68fSToby Isaac }
2017dfccc68fSToby Isaac 
2018ccd2543fSMatthew G Knepley /*@C
20198e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryAffineFEM - Assuming an affine map, compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
2020ccd2543fSMatthew G Knepley 
202120f4b53cSBarry Smith   Collective
2022ccd2543fSMatthew G Knepley 
20234165533cSJose E. Roman   Input Parameters:
202420f4b53cSBarry Smith + dm   - the `DMPLEX`
2025ccd2543fSMatthew G Knepley - cell - the cell
2026ccd2543fSMatthew G Knepley 
20274165533cSJose E. Roman   Output Parameters:
20289b172b3aSMatthew Knepley + v0   - the translation part of this affine transform, meaning the translation to the origin (not the first vertex of the reference cell)
2029ccd2543fSMatthew G Knepley . J    - the Jacobian of the transform from the reference element
2030ccd2543fSMatthew G Knepley . invJ - the inverse of the Jacobian
2031ccd2543fSMatthew G Knepley - detJ - the Jacobian determinant
2032ccd2543fSMatthew G Knepley 
2033ccd2543fSMatthew G Knepley   Level: advanced
2034ccd2543fSMatthew G Knepley 
203520f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeCellGeometryFEM()`, `DMGetCoordinateSection()`, `DMGetCoordinates()`
2036ccd2543fSMatthew G Knepley @*/
2037d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellGeometryAffineFEM(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
2038d71ae5a4SJacob Faibussowitsch {
2039ccd2543fSMatthew G Knepley   PetscFunctionBegin;
20409566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, NULL, v0, J, invJ, detJ));
20413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20428e0841e0SMatthew G. Knepley }
20438e0841e0SMatthew G. Knepley 
2044d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeCellGeometryFEM_FE(DM dm, PetscFE fe, PetscInt point, PetscQuadrature quad, PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
2045d71ae5a4SJacob Faibussowitsch {
20466858538eSMatthew G. Knepley   const PetscScalar *array;
20478e0841e0SMatthew G. Knepley   PetscScalar       *coords = NULL;
20486858538eSMatthew G. Knepley   PetscInt           numCoords;
20496858538eSMatthew G. Knepley   PetscBool          isDG;
20506858538eSMatthew G. Knepley   PetscQuadrature    feQuad;
20518e0841e0SMatthew G. Knepley   const PetscReal   *quadPoints;
2052ef0bb6c7SMatthew G. Knepley   PetscTabulation    T;
20536858538eSMatthew G. Knepley   PetscInt           dim, cdim, pdim, qdim, Nq, q;
20548e0841e0SMatthew G. Knepley 
20558e0841e0SMatthew G. Knepley   PetscFunctionBegin;
20569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
20579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
20586858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
2059dfccc68fSToby Isaac   if (!quad) { /* use the first point of the first functional of the dual space */
2060dfccc68fSToby Isaac     PetscDualSpace dsp;
2061dfccc68fSToby Isaac 
20629566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDualSpace(fe, &dsp));
20639566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(dsp, 0, &quad));
20649566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
2065dfccc68fSToby Isaac     Nq = 1;
2066dfccc68fSToby Isaac   } else {
20679566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
2068dfccc68fSToby Isaac   }
20699566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
20709566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &feQuad));
2071dfccc68fSToby Isaac   if (feQuad == quad) {
20729566063dSJacob Faibussowitsch     PetscCall(PetscFEGetCellTabulation(fe, J ? 1 : 0, &T));
207363a3b9bcSJacob Faibussowitsch     PetscCheck(numCoords == pdim * cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "There are %" PetscInt_FMT " coordinates for point %" PetscInt_FMT " != %" PetscInt_FMT "*%" PetscInt_FMT, numCoords, point, pdim, cdim);
2074dfccc68fSToby Isaac   } else {
20759566063dSJacob Faibussowitsch     PetscCall(PetscFECreateTabulation(fe, 1, Nq, quadPoints, J ? 1 : 0, &T));
2076dfccc68fSToby Isaac   }
207763a3b9bcSJacob Faibussowitsch   PetscCheck(qdim == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Point dimension %" PetscInt_FMT " != quadrature dimension %" PetscInt_FMT, dim, qdim);
2078ef0bb6c7SMatthew G. Knepley   {
2079ef0bb6c7SMatthew G. Knepley     const PetscReal *basis    = T->T[0];
2080ef0bb6c7SMatthew G. Knepley     const PetscReal *basisDer = T->T[1];
2081ef0bb6c7SMatthew G. Knepley     PetscReal        detJt;
2082ef0bb6c7SMatthew G. Knepley 
2083a2a9e04cSMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
208463a3b9bcSJacob Faibussowitsch     PetscCheck(Nq == T->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Np %" PetscInt_FMT " != %" PetscInt_FMT, Nq, T->Np);
208563a3b9bcSJacob Faibussowitsch     PetscCheck(pdim == T->Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nb %" PetscInt_FMT " != %" PetscInt_FMT, pdim, T->Nb);
208663a3b9bcSJacob Faibussowitsch     PetscCheck(dim == T->Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nc %" PetscInt_FMT " != %" PetscInt_FMT, dim, T->Nc);
208763a3b9bcSJacob Faibussowitsch     PetscCheck(cdim == T->cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "cdim %" PetscInt_FMT " != %" PetscInt_FMT, cdim, T->cdim);
2088a2a9e04cSMatthew G. Knepley #endif
2089dfccc68fSToby Isaac     if (v) {
20909566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(v, Nq * cdim));
2091f960e424SToby Isaac       for (q = 0; q < Nq; ++q) {
2092f960e424SToby Isaac         PetscInt i, k;
2093f960e424SToby Isaac 
2094301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
2095301b184aSMatthew G. Knepley           const PetscInt vertex = k / cdim;
2096ad540459SPierre Jolivet           for (i = 0; i < cdim; ++i) v[q * cdim + i] += basis[(q * pdim + k) * cdim + i] * PetscRealPart(coords[vertex * cdim + i]);
2097301b184aSMatthew G. Knepley         }
20989566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0 * pdim * cdim));
2099f960e424SToby Isaac       }
2100f960e424SToby Isaac     }
21018e0841e0SMatthew G. Knepley     if (J) {
21029566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(J, Nq * cdim * cdim));
21038e0841e0SMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
21048e0841e0SMatthew G. Knepley         PetscInt i, j, k, c, r;
21058e0841e0SMatthew G. Knepley 
21068e0841e0SMatthew G. Knepley         /* J = dx_i/d\xi_j = sum[k=0,n-1] dN_k/d\xi_j * x_i(k) */
2107301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
2108301b184aSMatthew G. Knepley           const PetscInt vertex = k / cdim;
2109301b184aSMatthew G. Knepley           for (j = 0; j < dim; ++j) {
2110ad540459SPierre Jolivet             for (i = 0; i < cdim; ++i) J[(q * cdim + i) * cdim + j] += basisDer[((q * pdim + k) * cdim + i) * dim + j] * PetscRealPart(coords[vertex * cdim + i]);
2111301b184aSMatthew G. Knepley           }
2112301b184aSMatthew G. Knepley         }
21139566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0 * pdim * dim * cdim));
21148e0841e0SMatthew G. Knepley         if (cdim > dim) {
21158e0841e0SMatthew G. Knepley           for (c = dim; c < cdim; ++c)
21169371c9d4SSatish Balay             for (r = 0; r < cdim; ++r) J[r * cdim + c] = r == c ? 1.0 : 0.0;
21178e0841e0SMatthew G. Knepley         }
2118f960e424SToby Isaac         if (!detJ && !invJ) continue;
2119a63b72c6SToby Isaac         detJt = 0.;
21208e0841e0SMatthew G. Knepley         switch (cdim) {
21218e0841e0SMatthew G. Knepley         case 3:
2122037dc194SToby Isaac           DMPlex_Det3D_Internal(&detJt, &J[q * cdim * dim]);
2123ad540459SPierre Jolivet           if (invJ) DMPlex_Invert3D_Internal(&invJ[q * cdim * dim], &J[q * cdim * dim], detJt);
212417fe8556SMatthew G. Knepley           break;
212549dc4407SMatthew G. Knepley         case 2:
21269f328543SToby Isaac           DMPlex_Det2D_Internal(&detJt, &J[q * cdim * dim]);
2127ad540459SPierre Jolivet           if (invJ) DMPlex_Invert2D_Internal(&invJ[q * cdim * dim], &J[q * cdim * dim], detJt);
212849dc4407SMatthew G. Knepley           break;
21298e0841e0SMatthew G. Knepley         case 1:
2130037dc194SToby Isaac           detJt = J[q * cdim * dim];
2131037dc194SToby Isaac           if (invJ) invJ[q * cdim * dim] = 1.0 / detJt;
213249dc4407SMatthew G. Knepley         }
2133f960e424SToby Isaac         if (detJ) detJ[q] = detJt;
213449dc4407SMatthew G. Knepley       }
213508401ef6SPierre Jolivet     } else PetscCheck(!detJ && !invJ, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Need J to compute invJ or detJ");
213649dc4407SMatthew G. Knepley   }
21379566063dSJacob Faibussowitsch   if (feQuad != quad) PetscCall(PetscTabulationDestroy(&T));
21386858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
21393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21408e0841e0SMatthew G. Knepley }
21418e0841e0SMatthew G. Knepley 
21428e0841e0SMatthew G. Knepley /*@C
21438e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryFEM - Compute the Jacobian, inverse Jacobian, and Jacobian determinant at each quadrature point in the given cell
21448e0841e0SMatthew G. Knepley 
214520f4b53cSBarry Smith   Collective
21468e0841e0SMatthew G. Knepley 
21474165533cSJose E. Roman   Input Parameters:
214820f4b53cSBarry Smith + dm   - the `DMPLEX`
21498e0841e0SMatthew G. Knepley . cell - the cell
215020f4b53cSBarry Smith - quad - the quadrature containing the points in the reference element where the geometry will be evaluated.  If `quad` is `NULL`, geometry will be
2151dfccc68fSToby Isaac          evaluated at the first vertex of the reference element
21528e0841e0SMatthew G. Knepley 
21534165533cSJose E. Roman   Output Parameters:
2154dfccc68fSToby Isaac + v    - the image of the transformed quadrature points, otherwise the image of the first vertex in the closure of the reference element
21558e0841e0SMatthew G. Knepley . J    - the Jacobian of the transform from the reference element at each quadrature point
21568e0841e0SMatthew G. Knepley . invJ - the inverse of the Jacobian at each quadrature point
21578e0841e0SMatthew G. Knepley - detJ - the Jacobian determinant at each quadrature point
21588e0841e0SMatthew G. Knepley 
21598e0841e0SMatthew G. Knepley   Level: advanced
21608e0841e0SMatthew G. Knepley 
216120f4b53cSBarry Smith .seealso: `DMPLEX`, `DMGetCoordinateSection()`, `DMGetCoordinates()`
21628e0841e0SMatthew G. Knepley @*/
2163d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellGeometryFEM(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
2164d71ae5a4SJacob Faibussowitsch {
2165bb4a5db5SMatthew G. Knepley   DM      cdm;
2166dfccc68fSToby Isaac   PetscFE fe = NULL;
21678e0841e0SMatthew G. Knepley 
21688e0841e0SMatthew G. Knepley   PetscFunctionBegin;
2169dadcf809SJacob Faibussowitsch   PetscValidRealPointer(detJ, 7);
21709566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2171bb4a5db5SMatthew G. Knepley   if (cdm) {
2172dfccc68fSToby Isaac     PetscClassId id;
2173dfccc68fSToby Isaac     PetscInt     numFields;
2174e5e52638SMatthew G. Knepley     PetscDS      prob;
2175dfccc68fSToby Isaac     PetscObject  disc;
2176dfccc68fSToby Isaac 
21779566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(cdm, &numFields));
2178dfccc68fSToby Isaac     if (numFields) {
21799566063dSJacob Faibussowitsch       PetscCall(DMGetDS(cdm, &prob));
21809566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, 0, &disc));
21819566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &id));
2182ad540459SPierre Jolivet       if (id == PETSCFE_CLASSID) fe = (PetscFE)disc;
2183dfccc68fSToby Isaac     }
2184dfccc68fSToby Isaac   }
21859566063dSJacob Faibussowitsch   if (!fe) PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, quad, v, J, invJ, detJ));
21869566063dSJacob Faibussowitsch   else PetscCall(DMPlexComputeCellGeometryFEM_FE(dm, fe, cell, quad, v, J, invJ, detJ));
21873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2188ccd2543fSMatthew G Knepley }
2189834e62ceSMatthew G. Knepley 
2190d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeGeometryFVM_0D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2191d71ae5a4SJacob Faibussowitsch {
21929bf2564aSMatt McGurn   PetscSection       coordSection;
21939bf2564aSMatt McGurn   Vec                coordinates;
21949bf2564aSMatt McGurn   const PetscScalar *coords = NULL;
21959bf2564aSMatt McGurn   PetscInt           d, dof, off;
21969bf2564aSMatt McGurn 
21979bf2564aSMatt McGurn   PetscFunctionBegin;
21989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
21999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
22009566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
22019bf2564aSMatt McGurn 
22029bf2564aSMatt McGurn   /* for a point the centroid is just the coord */
22039bf2564aSMatt McGurn   if (centroid) {
22049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
22059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
2206ad540459SPierre Jolivet     for (d = 0; d < dof; d++) centroid[d] = PetscRealPart(coords[off + d]);
22079bf2564aSMatt McGurn   }
22089bf2564aSMatt McGurn   if (normal) {
22099bf2564aSMatt McGurn     const PetscInt *support, *cones;
22109bf2564aSMatt McGurn     PetscInt        supportSize;
22119bf2564aSMatt McGurn     PetscReal       norm, sign;
22129bf2564aSMatt McGurn 
22139bf2564aSMatt McGurn     /* compute the norm based upon the support centroids */
22149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, cell, &supportSize));
22159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, cell, &support));
22169566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, support[0], NULL, normal, NULL));
22179bf2564aSMatt McGurn 
22189bf2564aSMatt McGurn     /* Take the normal from the centroid of the support to the vertex*/
22199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
22209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
2221ad540459SPierre Jolivet     for (d = 0; d < dof; d++) normal[d] -= PetscRealPart(coords[off + d]);
22229bf2564aSMatt McGurn 
22239bf2564aSMatt McGurn     /* Determine the sign of the normal based upon its location in the support */
22249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, support[0], &cones));
22259bf2564aSMatt McGurn     sign = cones[0] == cell ? 1.0 : -1.0;
22269bf2564aSMatt McGurn 
22279bf2564aSMatt McGurn     norm = DMPlex_NormD_Internal(dim, normal);
22289bf2564aSMatt McGurn     for (d = 0; d < dim; ++d) normal[d] /= (norm * sign);
22299bf2564aSMatt McGurn   }
2230ad540459SPierre Jolivet   if (vol) *vol = 1.0;
22319566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
22323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22339bf2564aSMatt McGurn }
22349bf2564aSMatt McGurn 
2235d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeGeometryFVM_1D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2236d71ae5a4SJacob Faibussowitsch {
22376858538eSMatthew G. Knepley   const PetscScalar *array;
2238a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
223921d6a034SMatthew G. Knepley   PetscInt           cdim, coordSize, d;
22406858538eSMatthew G. Knepley   PetscBool          isDG;
2241cc08537eSMatthew G. Knepley 
2242cc08537eSMatthew G. Knepley   PetscFunctionBegin;
224321d6a034SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
22446858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
224521d6a034SMatthew G. Knepley   PetscCheck(coordSize == cdim * 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge has %" PetscInt_FMT " coordinates != %" PetscInt_FMT, coordSize, cdim * 2);
2246cc08537eSMatthew G. Knepley   if (centroid) {
224721d6a034SMatthew G. Knepley     for (d = 0; d < cdim; ++d) centroid[d] = 0.5 * PetscRealPart(coords[d] + coords[cdim + d]);
2248cc08537eSMatthew G. Knepley   }
2249cc08537eSMatthew G. Knepley   if (normal) {
2250a60a936bSMatthew G. Knepley     PetscReal norm;
2251a60a936bSMatthew G. Knepley 
225221d6a034SMatthew G. Knepley     switch (cdim) {
225321d6a034SMatthew G. Knepley     case 3:
2254f315e28eSPierre Jolivet       normal[2] = 0.; /* fall through */
225521d6a034SMatthew G. Knepley     case 2:
225621d6a034SMatthew G. Knepley       normal[0] = -PetscRealPart(coords[1] - coords[cdim + 1]);
225721d6a034SMatthew G. Knepley       normal[1] = PetscRealPart(coords[0] - coords[cdim + 0]);
225821d6a034SMatthew G. Knepley       break;
225921d6a034SMatthew G. Knepley     case 1:
226021d6a034SMatthew G. Knepley       normal[0] = 1.0;
226121d6a034SMatthew G. Knepley       break;
226221d6a034SMatthew G. Knepley     default:
226321d6a034SMatthew G. Knepley       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Dimension %" PetscInt_FMT " not supported", cdim);
226421d6a034SMatthew G. Knepley     }
226521d6a034SMatthew G. Knepley     norm = DMPlex_NormD_Internal(cdim, normal);
226621d6a034SMatthew G. Knepley     for (d = 0; d < cdim; ++d) normal[d] /= norm;
2267cc08537eSMatthew G. Knepley   }
2268cc08537eSMatthew G. Knepley   if (vol) {
2269714b99b6SMatthew G. Knepley     *vol = 0.0;
227021d6a034SMatthew G. Knepley     for (d = 0; d < cdim; ++d) *vol += PetscSqr(PetscRealPart(coords[d] - coords[cdim + d]));
2271714b99b6SMatthew G. Knepley     *vol = PetscSqrtReal(*vol);
2272cc08537eSMatthew G. Knepley   }
22736858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
22743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2275cc08537eSMatthew G. Knepley }
2276cc08537eSMatthew G. Knepley 
2277cc08537eSMatthew G. Knepley /* Centroid_i = (\sum_n A_n Cn_i) / A */
2278d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeGeometryFVM_2D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2279d71ae5a4SJacob Faibussowitsch {
2280412e9a14SMatthew G. Knepley   DMPolytopeType     ct;
22816858538eSMatthew G. Knepley   const PetscScalar *array;
2282cc08537eSMatthew G. Knepley   PetscScalar       *coords = NULL;
22836858538eSMatthew G. Knepley   PetscInt           coordSize;
22846858538eSMatthew G. Knepley   PetscBool          isDG;
2285793a2a13SMatthew G. Knepley   PetscInt           fv[4] = {0, 1, 2, 3};
22866858538eSMatthew G. Knepley   PetscInt           cdim, numCorners, p, d;
2287cc08537eSMatthew G. Knepley 
2288cc08537eSMatthew G. Knepley   PetscFunctionBegin;
2289793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
22909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2291412e9a14SMatthew G. Knepley   switch (ct) {
22929371c9d4SSatish Balay   case DM_POLYTOPE_SEG_PRISM_TENSOR:
22939371c9d4SSatish Balay     fv[2] = 3;
22949371c9d4SSatish Balay     fv[3] = 2;
22959371c9d4SSatish Balay     break;
2296d71ae5a4SJacob Faibussowitsch   default:
2297d71ae5a4SJacob Faibussowitsch     break;
2298412e9a14SMatthew G. Knepley   }
22999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
23006858538eSMatthew G. Knepley   PetscCall(DMPlexGetConeSize(dm, cell, &numCorners));
23016858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
23023f27a4e6SJed Brown   {
23033f27a4e6SJed Brown     PetscReal c[3] = {0., 0., 0.}, n[3] = {0., 0., 0.}, origin[3] = {0., 0., 0.}, norm;
2304793a2a13SMatthew G. Knepley 
23053f27a4e6SJed Brown     for (d = 0; d < cdim; d++) origin[d] = PetscRealPart(coords[d]);
23064f99dae5SMatthew G. Knepley     for (p = 0; p < numCorners - 2; ++p) {
23073f27a4e6SJed Brown       PetscReal e0[3] = {0., 0., 0.}, e1[3] = {0., 0., 0.};
23083f27a4e6SJed Brown       for (d = 0; d < cdim; d++) {
23093f27a4e6SJed Brown         e0[d] = PetscRealPart(coords[cdim * fv[p + 1] + d]) - origin[d];
23103f27a4e6SJed Brown         e1[d] = PetscRealPart(coords[cdim * fv[p + 2] + d]) - origin[d];
23113f27a4e6SJed Brown       }
23123f27a4e6SJed Brown       const PetscReal dx = e0[1] * e1[2] - e0[2] * e1[1];
23133f27a4e6SJed Brown       const PetscReal dy = e0[2] * e1[0] - e0[0] * e1[2];
23143f27a4e6SJed Brown       const PetscReal dz = e0[0] * e1[1] - e0[1] * e1[0];
23153f27a4e6SJed Brown       const PetscReal a  = PetscSqrtReal(dx * dx + dy * dy + dz * dz);
23164f99dae5SMatthew G. Knepley 
23174f99dae5SMatthew G. Knepley       n[0] += dx;
23184f99dae5SMatthew G. Knepley       n[1] += dy;
23194f99dae5SMatthew G. Knepley       n[2] += dz;
2320ad540459SPierre Jolivet       for (d = 0; d < cdim; d++) c[d] += a * PetscRealPart(origin[d] + coords[cdim * fv[p + 1] + d] + coords[cdim * fv[p + 2] + d]) / 3.;
2321ceee4971SMatthew G. Knepley     }
23224f99dae5SMatthew G. Knepley     norm = PetscSqrtReal(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
232361451c10SMatthew G. Knepley     // Allow zero volume cells
232461451c10SMatthew G. Knepley     if (norm != 0) {
23254f99dae5SMatthew G. Knepley       n[0] /= norm;
23264f99dae5SMatthew G. Knepley       n[1] /= norm;
23274f99dae5SMatthew G. Knepley       n[2] /= norm;
23284f99dae5SMatthew G. Knepley       c[0] /= norm;
23294f99dae5SMatthew G. Knepley       c[1] /= norm;
23304f99dae5SMatthew G. Knepley       c[2] /= norm;
233161451c10SMatthew G. Knepley     }
23324f99dae5SMatthew G. Knepley     if (vol) *vol = 0.5 * norm;
23339371c9d4SSatish Balay     if (centroid)
23349371c9d4SSatish Balay       for (d = 0; d < cdim; ++d) centroid[d] = c[d];
23359371c9d4SSatish Balay     if (normal)
23369371c9d4SSatish Balay       for (d = 0; d < cdim; ++d) normal[d] = n[d];
23370a1d6728SMatthew G. Knepley   }
23386858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
23393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2340cc08537eSMatthew G. Knepley }
2341cc08537eSMatthew G. Knepley 
23420ec8681fSMatthew G. Knepley /* Centroid_i = (\sum_n V_n Cn_i) / V */
2343d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeGeometryFVM_3D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2344d71ae5a4SJacob Faibussowitsch {
2345412e9a14SMatthew G. Knepley   DMPolytopeType        ct;
23466858538eSMatthew G. Knepley   const PetscScalar    *array;
23470ec8681fSMatthew G. Knepley   PetscScalar          *coords = NULL;
23486858538eSMatthew G. Knepley   PetscInt              coordSize;
23496858538eSMatthew G. Knepley   PetscBool             isDG;
23503f27a4e6SJed Brown   PetscReal             vsum      = 0.0, vtmp, coordsTmp[3 * 3], origin[3];
23516858538eSMatthew G. Knepley   const PetscInt        order[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
23526858538eSMatthew G. Knepley   const PetscInt       *cone, *faceSizes, *faces;
23536858538eSMatthew G. Knepley   const DMPolytopeType *faceTypes;
2354793a2a13SMatthew G. Knepley   PetscBool             isHybrid = PETSC_FALSE;
23556858538eSMatthew G. Knepley   PetscInt              numFaces, f, fOff = 0, p, d;
23560ec8681fSMatthew G. Knepley 
23570ec8681fSMatthew G. Knepley   PetscFunctionBegin;
235863a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No support for dim %" PetscInt_FMT " > 3", dim);
2359793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
23609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2361412e9a14SMatthew G. Knepley   switch (ct) {
2362412e9a14SMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
2363412e9a14SMatthew G. Knepley   case DM_POLYTOPE_SEG_PRISM_TENSOR:
2364412e9a14SMatthew G. Knepley   case DM_POLYTOPE_TRI_PRISM_TENSOR:
2365d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
2366d71ae5a4SJacob Faibussowitsch     isHybrid = PETSC_TRUE;
2367d71ae5a4SJacob Faibussowitsch   default:
2368d71ae5a4SJacob Faibussowitsch     break;
2369412e9a14SMatthew G. Knepley   }
2370793a2a13SMatthew G. Knepley 
23719371c9d4SSatish Balay   if (centroid)
23729371c9d4SSatish Balay     for (d = 0; d < dim; ++d) centroid[d] = 0.0;
23736858538eSMatthew G. Knepley   PetscCall(DMPlexGetCone(dm, cell, &cone));
23746858538eSMatthew G. Knepley 
23756858538eSMatthew G. Knepley   // Using the closure of faces for coordinates does not work in periodic geometries, so we index into the cell coordinates
23766858538eSMatthew G. Knepley   PetscCall(DMPlexGetRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
23776858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
23780ec8681fSMatthew G. Knepley   for (f = 0; f < numFaces; ++f) {
2379793a2a13SMatthew G. Knepley     PetscBool flip = isHybrid && f == 0 ? PETSC_TRUE : PETSC_FALSE; /* The first hybrid face is reversed */
2380793a2a13SMatthew G. Knepley 
23813f27a4e6SJed Brown     // If using zero as the origin vertex for each tetrahedron, an element far from the origin will have positive and
23823f27a4e6SJed Brown     // negative volumes that nearly cancel, thus incurring rounding error. Here we define origin[] as the first vertex
23833f27a4e6SJed Brown     // so that all tetrahedra have positive volume.
23849371c9d4SSatish Balay     if (f == 0)
23859371c9d4SSatish Balay       for (d = 0; d < dim; d++) origin[d] = PetscRealPart(coords[d]);
23866858538eSMatthew G. Knepley     switch (faceTypes[f]) {
2387ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
23880ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
23896858538eSMatthew G. Knepley         coordsTmp[0 * dim + d] = PetscRealPart(coords[faces[fOff + 0] * dim + d]) - origin[d];
23906858538eSMatthew G. Knepley         coordsTmp[1 * dim + d] = PetscRealPart(coords[faces[fOff + 1] * dim + d]) - origin[d];
23916858538eSMatthew G. Knepley         coordsTmp[2 * dim + d] = PetscRealPart(coords[faces[fOff + 2] * dim + d]) - origin[d];
23920ec8681fSMatthew G. Knepley       }
23930ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
23946858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
23950ec8681fSMatthew G. Knepley       vsum += vtmp;
23964f25033aSJed Brown       if (centroid) { /* Centroid of OABC = (a+b+c)/4 */
23970ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23981ee9d5ecSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p * dim + d] * vtmp;
23990ec8681fSMatthew G. Knepley         }
24000ec8681fSMatthew G. Knepley       }
24010ec8681fSMatthew G. Knepley       break;
2402ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
24039371c9d4SSatish Balay     case DM_POLYTOPE_SEG_PRISM_TENSOR: {
2404793a2a13SMatthew G. Knepley       PetscInt fv[4] = {0, 1, 2, 3};
2405793a2a13SMatthew G. Knepley 
2406793a2a13SMatthew G. Knepley       /* Side faces for hybrid cells are are stored as tensor products */
24079371c9d4SSatish Balay       if (isHybrid && f > 1) {
24089371c9d4SSatish Balay         fv[2] = 3;
24099371c9d4SSatish Balay         fv[3] = 2;
24109371c9d4SSatish Balay       }
24110ec8681fSMatthew G. Knepley       /* DO FOR PYRAMID */
24120ec8681fSMatthew G. Knepley       /* First tet */
24130ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
24146858538eSMatthew G. Knepley         coordsTmp[0 * dim + d] = PetscRealPart(coords[faces[fOff + fv[0]] * dim + d]) - origin[d];
24156858538eSMatthew G. Knepley         coordsTmp[1 * dim + d] = PetscRealPart(coords[faces[fOff + fv[1]] * dim + d]) - origin[d];
24166858538eSMatthew G. Knepley         coordsTmp[2 * dim + d] = PetscRealPart(coords[faces[fOff + fv[3]] * dim + d]) - origin[d];
24170ec8681fSMatthew G. Knepley       }
24180ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
24196858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
24200ec8681fSMatthew G. Knepley       vsum += vtmp;
24210ec8681fSMatthew G. Knepley       if (centroid) {
24220ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
24230ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p * dim + d] * vtmp;
24240ec8681fSMatthew G. Knepley         }
24250ec8681fSMatthew G. Knepley       }
24260ec8681fSMatthew G. Knepley       /* Second tet */
24270ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
24286858538eSMatthew G. Knepley         coordsTmp[0 * dim + d] = PetscRealPart(coords[faces[fOff + fv[1]] * dim + d]) - origin[d];
24296858538eSMatthew G. Knepley         coordsTmp[1 * dim + d] = PetscRealPart(coords[faces[fOff + fv[2]] * dim + d]) - origin[d];
24306858538eSMatthew G. Knepley         coordsTmp[2 * dim + d] = PetscRealPart(coords[faces[fOff + fv[3]] * dim + d]) - origin[d];
24310ec8681fSMatthew G. Knepley       }
24320ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
24336858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
24340ec8681fSMatthew G. Knepley       vsum += vtmp;
24350ec8681fSMatthew G. Knepley       if (centroid) {
24360ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
24370ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p * dim + d] * vtmp;
24380ec8681fSMatthew G. Knepley         }
24390ec8681fSMatthew G. Knepley       }
24400ec8681fSMatthew G. Knepley       break;
2441793a2a13SMatthew G. Knepley     }
2442d71ae5a4SJacob Faibussowitsch     default:
2443d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle face %" PetscInt_FMT " of type %s", cone[f], DMPolytopeTypes[ct]);
24440ec8681fSMatthew G. Knepley     }
24456858538eSMatthew G. Knepley     fOff += faceSizes[f];
24460ec8681fSMatthew G. Knepley   }
24476858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
24486858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
24498763be8eSMatthew G. Knepley   if (vol) *vol = PetscAbsReal(vsum);
24509371c9d4SSatish Balay   if (normal)
24519371c9d4SSatish Balay     for (d = 0; d < dim; ++d) normal[d] = 0.0;
24529371c9d4SSatish Balay   if (centroid)
24539371c9d4SSatish Balay     for (d = 0; d < dim; ++d) centroid[d] = centroid[d] / (vsum * 4) + origin[d];
24543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24550ec8681fSMatthew G. Knepley }
24560ec8681fSMatthew G. Knepley 
2457834e62ceSMatthew G. Knepley /*@C
2458834e62ceSMatthew G. Knepley   DMPlexComputeCellGeometryFVM - Compute the volume for a given cell
2459834e62ceSMatthew G. Knepley 
246020f4b53cSBarry Smith   Collective
2461834e62ceSMatthew G. Knepley 
24624165533cSJose E. Roman   Input Parameters:
246320f4b53cSBarry Smith + dm   - the `DMPLEX`
2464834e62ceSMatthew G. Knepley - cell - the cell
2465834e62ceSMatthew G. Knepley 
24664165533cSJose E. Roman   Output Parameters:
2467834e62ceSMatthew G. Knepley + volume   - the cell volume
2468cc08537eSMatthew G. Knepley . centroid - the cell centroid
2469cc08537eSMatthew G. Knepley - normal - the cell normal, if appropriate
2470834e62ceSMatthew G. Knepley 
2471834e62ceSMatthew G. Knepley   Level: advanced
2472834e62ceSMatthew G. Knepley 
247320f4b53cSBarry Smith .seealso: `DMPLEX`, `DMGetCoordinateSection()`, `DMGetCoordinates()`
2474834e62ceSMatthew G. Knepley @*/
2475d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellGeometryFVM(DM dm, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2476d71ae5a4SJacob Faibussowitsch {
24770ec8681fSMatthew G. Knepley   PetscInt depth, dim;
2478834e62ceSMatthew G. Knepley 
2479834e62ceSMatthew G. Knepley   PetscFunctionBegin;
24809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
24819566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
248208401ef6SPierre Jolivet   PetscCheck(depth == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh must be interpolated");
24839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPointDepth(dm, cell, &depth));
2484011ea5d8SMatthew G. Knepley   switch (depth) {
2485d71ae5a4SJacob Faibussowitsch   case 0:
2486d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_0D_Internal(dm, dim, cell, vol, centroid, normal));
2487d71ae5a4SJacob Faibussowitsch     break;
2488d71ae5a4SJacob Faibussowitsch   case 1:
2489d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_1D_Internal(dm, dim, cell, vol, centroid, normal));
2490d71ae5a4SJacob Faibussowitsch     break;
2491d71ae5a4SJacob Faibussowitsch   case 2:
2492d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_2D_Internal(dm, dim, cell, vol, centroid, normal));
2493d71ae5a4SJacob Faibussowitsch     break;
2494d71ae5a4SJacob Faibussowitsch   case 3:
2495d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_3D_Internal(dm, dim, cell, vol, centroid, normal));
2496d71ae5a4SJacob Faibussowitsch     break;
2497d71ae5a4SJacob Faibussowitsch   default:
2498d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %" PetscInt_FMT " (depth %" PetscInt_FMT ") for element geometry computation", dim, depth);
2499834e62ceSMatthew G. Knepley   }
25003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2501834e62ceSMatthew G. Knepley }
2502113c68e6SMatthew G. Knepley 
2503c501906fSMatthew G. Knepley /*@
2504891a9168SMatthew G. Knepley   DMPlexComputeGeometryFVM - Computes the cell and face geometry for a finite volume method
2505891a9168SMatthew G. Knepley 
2506891a9168SMatthew G. Knepley   Input Parameter:
250720f4b53cSBarry Smith . dm - The `DMPLEX`
2508891a9168SMatthew G. Knepley 
2509891a9168SMatthew G. Knepley   Output Parameters:
251020f4b53cSBarry Smith + cellgeom - A `Vec` of `PetscFVCellGeom` data
251120f4b53cSBarry Smith - facegeom - A `Vec` of `PetscFVFaceGeom` data
2512891a9168SMatthew G. Knepley 
2513891a9168SMatthew G. Knepley   Level: developer
2514891a9168SMatthew G. Knepley 
251520f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscFVFaceGeom`, `PetscFVCellGeom`
2516891a9168SMatthew G. Knepley @*/
2517d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGeometryFVM(DM dm, Vec *cellgeom, Vec *facegeom)
2518d71ae5a4SJacob Faibussowitsch {
2519113c68e6SMatthew G. Knepley   DM           dmFace, dmCell;
2520113c68e6SMatthew G. Knepley   DMLabel      ghostLabel;
2521113c68e6SMatthew G. Knepley   PetscSection sectionFace, sectionCell;
2522113c68e6SMatthew G. Knepley   PetscSection coordSection;
2523113c68e6SMatthew G. Knepley   Vec          coordinates;
2524113c68e6SMatthew G. Knepley   PetscScalar *fgeom, *cgeom;
2525113c68e6SMatthew G. Knepley   PetscReal    minradius, gminradius;
2526113c68e6SMatthew G. Knepley   PetscInt     dim, cStart, cEnd, cEndInterior, c, fStart, fEnd, f;
2527113c68e6SMatthew G. Knepley 
2528113c68e6SMatthew G. Knepley   PetscFunctionBegin;
25299566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
25309566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
25319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2532113c68e6SMatthew G. Knepley   /* Make cell centroids and volumes */
25339566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmCell));
25349566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection));
25359566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmCell, coordinates));
25369566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &sectionCell));
25379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
25389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
25399566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd));
25409566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, (PetscInt)PetscCeilReal(((PetscReal)sizeof(PetscFVCellGeom)) / sizeof(PetscScalar))));
25419566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionCell));
25429566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmCell, sectionCell));
25439566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionCell));
25449566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmCell, cellgeom));
2545485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
25469566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*cellgeom, &cgeom));
2547113c68e6SMatthew G. Knepley   for (c = cStart; c < cEndInterior; ++c) {
2548113c68e6SMatthew G. Knepley     PetscFVCellGeom *cg;
2549113c68e6SMatthew G. Knepley 
25509566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmCell, c, cgeom, &cg));
25519566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(cg, 1));
25529566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dmCell, c, &cg->volume, cg->centroid, NULL));
2553113c68e6SMatthew G. Knepley   }
2554113c68e6SMatthew G. Knepley   /* Compute face normals and minimum cell radius */
25559566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmFace));
25569566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &sectionFace));
25579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
25589566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionFace, fStart, fEnd));
25599566063dSJacob Faibussowitsch   for (f = fStart; f < fEnd; ++f) PetscCall(PetscSectionSetDof(sectionFace, f, (PetscInt)PetscCeilReal(((PetscReal)sizeof(PetscFVFaceGeom)) / sizeof(PetscScalar))));
25609566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionFace));
25619566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmFace, sectionFace));
25629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionFace));
25639566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmFace, facegeom));
25649566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*facegeom, &fgeom));
25659566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2566113c68e6SMatthew G. Knepley   minradius = PETSC_MAX_REAL;
2567113c68e6SMatthew G. Knepley   for (f = fStart; f < fEnd; ++f) {
2568113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2569113c68e6SMatthew G. Knepley     PetscReal        area;
2570412e9a14SMatthew G. Knepley     const PetscInt  *cells;
2571412e9a14SMatthew G. Knepley     PetscInt         ncells, ghost = -1, d, numChildren;
2572113c68e6SMatthew G. Knepley 
25739566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
25749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
25759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &cells));
25769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &ncells));
2577412e9a14SMatthew G. Knepley     /* It is possible to get a face with no support when using partition overlap */
2578412e9a14SMatthew G. Knepley     if (!ncells || ghost >= 0 || numChildren) continue;
25799566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, f, fgeom, &fg));
25809566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, f, &area, fg->centroid, fg->normal));
2581113c68e6SMatthew G. Knepley     for (d = 0; d < dim; ++d) fg->normal[d] *= area;
2582113c68e6SMatthew G. Knepley     /* Flip face orientation if necessary to match ordering in support, and Update minimum radius */
2583113c68e6SMatthew G. Knepley     {
2584113c68e6SMatthew G. Knepley       PetscFVCellGeom *cL, *cR;
2585113c68e6SMatthew G. Knepley       PetscReal       *lcentroid, *rcentroid;
25860453c0cdSMatthew G. Knepley       PetscReal        l[3], r[3], v[3];
2587113c68e6SMatthew G. Knepley 
25889566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cgeom, &cL));
2589113c68e6SMatthew G. Knepley       lcentroid = cells[0] >= cEndInterior ? fg->centroid : cL->centroid;
259006348e87SToby Isaac       if (ncells > 1) {
25919566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cgeom, &cR));
2592113c68e6SMatthew G. Knepley         rcentroid = cells[1] >= cEndInterior ? fg->centroid : cR->centroid;
25939371c9d4SSatish Balay       } else {
259406348e87SToby Isaac         rcentroid = fg->centroid;
259506348e87SToby Isaac       }
25969566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, lcentroid, l));
25979566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, rcentroid, r));
25980453c0cdSMatthew G. Knepley       DMPlex_WaxpyD_Internal(dim, -1, l, r, v);
2599113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) < 0) {
2600113c68e6SMatthew G. Knepley         for (d = 0; d < dim; ++d) fg->normal[d] = -fg->normal[d];
2601113c68e6SMatthew G. Knepley       }
2602113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) <= 0) {
260363a3b9bcSJacob Faibussowitsch         PetscCheck(dim != 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Direction for face %" PetscInt_FMT " could not be fixed, normal (%g,%g) v (%g,%g)", f, (double)fg->normal[0], (double)fg->normal[1], (double)v[0], (double)v[1]);
260463a3b9bcSJacob Faibussowitsch         PetscCheck(dim != 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Direction for face %" PetscInt_FMT " could not be fixed, normal (%g,%g,%g) v (%g,%g,%g)", f, (double)fg->normal[0], (double)fg->normal[1], (double)fg->normal[2], (double)v[0], (double)v[1], (double)v[2]);
260563a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Direction for face %" PetscInt_FMT " could not be fixed", f);
2606113c68e6SMatthew G. Knepley       }
2607113c68e6SMatthew G. Knepley       if (cells[0] < cEndInterior) {
2608113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cL->centroid, v);
2609113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2610113c68e6SMatthew G. Knepley       }
261106348e87SToby Isaac       if (ncells > 1 && cells[1] < cEndInterior) {
2612113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cR->centroid, v);
2613113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2614113c68e6SMatthew G. Knepley       }
2615113c68e6SMatthew G. Knepley     }
2616113c68e6SMatthew G. Knepley   }
26171c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&minradius, &gminradius, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm)));
26189566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMinRadius(dm, gminradius));
2619113c68e6SMatthew G. Knepley   /* Compute centroids of ghost cells */
2620113c68e6SMatthew G. Knepley   for (c = cEndInterior; c < cEnd; ++c) {
2621113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2622113c68e6SMatthew G. Knepley     const PetscInt  *cone, *support;
2623113c68e6SMatthew G. Knepley     PetscInt         coneSize, supportSize, s;
2624113c68e6SMatthew G. Knepley 
26259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmCell, c, &coneSize));
262663a3b9bcSJacob Faibussowitsch     PetscCheck(coneSize == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %" PetscInt_FMT " has cone size %" PetscInt_FMT " != 1", c, coneSize);
26279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmCell, c, &cone));
26289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmCell, cone[0], &supportSize));
262963a3b9bcSJacob Faibussowitsch     PetscCheck(supportSize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[0], supportSize);
26309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmCell, cone[0], &support));
26319566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, cone[0], fgeom, &fg));
2632113c68e6SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
2633113c68e6SMatthew G. Knepley       /* Reflect ghost centroid across plane of face */
2634113c68e6SMatthew G. Knepley       if (support[s] == c) {
2635640bce14SSatish Balay         PetscFVCellGeom *ci;
2636113c68e6SMatthew G. Knepley         PetscFVCellGeom *cg;
2637113c68e6SMatthew G. Knepley         PetscReal        c2f[3], a;
2638113c68e6SMatthew G. Knepley 
26399566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, support[(s + 1) % 2], cgeom, &ci));
2640113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, ci->centroid, fg->centroid, c2f); /* cell to face centroid */
2641113c68e6SMatthew G. Knepley         a = DMPlex_DotRealD_Internal(dim, c2f, fg->normal) / DMPlex_DotRealD_Internal(dim, fg->normal, fg->normal);
26429566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRef(dmCell, support[s], cgeom, &cg));
2643113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, 2 * a, fg->normal, ci->centroid, cg->centroid);
2644113c68e6SMatthew G. Knepley         cg->volume = ci->volume;
2645113c68e6SMatthew G. Knepley       }
2646113c68e6SMatthew G. Knepley     }
2647113c68e6SMatthew G. Knepley   }
26489566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*facegeom, &fgeom));
26499566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*cellgeom, &cgeom));
26509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmCell));
26519566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmFace));
26523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2653113c68e6SMatthew G. Knepley }
2654113c68e6SMatthew G. Knepley 
2655113c68e6SMatthew G. Knepley /*@C
2656113c68e6SMatthew G. Knepley   DMPlexGetMinRadius - Returns the minimum distance from any cell centroid to a face
2657113c68e6SMatthew G. Knepley 
265820f4b53cSBarry Smith   Not Collective
2659113c68e6SMatthew G. Knepley 
26604165533cSJose E. Roman   Input Parameter:
266120f4b53cSBarry Smith . dm - the `DMPLEX`
2662113c68e6SMatthew G. Knepley 
26634165533cSJose E. Roman   Output Parameter:
2664a5b23f4aSJose E. Roman . minradius - the minimum cell radius
2665113c68e6SMatthew G. Knepley 
2666113c68e6SMatthew G. Knepley   Level: developer
2667113c68e6SMatthew G. Knepley 
266820f4b53cSBarry Smith .seealso: `DMPLEX`, `DMGetCoordinates()`
2669113c68e6SMatthew G. Knepley @*/
2670d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMinRadius(DM dm, PetscReal *minradius)
2671d71ae5a4SJacob Faibussowitsch {
2672113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2673113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2674dadcf809SJacob Faibussowitsch   PetscValidRealPointer(minradius, 2);
2675113c68e6SMatthew G. Knepley   *minradius = ((DM_Plex *)dm->data)->minradius;
26763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2677113c68e6SMatthew G. Knepley }
2678113c68e6SMatthew G. Knepley 
2679113c68e6SMatthew G. Knepley /*@C
2680113c68e6SMatthew G. Knepley   DMPlexSetMinRadius - Sets the minimum distance from the cell centroid to a face
2681113c68e6SMatthew G. Knepley 
268220f4b53cSBarry Smith   Logically Collective
2683113c68e6SMatthew G. Knepley 
26844165533cSJose E. Roman   Input Parameters:
268520f4b53cSBarry Smith + dm - the `DMPLEX`
2686a5b23f4aSJose E. Roman - minradius - the minimum cell radius
2687113c68e6SMatthew G. Knepley 
2688113c68e6SMatthew G. Knepley   Level: developer
2689113c68e6SMatthew G. Knepley 
269020f4b53cSBarry Smith .seealso: `DMPLEX`, `DMSetCoordinates()`
2691113c68e6SMatthew G. Knepley @*/
2692d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMinRadius(DM dm, PetscReal minradius)
2693d71ae5a4SJacob Faibussowitsch {
2694113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2695113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2696113c68e6SMatthew G. Knepley   ((DM_Plex *)dm->data)->minradius = minradius;
26973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2698113c68e6SMatthew G. Knepley }
2699856ac710SMatthew G. Knepley 
2700d71ae5a4SJacob Faibussowitsch static PetscErrorCode BuildGradientReconstruction_Internal(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2701d71ae5a4SJacob Faibussowitsch {
2702856ac710SMatthew G. Knepley   DMLabel      ghostLabel;
2703856ac710SMatthew G. Knepley   PetscScalar *dx, *grad, **gref;
2704856ac710SMatthew G. Knepley   PetscInt     dim, cStart, cEnd, c, cEndInterior, maxNumFaces;
2705856ac710SMatthew G. Knepley 
2706856ac710SMatthew G. Knepley   PetscFunctionBegin;
27079566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
27089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
27099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2710089217ebSMatthew G. Knepley   cEndInterior = cEndInterior < 0 ? cEnd : cEndInterior;
27119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxNumFaces, NULL));
27129566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
27139566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
27149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces * dim, &dx, maxNumFaces * dim, &grad, maxNumFaces, &gref));
2715856ac710SMatthew G. Knepley   for (c = cStart; c < cEndInterior; c++) {
2716856ac710SMatthew G. Knepley     const PetscInt  *faces;
2717856ac710SMatthew G. Knepley     PetscInt         numFaces, usedFaces, f, d;
2718640bce14SSatish Balay     PetscFVCellGeom *cg;
2719856ac710SMatthew G. Knepley     PetscBool        boundary;
2720856ac710SMatthew G. Knepley     PetscInt         ghost;
2721856ac710SMatthew G. Knepley 
2722a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
2723a79418b7SMatt McGurn     PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2724a79418b7SMatt McGurn     if (ghost >= 0) continue;
2725a79418b7SMatt McGurn 
27269566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
27279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &numFaces));
27289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &faces));
272963a3b9bcSJacob Faibussowitsch     PetscCheck(numFaces >= dim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell %" PetscInt_FMT " has only %" PetscInt_FMT " faces, not enough for gradient reconstruction", c, numFaces);
2730856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
2731640bce14SSatish Balay       PetscFVCellGeom *cg1;
2732856ac710SMatthew G. Knepley       PetscFVFaceGeom *fg;
2733856ac710SMatthew G. Knepley       const PetscInt  *fcells;
2734856ac710SMatthew G. Knepley       PetscInt         ncell, side;
2735856ac710SMatthew G. Knepley 
27369566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
27379566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2738856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
27399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, faces[f], &fcells));
2740856ac710SMatthew G. Knepley       side  = (c != fcells[0]); /* c is on left=0 or right=1 of face */
2741856ac710SMatthew G. Knepley       ncell = fcells[!side];    /* the neighbor */
27429566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, faces[f], fgeom, &fg));
27439566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2744856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) dx[usedFaces * dim + d] = cg1->centroid[d] - cg->centroid[d];
2745856ac710SMatthew G. Knepley       gref[usedFaces++] = fg->grad[side]; /* Gradient reconstruction term will go here */
2746856ac710SMatthew G. Knepley     }
274728b400f6SJacob Faibussowitsch     PetscCheck(usedFaces, PETSC_COMM_SELF, PETSC_ERR_USER, "Mesh contains isolated cell (no neighbors). Is it intentional?");
27489566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, usedFaces, dx, grad));
2749856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
27509566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
27519566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2752856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
2753856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) gref[usedFaces][d] = grad[usedFaces * dim + d];
2754856ac710SMatthew G. Knepley       ++usedFaces;
2755856ac710SMatthew G. Knepley     }
2756856ac710SMatthew G. Knepley   }
27579566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
27583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2759856ac710SMatthew G. Knepley }
2760856ac710SMatthew G. Knepley 
2761d71ae5a4SJacob Faibussowitsch static PetscErrorCode BuildGradientReconstruction_Internal_Tree(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2762d71ae5a4SJacob Faibussowitsch {
2763b81db932SToby Isaac   DMLabel      ghostLabel;
2764b81db932SToby Isaac   PetscScalar *dx, *grad, **gref;
2765b81db932SToby Isaac   PetscInt     dim, cStart, cEnd, c, cEndInterior, fStart, fEnd, f, nStart, nEnd, maxNumFaces = 0;
2766b81db932SToby Isaac   PetscSection neighSec;
2767b81db932SToby Isaac   PetscInt(*neighbors)[2];
2768b81db932SToby Isaac   PetscInt *counter;
2769b81db932SToby Isaac 
2770b81db932SToby Isaac   PetscFunctionBegin;
27719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
27729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
27739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2774485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
27759566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &neighSec));
27769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(neighSec, cStart, cEndInterior));
27779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
27789566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2779b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2780b81db932SToby Isaac     const PetscInt *fcells;
2781b81db932SToby Isaac     PetscBool       boundary;
27825bc680faSToby Isaac     PetscInt        ghost = -1;
2783b81db932SToby Isaac     PetscInt        numChildren, numCells, c;
2784b81db932SToby Isaac 
27859566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
27869566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
27879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2788b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
27899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
279006348e87SToby Isaac     if (numCells == 2) {
27919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2792b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2793b81db932SToby Isaac         PetscInt cell = fcells[c];
2794b81db932SToby Isaac 
279548a46eb9SPierre Jolivet         if (cell >= cStart && cell < cEndInterior) PetscCall(PetscSectionAddDof(neighSec, cell, 1));
2796b81db932SToby Isaac       }
2797b81db932SToby Isaac     }
279806348e87SToby Isaac   }
27999566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(neighSec));
28009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(neighSec, &maxNumFaces));
28019566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
2802b81db932SToby Isaac   nStart = 0;
28039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(neighSec, &nEnd));
28049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((nEnd - nStart), &neighbors));
28059566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEndInterior - cStart), &counter));
2806b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2807b81db932SToby Isaac     const PetscInt *fcells;
2808b81db932SToby Isaac     PetscBool       boundary;
28095bc680faSToby Isaac     PetscInt        ghost = -1;
2810b81db932SToby Isaac     PetscInt        numChildren, numCells, c;
2811b81db932SToby Isaac 
28129566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
28139566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
28149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2815b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
28169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
281706348e87SToby Isaac     if (numCells == 2) {
28189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2819b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2820b81db932SToby Isaac         PetscInt cell = fcells[c], off;
2821b81db932SToby Isaac 
2822e6885bbbSToby Isaac         if (cell >= cStart && cell < cEndInterior) {
28239566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(neighSec, cell, &off));
2824b81db932SToby Isaac           off += counter[cell - cStart]++;
2825b81db932SToby Isaac           neighbors[off][0] = f;
2826b81db932SToby Isaac           neighbors[off][1] = fcells[1 - c];
2827b81db932SToby Isaac         }
2828b81db932SToby Isaac       }
2829b81db932SToby Isaac     }
283006348e87SToby Isaac   }
28319566063dSJacob Faibussowitsch   PetscCall(PetscFree(counter));
28329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces * dim, &dx, maxNumFaces * dim, &grad, maxNumFaces, &gref));
2833b81db932SToby Isaac   for (c = cStart; c < cEndInterior; c++) {
2834317218b9SToby Isaac     PetscInt         numFaces, f, d, off, ghost = -1;
2835640bce14SSatish Balay     PetscFVCellGeom *cg;
2836b81db932SToby Isaac 
28379566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
28389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(neighSec, c, &numFaces));
28399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(neighSec, c, &off));
2840a79418b7SMatt McGurn 
2841a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
28429566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2843a79418b7SMatt McGurn     if (ghost >= 0) continue;
2844a79418b7SMatt McGurn 
284563a3b9bcSJacob Faibussowitsch     PetscCheck(numFaces >= dim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell %" PetscInt_FMT " has only %" PetscInt_FMT " faces, not enough for gradient reconstruction", c, numFaces);
2846b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2847640bce14SSatish Balay       PetscFVCellGeom *cg1;
2848b81db932SToby Isaac       PetscFVFaceGeom *fg;
2849b81db932SToby Isaac       const PetscInt  *fcells;
2850b81db932SToby Isaac       PetscInt         ncell, side, nface;
2851b81db932SToby Isaac 
2852b81db932SToby Isaac       nface = neighbors[off + f][0];
2853b81db932SToby Isaac       ncell = neighbors[off + f][1];
28549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, nface, &fcells));
2855b81db932SToby Isaac       side = (c != fcells[0]);
28569566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, nface, fgeom, &fg));
28579566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2858b81db932SToby Isaac       for (d = 0; d < dim; ++d) dx[f * dim + d] = cg1->centroid[d] - cg->centroid[d];
2859b81db932SToby Isaac       gref[f] = fg->grad[side]; /* Gradient reconstruction term will go here */
2860b81db932SToby Isaac     }
28619566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, numFaces, dx, grad));
2862b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2863b81db932SToby Isaac       for (d = 0; d < dim; ++d) gref[f][d] = grad[f * dim + d];
2864b81db932SToby Isaac     }
2865b81db932SToby Isaac   }
28669566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
28679566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&neighSec));
28689566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighbors));
28693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2870b81db932SToby Isaac }
2871b81db932SToby Isaac 
2872856ac710SMatthew G. Knepley /*@
2873856ac710SMatthew G. Knepley   DMPlexComputeGradientFVM - Compute geometric factors for gradient reconstruction, which are stored in the geometry data, and compute layout for gradient data
2874856ac710SMatthew G. Knepley 
287520f4b53cSBarry Smith   Collective
2876856ac710SMatthew G. Knepley 
28774165533cSJose E. Roman   Input Parameters:
287820f4b53cSBarry Smith + dm  - The `DMPLEX`
287920f4b53cSBarry Smith . fvm - The `PetscFV`
288020f4b53cSBarry Smith - cellGeometry - The face geometry from `DMPlexComputeCellGeometryFVM()`
2881856ac710SMatthew G. Knepley 
28826b867d5aSJose E. Roman   Input/Output Parameter:
288320f4b53cSBarry Smith . faceGeometry - The face geometry from `DMPlexComputeFaceGeometryFVM()`; on output
28846b867d5aSJose E. Roman                  the geometric factors for gradient calculation are inserted
28856b867d5aSJose E. Roman 
28866b867d5aSJose E. Roman   Output Parameter:
288720f4b53cSBarry Smith . dmGrad - The `DM` describing the layout of gradient data
2888856ac710SMatthew G. Knepley 
2889856ac710SMatthew G. Knepley   Level: developer
2890856ac710SMatthew G. Knepley 
289120f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexGetFaceGeometryFVM()`, `DMPlexGetCellGeometryFVM()`
2892856ac710SMatthew G. Knepley @*/
2893d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientFVM(DM dm, PetscFV fvm, Vec faceGeometry, Vec cellGeometry, DM *dmGrad)
2894d71ae5a4SJacob Faibussowitsch {
2895856ac710SMatthew G. Knepley   DM           dmFace, dmCell;
2896856ac710SMatthew G. Knepley   PetscScalar *fgeom, *cgeom;
2897b81db932SToby Isaac   PetscSection sectionGrad, parentSection;
2898856ac710SMatthew G. Knepley   PetscInt     dim, pdim, cStart, cEnd, cEndInterior, c;
2899856ac710SMatthew G. Knepley 
2900856ac710SMatthew G. Knepley   PetscFunctionBegin;
29019566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
29029566063dSJacob Faibussowitsch   PetscCall(PetscFVGetNumComponents(fvm, &pdim));
29039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
29049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2905856ac710SMatthew G. Knepley   /* Construct the interpolant corresponding to each face from the least-square solution over the cell neighborhood */
29069566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
29079566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
29089566063dSJacob Faibussowitsch   PetscCall(VecGetArray(faceGeometry, &fgeom));
29099566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cellGeometry, &cgeom));
29109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTree(dm, &parentSection, NULL, NULL, NULL, NULL));
2911b81db932SToby Isaac   if (!parentSection) {
29129566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2913b5a3613cSMatthew G. Knepley   } else {
29149566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal_Tree(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2915b81db932SToby Isaac   }
29169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(faceGeometry, &fgeom));
29179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cellGeometry, &cgeom));
2918856ac710SMatthew G. Knepley   /* Create storage for gradients */
29199566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, dmGrad));
29209566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &sectionGrad));
29219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionGrad, cStart, cEnd));
29229566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionGrad, c, pdim * dim));
29239566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionGrad));
29249566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*dmGrad, sectionGrad));
29259566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionGrad));
29263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2927856ac710SMatthew G. Knepley }
2928b27d5b9eSToby Isaac 
2929c501906fSMatthew G. Knepley /*@
2930c501906fSMatthew G. Knepley   DMPlexGetDataFVM - Retrieve precomputed cell geometry
2931c501906fSMatthew G. Knepley 
293220f4b53cSBarry Smith   Collective
2933c501906fSMatthew G. Knepley 
29344165533cSJose E. Roman   Input Parameters:
293520f4b53cSBarry Smith + dm  - The `DM`
293620f4b53cSBarry Smith - fv  - The `PetscFV`
2937c501906fSMatthew G. Knepley 
2938c501906fSMatthew G. Knepley   Output Parameters:
2939c501906fSMatthew G. Knepley + cellGeometry - The cell geometry
2940c501906fSMatthew G. Knepley . faceGeometry - The face geometry
29416b867d5aSJose E. Roman - gradDM       - The gradient matrices
2942c501906fSMatthew G. Knepley 
2943c501906fSMatthew G. Knepley   Level: developer
2944c501906fSMatthew G. Knepley 
294520f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeGeometryFVM()`
2946c501906fSMatthew G. Knepley @*/
2947d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetDataFVM(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM)
2948d71ae5a4SJacob Faibussowitsch {
2949b27d5b9eSToby Isaac   PetscObject cellgeomobj, facegeomobj;
2950b27d5b9eSToby Isaac 
2951b27d5b9eSToby Isaac   PetscFunctionBegin;
29529566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2953b27d5b9eSToby Isaac   if (!cellgeomobj) {
2954b27d5b9eSToby Isaac     Vec cellgeomInt, facegeomInt;
2955b27d5b9eSToby Isaac 
29569566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellgeomInt, &facegeomInt));
29579566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)dm, "DMPlex_cellgeom_fvm", (PetscObject)cellgeomInt));
29589566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)dm, "DMPlex_facegeom_fvm", (PetscObject)facegeomInt));
29599566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellgeomInt));
29609566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&facegeomInt));
29619566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2962b27d5b9eSToby Isaac   }
29639566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)dm, "DMPlex_facegeom_fvm", &facegeomobj));
2964b27d5b9eSToby Isaac   if (cellgeom) *cellgeom = (Vec)cellgeomobj;
2965b27d5b9eSToby Isaac   if (facegeom) *facegeom = (Vec)facegeomobj;
2966b27d5b9eSToby Isaac   if (gradDM) {
2967b27d5b9eSToby Isaac     PetscObject gradobj;
2968b27d5b9eSToby Isaac     PetscBool   computeGradients;
2969b27d5b9eSToby Isaac 
29709566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv, &computeGradients));
2971b27d5b9eSToby Isaac     if (!computeGradients) {
2972b27d5b9eSToby Isaac       *gradDM = NULL;
29733ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2974b27d5b9eSToby Isaac     }
29759566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "DMPlex_dmgrad_fvm", &gradobj));
2976b27d5b9eSToby Isaac     if (!gradobj) {
2977b27d5b9eSToby Isaac       DM dmGradInt;
2978b27d5b9eSToby Isaac 
29799566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeGradientFVM(dm, fv, (Vec)facegeomobj, (Vec)cellgeomobj, &dmGradInt));
29809566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "DMPlex_dmgrad_fvm", (PetscObject)dmGradInt));
29819566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmGradInt));
29829566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)dm, "DMPlex_dmgrad_fvm", &gradobj));
2983b27d5b9eSToby Isaac     }
2984b27d5b9eSToby Isaac     *gradDM = (DM)gradobj;
2985b27d5b9eSToby Isaac   }
29863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2987b27d5b9eSToby Isaac }
2988d6143a4eSToby Isaac 
2989d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCoordinatesToReference_NewtonUpdate(PetscInt dimC, PetscInt dimR, PetscScalar *J, PetscScalar *invJ, PetscScalar *work, PetscReal *resNeg, PetscReal *guess)
2990d71ae5a4SJacob Faibussowitsch {
29919d150b73SToby Isaac   PetscInt l, m;
29929d150b73SToby Isaac 
2993cd345991SToby Isaac   PetscFunctionBeginHot;
29949d150b73SToby Isaac   if (dimC == dimR && dimR <= 3) {
29959d150b73SToby Isaac     /* invert Jacobian, multiply */
29969d150b73SToby Isaac     PetscScalar det, idet;
29979d150b73SToby Isaac 
29989d150b73SToby Isaac     switch (dimR) {
2999d71ae5a4SJacob Faibussowitsch     case 1:
3000d71ae5a4SJacob Faibussowitsch       invJ[0] = 1. / J[0];
3001d71ae5a4SJacob Faibussowitsch       break;
30029d150b73SToby Isaac     case 2:
30039d150b73SToby Isaac       det     = J[0] * J[3] - J[1] * J[2];
30049d150b73SToby Isaac       idet    = 1. / det;
30059d150b73SToby Isaac       invJ[0] = J[3] * idet;
30069d150b73SToby Isaac       invJ[1] = -J[1] * idet;
30079d150b73SToby Isaac       invJ[2] = -J[2] * idet;
30089d150b73SToby Isaac       invJ[3] = J[0] * idet;
30099d150b73SToby Isaac       break;
30109371c9d4SSatish Balay     case 3: {
30119d150b73SToby Isaac       invJ[0] = J[4] * J[8] - J[5] * J[7];
30129d150b73SToby Isaac       invJ[1] = J[2] * J[7] - J[1] * J[8];
30139d150b73SToby Isaac       invJ[2] = J[1] * J[5] - J[2] * J[4];
30149d150b73SToby Isaac       det     = invJ[0] * J[0] + invJ[1] * J[3] + invJ[2] * J[6];
30159d150b73SToby Isaac       idet    = 1. / det;
30169d150b73SToby Isaac       invJ[0] *= idet;
30179d150b73SToby Isaac       invJ[1] *= idet;
30189d150b73SToby Isaac       invJ[2] *= idet;
30199d150b73SToby Isaac       invJ[3] = idet * (J[5] * J[6] - J[3] * J[8]);
30209d150b73SToby Isaac       invJ[4] = idet * (J[0] * J[8] - J[2] * J[6]);
30219d150b73SToby Isaac       invJ[5] = idet * (J[2] * J[3] - J[0] * J[5]);
30229d150b73SToby Isaac       invJ[6] = idet * (J[3] * J[7] - J[4] * J[6]);
30239d150b73SToby Isaac       invJ[7] = idet * (J[1] * J[6] - J[0] * J[7]);
30249d150b73SToby Isaac       invJ[8] = idet * (J[0] * J[4] - J[1] * J[3]);
30259371c9d4SSatish Balay     } break;
30269d150b73SToby Isaac     }
30279d150b73SToby Isaac     for (l = 0; l < dimR; l++) {
3028ad540459SPierre Jolivet       for (m = 0; m < dimC; m++) guess[l] += PetscRealPart(invJ[l * dimC + m]) * resNeg[m];
30299d150b73SToby Isaac     }
30309d150b73SToby Isaac   } else {
30319d150b73SToby Isaac #if defined(PETSC_USE_COMPLEX)
30329d150b73SToby Isaac     char transpose = 'C';
30339d150b73SToby Isaac #else
30349d150b73SToby Isaac     char transpose = 'T';
30359d150b73SToby Isaac #endif
30369d150b73SToby Isaac     PetscBLASInt m        = dimR;
30379d150b73SToby Isaac     PetscBLASInt n        = dimC;
30389d150b73SToby Isaac     PetscBLASInt one      = 1;
30399d150b73SToby Isaac     PetscBLASInt worksize = dimR * dimC, info;
30409d150b73SToby Isaac 
3041ad540459SPierre Jolivet     for (l = 0; l < dimC; l++) invJ[l] = resNeg[l];
30429d150b73SToby Isaac 
3043792fecdfSBarry Smith     PetscCallBLAS("LAPACKgels", LAPACKgels_(&transpose, &m, &n, &one, J, &m, invJ, &n, work, &worksize, &info));
304408401ef6SPierre Jolivet     PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELS");
30459d150b73SToby Isaac 
3046ad540459SPierre Jolivet     for (l = 0; l < dimR; l++) guess[l] += PetscRealPart(invJ[l]);
30479d150b73SToby Isaac   }
30483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30499d150b73SToby Isaac }
30509d150b73SToby Isaac 
3051d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCoordinatesToReference_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
3052d71ae5a4SJacob Faibussowitsch {
3053c0cbe899SToby Isaac   PetscInt     coordSize, i, j, k, l, m, maxIts = 7, numV = (1 << dimR);
30549d150b73SToby Isaac   PetscScalar *coordsScalar = NULL;
30559d150b73SToby Isaac   PetscReal   *cellData, *cellCoords, *cellCoeffs, *extJ, *resNeg;
30569d150b73SToby Isaac   PetscScalar *J, *invJ, *work;
30579d150b73SToby Isaac 
30589d150b73SToby Isaac   PetscFunctionBegin;
30599d150b73SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
30609566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
30611dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT, dimC * (1 << dimR), coordSize);
30629566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
30639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
30649d150b73SToby Isaac   cellCoords = &cellData[0];
30659d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
30669d150b73SToby Isaac   extJ       = &cellData[2 * coordSize];
30679d150b73SToby Isaac   resNeg     = &cellData[2 * coordSize + dimR];
30689d150b73SToby Isaac   invJ       = &J[dimR * dimC];
30699d150b73SToby Isaac   work       = &J[2 * dimR * dimC];
30709d150b73SToby Isaac   if (dimR == 2) {
30719d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
30729d150b73SToby Isaac 
30739d150b73SToby Isaac     for (i = 0; i < 4; i++) {
30749d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
30759d150b73SToby Isaac 
3076ad540459SPierre Jolivet       for (j = 0; j < dimC; j++) cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
30779d150b73SToby Isaac     }
30789d150b73SToby Isaac   } else if (dimR == 3) {
30799d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
30809d150b73SToby Isaac 
30819d150b73SToby Isaac     for (i = 0; i < 8; i++) {
30829d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
30839d150b73SToby Isaac 
3084ad540459SPierre Jolivet       for (j = 0; j < dimC; j++) cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
30859d150b73SToby Isaac     }
30869d150b73SToby Isaac   } else {
3087ad540459SPierre Jolivet     for (i = 0; i < coordSize; i++) cellCoords[i] = PetscRealPart(coordsScalar[i]);
30889d150b73SToby Isaac   }
30899d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
30909d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
30919d150b73SToby Isaac     PetscReal *swap;
30929d150b73SToby Isaac 
30939d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
30949d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
30959d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
30969d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
30979d150b73SToby Isaac       }
30989d150b73SToby Isaac     }
30999d150b73SToby Isaac 
31009d150b73SToby Isaac     if (i < dimR - 1) {
31019d150b73SToby Isaac       swap       = cellCoeffs;
31029d150b73SToby Isaac       cellCoeffs = cellCoords;
31039d150b73SToby Isaac       cellCoords = swap;
31049d150b73SToby Isaac     }
31059d150b73SToby Isaac   }
31069566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(refCoords, numPoints * dimR));
31079d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
31089d150b73SToby Isaac     for (i = 0; i < maxIts; i++) {
31099d150b73SToby Isaac       PetscReal *guess = &refCoords[dimR * j];
31109d150b73SToby Isaac 
31119d150b73SToby Isaac       /* compute -residual and Jacobian */
3112ad540459SPierre Jolivet       for (k = 0; k < dimC; k++) resNeg[k] = realCoords[dimC * j + k];
3113ad540459SPierre Jolivet       for (k = 0; k < dimC * dimR; k++) J[k] = 0.;
31149d150b73SToby Isaac       for (k = 0; k < numV; k++) {
31159d150b73SToby Isaac         PetscReal extCoord = 1.;
31169d150b73SToby Isaac         for (l = 0; l < dimR; l++) {
31179d150b73SToby Isaac           PetscReal coord = guess[l];
31189d150b73SToby Isaac           PetscInt  dep   = (k & (1 << l)) >> l;
31199d150b73SToby Isaac 
31209d150b73SToby Isaac           extCoord *= dep * coord + !dep;
31219d150b73SToby Isaac           extJ[l] = dep;
31229d150b73SToby Isaac 
31239d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
31249d150b73SToby Isaac             PetscReal coord = guess[m];
31259d150b73SToby Isaac             PetscInt  dep   = ((k & (1 << m)) >> m) && (m != l);
31269d150b73SToby Isaac             PetscReal mult  = dep * coord + !dep;
31279d150b73SToby Isaac 
31289d150b73SToby Isaac             extJ[l] *= mult;
31299d150b73SToby Isaac           }
31309d150b73SToby Isaac         }
31319d150b73SToby Isaac         for (l = 0; l < dimC; l++) {
31329d150b73SToby Isaac           PetscReal coeff = cellCoeffs[dimC * k + l];
31339d150b73SToby Isaac 
31349d150b73SToby Isaac           resNeg[l] -= coeff * extCoord;
3135ad540459SPierre Jolivet           for (m = 0; m < dimR; m++) J[dimR * l + m] += coeff * extJ[m];
31369d150b73SToby Isaac         }
31379d150b73SToby Isaac       }
313876bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
31390611203eSToby Isaac         PetscReal maxAbs = 0.;
31400611203eSToby Isaac 
3141ad540459SPierre Jolivet         for (l = 0; l < dimC; l++) maxAbs = PetscMax(maxAbs, PetscAbsReal(resNeg[l]));
314263a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n", cell, j, i, (double)maxAbs));
31430611203eSToby Isaac       }
31449d150b73SToby Isaac 
31459566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(dimC, dimR, J, invJ, work, resNeg, guess));
31469d150b73SToby Isaac     }
31479d150b73SToby Isaac   }
31489566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
31499566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
31509566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31529d150b73SToby Isaac }
31539d150b73SToby Isaac 
3154d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceToCoordinates_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
3155d71ae5a4SJacob Faibussowitsch {
31569d150b73SToby Isaac   PetscInt     coordSize, i, j, k, l, numV = (1 << dimR);
31579d150b73SToby Isaac   PetscScalar *coordsScalar = NULL;
31589d150b73SToby Isaac   PetscReal   *cellData, *cellCoords, *cellCoeffs;
31599d150b73SToby Isaac 
31609d150b73SToby Isaac   PetscFunctionBegin;
31619d150b73SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
31629566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31631dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT, dimC * (1 << dimR), coordSize);
31649566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
31659d150b73SToby Isaac   cellCoords = &cellData[0];
31669d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
31679d150b73SToby Isaac   if (dimR == 2) {
31689d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
31699d150b73SToby Isaac 
31709d150b73SToby Isaac     for (i = 0; i < 4; i++) {
31719d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
31729d150b73SToby Isaac 
3173ad540459SPierre Jolivet       for (j = 0; j < dimC; j++) cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
31749d150b73SToby Isaac     }
31759d150b73SToby Isaac   } else if (dimR == 3) {
31769d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
31779d150b73SToby Isaac 
31789d150b73SToby Isaac     for (i = 0; i < 8; i++) {
31799d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
31809d150b73SToby Isaac 
3181ad540459SPierre Jolivet       for (j = 0; j < dimC; j++) cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
31829d150b73SToby Isaac     }
31839d150b73SToby Isaac   } else {
3184ad540459SPierre Jolivet     for (i = 0; i < coordSize; i++) cellCoords[i] = PetscRealPart(coordsScalar[i]);
31859d150b73SToby Isaac   }
31869d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
31879d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
31889d150b73SToby Isaac     PetscReal *swap;
31899d150b73SToby Isaac 
31909d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
31919d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
31929d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
31939d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
31949d150b73SToby Isaac       }
31959d150b73SToby Isaac     }
31969d150b73SToby Isaac 
31979d150b73SToby Isaac     if (i < dimR - 1) {
31989d150b73SToby Isaac       swap       = cellCoeffs;
31999d150b73SToby Isaac       cellCoeffs = cellCoords;
32009d150b73SToby Isaac       cellCoords = swap;
32019d150b73SToby Isaac     }
32029d150b73SToby Isaac   }
32039566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(realCoords, numPoints * dimC));
32049d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32059d150b73SToby Isaac     const PetscReal *guess  = &refCoords[dimR * j];
32069d150b73SToby Isaac     PetscReal       *mapped = &realCoords[dimC * j];
32079d150b73SToby Isaac 
32089d150b73SToby Isaac     for (k = 0; k < numV; k++) {
32099d150b73SToby Isaac       PetscReal extCoord = 1.;
32109d150b73SToby Isaac       for (l = 0; l < dimR; l++) {
32119d150b73SToby Isaac         PetscReal coord = guess[l];
32129d150b73SToby Isaac         PetscInt  dep   = (k & (1 << l)) >> l;
32139d150b73SToby Isaac 
32149d150b73SToby Isaac         extCoord *= dep * coord + !dep;
32159d150b73SToby Isaac       }
32169d150b73SToby Isaac       for (l = 0; l < dimC; l++) {
32179d150b73SToby Isaac         PetscReal coeff = cellCoeffs[dimC * k + l];
32189d150b73SToby Isaac 
32199d150b73SToby Isaac         mapped[l] += coeff * extCoord;
32209d150b73SToby Isaac       }
32219d150b73SToby Isaac     }
32229d150b73SToby Isaac   }
32239566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
32249566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
32253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32269d150b73SToby Isaac }
32279d150b73SToby Isaac 
32289c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
3229d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCoordinatesToReference_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt Nc, PetscInt dimR)
3230d71ae5a4SJacob Faibussowitsch {
32319c3cf19fSMatthew G. Knepley   PetscInt     numComp, pdim, i, j, k, l, m, maxIter = 7, coordSize;
3232c6e120d1SToby Isaac   PetscScalar *nodes = NULL;
3233c6e120d1SToby Isaac   PetscReal   *invV, *modes;
3234c6e120d1SToby Isaac   PetscReal   *B, *D, *resNeg;
3235c6e120d1SToby Isaac   PetscScalar *J, *invJ, *work;
32369d150b73SToby Isaac 
32379d150b73SToby Isaac   PetscFunctionBegin;
32389566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32399566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
324063a3b9bcSJacob Faibussowitsch   PetscCheck(numComp == Nc, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "coordinate discretization must have as many components (%" PetscInt_FMT ") as embedding dimension (!= %" PetscInt_FMT ")", numComp, Nc);
32419566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32429d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32439566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, pdim, MPIU_REAL, &modes));
32449d150b73SToby Isaac   invV = fe->invV;
3245012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3246012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3247ad540459SPierre Jolivet     for (j = 0; j < pdim; ++j) modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
32489d150b73SToby Isaac   }
32499566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, pdim * Nc + pdim * Nc * dimR + Nc, MPIU_REAL, &B));
32509c3cf19fSMatthew G. Knepley   D      = &B[pdim * Nc];
32519c3cf19fSMatthew G. Knepley   resNeg = &D[pdim * Nc * dimR];
32529566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * Nc * dimR, MPIU_SCALAR, &J));
32539c3cf19fSMatthew G. Knepley   invJ = &J[Nc * dimR];
32549c3cf19fSMatthew G. Knepley   work = &invJ[Nc * dimR];
3255ad540459SPierre Jolivet   for (i = 0; i < numPoints * dimR; i++) refCoords[i] = 0.;
32569d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32579b1f03cbSToby Isaac     for (i = 0; i < maxIter; i++) { /* we could batch this so that we're not making big B and D arrays all the time */
32589d150b73SToby Isaac       PetscReal *guess = &refCoords[j * dimR];
32599566063dSJacob Faibussowitsch       PetscCall(PetscSpaceEvaluate(fe->basisSpace, 1, guess, B, D, NULL));
3260ad540459SPierre Jolivet       for (k = 0; k < Nc; k++) resNeg[k] = realCoords[j * Nc + k];
3261ad540459SPierre Jolivet       for (k = 0; k < Nc * dimR; k++) J[k] = 0.;
32629c3cf19fSMatthew G. Knepley       for (k = 0; k < pdim; k++) {
32639c3cf19fSMatthew G. Knepley         for (l = 0; l < Nc; l++) {
3264012b7cc6SMatthew G. Knepley           resNeg[l] -= modes[k] * B[k * Nc + l];
3265ad540459SPierre Jolivet           for (m = 0; m < dimR; m++) J[l * dimR + m] += modes[k] * D[(k * Nc + l) * dimR + m];
32669d150b73SToby Isaac         }
32679d150b73SToby Isaac       }
326876bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
32690611203eSToby Isaac         PetscReal maxAbs = 0.;
32700611203eSToby Isaac 
3271ad540459SPierre Jolivet         for (l = 0; l < Nc; l++) maxAbs = PetscMax(maxAbs, PetscAbsReal(resNeg[l]));
327263a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm, "cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n", cell, j, i, (double)maxAbs));
32730611203eSToby Isaac       }
32749566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(Nc, dimR, J, invJ, work, resNeg, guess));
32759d150b73SToby Isaac     }
32769d150b73SToby Isaac   }
32779566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * Nc * dimR, MPIU_SCALAR, &J));
32789566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, pdim * Nc + pdim * Nc * dimR + Nc, MPIU_REAL, &B));
32799566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_REAL, &modes));
32809566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32829d150b73SToby Isaac }
32839d150b73SToby Isaac 
32849c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
3285d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceToCoordinates_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt Nc, PetscInt dimR)
3286d71ae5a4SJacob Faibussowitsch {
32879c3cf19fSMatthew G. Knepley   PetscInt     numComp, pdim, i, j, k, l, coordSize;
3288c6e120d1SToby Isaac   PetscScalar *nodes = NULL;
3289c6e120d1SToby Isaac   PetscReal   *invV, *modes;
32909d150b73SToby Isaac   PetscReal   *B;
32919d150b73SToby Isaac 
32929d150b73SToby Isaac   PetscFunctionBegin;
32939566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32949566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
329563a3b9bcSJacob Faibussowitsch   PetscCheck(numComp == Nc, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "coordinate discretization must have as many components (%" PetscInt_FMT ") as embedding dimension (!= %" PetscInt_FMT ")", numComp, Nc);
32969566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32979d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32989566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, pdim, MPIU_REAL, &modes));
32999d150b73SToby Isaac   invV = fe->invV;
3300012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3301012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3302ad540459SPierre Jolivet     for (j = 0; j < pdim; ++j) modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
33039d150b73SToby Isaac   }
33049566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numPoints * pdim * Nc, MPIU_REAL, &B));
33059566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(fe->basisSpace, numPoints, refCoords, B, NULL, NULL));
3306ad540459SPierre Jolivet   for (i = 0; i < numPoints * Nc; i++) realCoords[i] = 0.;
33079d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
33089c3cf19fSMatthew G. Knepley     PetscReal *mapped = &realCoords[j * Nc];
33099d150b73SToby Isaac 
33109c3cf19fSMatthew G. Knepley     for (k = 0; k < pdim; k++) {
3311ad540459SPierre Jolivet       for (l = 0; l < Nc; l++) mapped[l] += modes[k] * B[(j * pdim + k) * Nc + l];
33129d150b73SToby Isaac     }
33139d150b73SToby Isaac   }
33149566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numPoints * pdim * Nc, MPIU_REAL, &B));
33159566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_REAL, &modes));
33169566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
33173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33189d150b73SToby Isaac }
33199d150b73SToby Isaac 
3320d6143a4eSToby Isaac /*@
3321d6143a4eSToby Isaac   DMPlexCoordinatesToReference - Pull coordinates back from the mesh to the reference element using a single element
3322d6143a4eSToby Isaac   map.  This inversion will be accurate inside the reference element, but may be inaccurate for mappings that do not
3323d6143a4eSToby Isaac   extend uniquely outside the reference cell (e.g, most non-affine maps)
3324d6143a4eSToby Isaac 
332520f4b53cSBarry Smith   Not Collective
3326d6143a4eSToby Isaac 
3327d6143a4eSToby Isaac   Input Parameters:
332820f4b53cSBarry Smith + dm         - The mesh, with coordinate maps defined either by a `PetscDS` for the coordinate `DM` (see `DMGetCoordinateDM()`) or
3329d6143a4eSToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
3330d6143a4eSToby Isaac                as a multilinear map for tensor-product elements
3331d6143a4eSToby Isaac . cell       - the cell whose map is used.
3332d6143a4eSToby Isaac . numPoints  - the number of points to locate
333320f4b53cSBarry Smith - realCoords - (numPoints x coordinate dimension) array of coordinates (see `DMGetCoordinateDim()`)
3334d6143a4eSToby Isaac 
33352fe279fdSBarry Smith   Output Parameter:
333620f4b53cSBarry Smith . refCoords  - (`numPoints` x `dimension`) array of reference coordinates (see `DMGetDimension()`)
33371b266c99SBarry Smith 
33381b266c99SBarry Smith   Level: intermediate
333973c9229bSMatthew Knepley 
334020f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexReferenceToCoordinates()`
3341d6143a4eSToby Isaac @*/
3342d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCoordinatesToReference(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[])
3343d71ae5a4SJacob Faibussowitsch {
3344485ad865SMatthew G. Knepley   PetscInt dimC, dimR, depth, cStart, cEnd, i;
33459d150b73SToby Isaac   DM       coordDM = NULL;
33469d150b73SToby Isaac   Vec      coords;
33479d150b73SToby Isaac   PetscFE  fe = NULL;
33489d150b73SToby Isaac 
3349d6143a4eSToby Isaac   PetscFunctionBegin;
33509d150b73SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
33519566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dimR));
33529566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimC));
33533ba16761SJacob Faibussowitsch   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(PETSC_SUCCESS);
33549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
33559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coords));
33569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordDM));
33579d150b73SToby Isaac   if (coordDM) {
33589d150b73SToby Isaac     PetscInt coordFields;
33599d150b73SToby Isaac 
33609566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM, &coordFields));
33619d150b73SToby Isaac     if (coordFields) {
33629d150b73SToby Isaac       PetscClassId id;
33639d150b73SToby Isaac       PetscObject  disc;
33649d150b73SToby Isaac 
33659566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM, 0, NULL, &disc));
33669566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &id));
3367ad540459SPierre Jolivet       if (id == PETSCFE_CLASSID) fe = (PetscFE)disc;
33689d150b73SToby Isaac     }
33699d150b73SToby Isaac   }
33709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
33711dca8a05SBarry Smith   PetscCheck(cell >= cStart && cell < cEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " not in cell range [%" PetscInt_FMT ",%" PetscInt_FMT ")", cell, cStart, cEnd);
33729d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
33739d150b73SToby Isaac     PetscInt  coneSize;
33749d150b73SToby Isaac     PetscBool isSimplex, isTensor;
33759d150b73SToby Isaac 
33769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
33779d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
33789d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
33799d150b73SToby Isaac     if (isSimplex) {
33809d150b73SToby Isaac       PetscReal detJ, *v0, *J, *invJ;
33819d150b73SToby Isaac 
33829566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33839d150b73SToby Isaac       J    = &v0[dimC];
33849d150b73SToby Isaac       invJ = &J[dimC * dimC];
33859566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, invJ, &detJ));
33869d150b73SToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the inverse affine transformation for each point */
3387c330f8ffSToby Isaac         const PetscReal x0[3] = {-1., -1., -1.};
3388c330f8ffSToby Isaac 
3389c330f8ffSToby Isaac         CoordinatesRealToRef(dimC, dimR, x0, v0, invJ, &realCoords[dimC * i], &refCoords[dimR * i]);
33909d150b73SToby Isaac       }
33919566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33929d150b73SToby Isaac     } else if (isTensor) {
33939566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_Tensor(coordDM, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
339463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unrecognized cone size %" PetscInt_FMT, coneSize);
33959d150b73SToby Isaac   } else {
33969566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesToReference_FE(coordDM, fe, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
33979d150b73SToby Isaac   }
33983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33999d150b73SToby Isaac }
34009d150b73SToby Isaac 
34019d150b73SToby Isaac /*@
34029d150b73SToby Isaac   DMPlexReferenceToCoordinates - Map references coordinates to coordinates in the the mesh for a single element map.
34039d150b73SToby Isaac 
340420f4b53cSBarry Smith   Not Collective
34059d150b73SToby Isaac 
34069d150b73SToby Isaac   Input Parameters:
34072fe279fdSBarry Smith + dm         - The mesh, with coordinate maps defined either by a PetscDS for the coordinate `DM` (see `DMGetCoordinateDM()`) or
34089d150b73SToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
34099d150b73SToby Isaac                as a multilinear map for tensor-product elements
34109d150b73SToby Isaac . cell       - the cell whose map is used.
34119d150b73SToby Isaac . numPoints  - the number of points to locate
34122fe279fdSBarry Smith - refCoords  - (numPoints x dimension) array of reference coordinates (see `DMGetDimension()`)
34139d150b73SToby Isaac 
34142fe279fdSBarry Smith   Output Parameter:
34152fe279fdSBarry Smith . realCoords - (numPoints x coordinate dimension) array of coordinates (see `DMGetCoordinateDim()`)
34161b266c99SBarry Smith 
34171b266c99SBarry Smith    Level: intermediate
341873c9229bSMatthew Knepley 
34192fe279fdSBarry Smith .seealso: `DMPLEX`, `DMPlexCoordinatesToReference()`
34209d150b73SToby Isaac @*/
3421d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceToCoordinates(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[])
3422d71ae5a4SJacob Faibussowitsch {
3423485ad865SMatthew G. Knepley   PetscInt dimC, dimR, depth, cStart, cEnd, i;
34249d150b73SToby Isaac   DM       coordDM = NULL;
34259d150b73SToby Isaac   Vec      coords;
34269d150b73SToby Isaac   PetscFE  fe = NULL;
34279d150b73SToby Isaac 
34289d150b73SToby Isaac   PetscFunctionBegin;
34299d150b73SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
34309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dimR));
34319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimC));
34323ba16761SJacob Faibussowitsch   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(PETSC_SUCCESS);
34339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
34349566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coords));
34359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &coordDM));
34369d150b73SToby Isaac   if (coordDM) {
34379d150b73SToby Isaac     PetscInt coordFields;
34389d150b73SToby Isaac 
34399566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM, &coordFields));
34409d150b73SToby Isaac     if (coordFields) {
34419d150b73SToby Isaac       PetscClassId id;
34429d150b73SToby Isaac       PetscObject  disc;
34439d150b73SToby Isaac 
34449566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM, 0, NULL, &disc));
34459566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &id));
3446ad540459SPierre Jolivet       if (id == PETSCFE_CLASSID) fe = (PetscFE)disc;
34479d150b73SToby Isaac     }
34489d150b73SToby Isaac   }
34499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
34501dca8a05SBarry Smith   PetscCheck(cell >= cStart && cell < cEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " not in cell range [%" PetscInt_FMT ",%" PetscInt_FMT ")", cell, cStart, cEnd);
34519d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
34529d150b73SToby Isaac     PetscInt  coneSize;
34539d150b73SToby Isaac     PetscBool isSimplex, isTensor;
34549d150b73SToby Isaac 
34559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
34569d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
34579d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
34589d150b73SToby Isaac     if (isSimplex) {
34599d150b73SToby Isaac       PetscReal detJ, *v0, *J;
34609d150b73SToby Isaac 
34619566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34629d150b73SToby Isaac       J = &v0[dimC];
34639566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, NULL, &detJ));
3464c330f8ffSToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the affine transformation for each point */
3465c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3466c330f8ffSToby Isaac 
3467c330f8ffSToby Isaac         CoordinatesRefToReal(dimC, dimR, xi0, v0, J, &refCoords[dimR * i], &realCoords[dimC * i]);
34689d150b73SToby Isaac       }
34699566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34709d150b73SToby Isaac     } else if (isTensor) {
34719566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates_Tensor(coordDM, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
347263a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unrecognized cone size %" PetscInt_FMT, coneSize);
34739d150b73SToby Isaac   } else {
34749566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates_FE(coordDM, fe, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
34759d150b73SToby Isaac   }
34763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3477d6143a4eSToby Isaac }
34780139fca9SMatthew G. Knepley 
34790139fca9SMatthew G. Knepley /*@C
34802fe279fdSBarry Smith   DMPlexRemapGeometry - This function maps the original `DM` coordinates to new coordinates.
34810139fca9SMatthew G. Knepley 
348220f4b53cSBarry Smith   Not Collective
34830139fca9SMatthew G. Knepley 
34840139fca9SMatthew G. Knepley   Input Parameters:
34852fe279fdSBarry Smith + dm      - The `DM`
34860139fca9SMatthew G. Knepley . time    - The time
34870139fca9SMatthew G. Knepley - func    - The function transforming current coordinates to new coordaintes
34880139fca9SMatthew G. Knepley 
348920f4b53cSBarry Smith    Calling sequence of `func`:
349020f4b53cSBarry Smith .vb
349120f4b53cSBarry Smith    void func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
349220f4b53cSBarry Smith              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
349320f4b53cSBarry Smith              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
349420f4b53cSBarry Smith              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
349520f4b53cSBarry Smith .ve
34960139fca9SMatthew G. Knepley +  dim          - The spatial dimension
34970139fca9SMatthew G. Knepley .  Nf           - The number of input fields (here 1)
34980139fca9SMatthew G. Knepley .  NfAux        - The number of input auxiliary fields
34990139fca9SMatthew G. Knepley .  uOff         - The offset of the coordinates in u[] (here 0)
35000139fca9SMatthew G. Knepley .  uOff_x       - The offset of the coordinates in u_x[] (here 0)
35010139fca9SMatthew G. Knepley .  u            - The coordinate values at this point in space
350220f4b53cSBarry Smith .  u_t          - The coordinate time derivative at this point in space (here `NULL`)
35030139fca9SMatthew G. Knepley .  u_x          - The coordinate derivatives at this point in space
35040139fca9SMatthew G. Knepley .  aOff         - The offset of each auxiliary field in u[]
35050139fca9SMatthew G. Knepley .  aOff_x       - The offset of each auxiliary field in u_x[]
35060139fca9SMatthew G. Knepley .  a            - The auxiliary field values at this point in space
350720f4b53cSBarry Smith .  a_t          - The auxiliary field time derivative at this point in space (or `NULL`)
35080139fca9SMatthew G. Knepley .  a_x          - The auxiliary field derivatives at this point in space
35090139fca9SMatthew G. Knepley .  t            - The current time
35100139fca9SMatthew G. Knepley .  x            - The coordinates of this point (here not used)
35110139fca9SMatthew G. Knepley .  numConstants - The number of constants
35120139fca9SMatthew G. Knepley .  constants    - The value of each constant
35130139fca9SMatthew G. Knepley -  f            - The new coordinates at this point in space
35140139fca9SMatthew G. Knepley 
35150139fca9SMatthew G. Knepley   Level: intermediate
35160139fca9SMatthew G. Knepley 
35172fe279fdSBarry Smith .seealso: `DMPLEX`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMProjectFieldLocal()`, `DMProjectFieldLabelLocal()`
35180139fca9SMatthew G. Knepley @*/
3519d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRemapGeometry(DM dm, PetscReal time, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
3520d71ae5a4SJacob Faibussowitsch {
35210139fca9SMatthew G. Knepley   DM      cdm;
35228bf1a49fSMatthew G. Knepley   DMField cf;
35230139fca9SMatthew G. Knepley   Vec     lCoords, tmpCoords;
35240139fca9SMatthew G. Knepley 
35250139fca9SMatthew G. Knepley   PetscFunctionBegin;
35269566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35279566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35289566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(cdm, &tmpCoords));
35299566063dSJacob Faibussowitsch   PetscCall(VecCopy(lCoords, tmpCoords));
35308bf1a49fSMatthew G. Knepley   /* We have to do the coordinate field manually right now since the coordinate DM will not have its own */
35319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &cf));
35326858538eSMatthew G. Knepley   cdm->coordinates[0].field = cf;
35339566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(cdm, time, tmpCoords, &func, INSERT_VALUES, lCoords));
35346858538eSMatthew G. Knepley   cdm->coordinates[0].field = NULL;
35359566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(cdm, &tmpCoords));
35369566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, lCoords));
35373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35380139fca9SMatthew G. Knepley }
35390139fca9SMatthew G. Knepley 
35400139fca9SMatthew G. Knepley /* Shear applies the transformation, assuming we fix z,
35410139fca9SMatthew G. Knepley   / 1  0  m_0 \
35420139fca9SMatthew G. Knepley   | 0  1  m_1 |
35430139fca9SMatthew G. Knepley   \ 0  0   1  /
35440139fca9SMatthew G. Knepley */
3545d71ae5a4SJacob Faibussowitsch static void f0_shear(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar coords[])
3546d71ae5a4SJacob Faibussowitsch {
35470139fca9SMatthew G. Knepley   const PetscInt Nc = uOff[1] - uOff[0];
3548c1f1bd54SMatthew G. Knepley   const PetscInt ax = (PetscInt)PetscRealPart(constants[0]);
35490139fca9SMatthew G. Knepley   PetscInt       c;
35500139fca9SMatthew G. Knepley 
3551ad540459SPierre Jolivet   for (c = 0; c < Nc; ++c) coords[c] = u[c] + constants[c + 1] * u[ax];
35520139fca9SMatthew G. Knepley }
35530139fca9SMatthew G. Knepley 
35540139fca9SMatthew G. Knepley /*@C
35550139fca9SMatthew G. Knepley   DMPlexShearGeometry - This shears the domain, meaning adds a multiple of the shear coordinate to all other coordinates.
35560139fca9SMatthew G. Knepley 
355720f4b53cSBarry Smith   Not Collective
35580139fca9SMatthew G. Knepley 
35590139fca9SMatthew G. Knepley   Input Parameters:
356020f4b53cSBarry Smith + dm          - The `DMPLEX`
35613ee9839eSMatthew G. Knepley . direction   - The shear coordinate direction, e.g. 0 is the x-axis
35620139fca9SMatthew G. Knepley - multipliers - The multiplier m for each direction which is not the shear direction
35630139fca9SMatthew G. Knepley 
35640139fca9SMatthew G. Knepley   Level: intermediate
35650139fca9SMatthew G. Knepley 
356620f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexRemapGeometry()`
35670139fca9SMatthew G. Knepley @*/
3568d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexShearGeometry(DM dm, DMDirection direction, PetscReal multipliers[])
3569d71ae5a4SJacob Faibussowitsch {
35700139fca9SMatthew G. Knepley   DM             cdm;
35710139fca9SMatthew G. Knepley   PetscDS        cds;
35720139fca9SMatthew G. Knepley   PetscObject    obj;
35730139fca9SMatthew G. Knepley   PetscClassId   id;
35740139fca9SMatthew G. Knepley   PetscScalar   *moduli;
35753ee9839eSMatthew G. Knepley   const PetscInt dir = (PetscInt)direction;
35760139fca9SMatthew G. Knepley   PetscInt       dE, d, e;
35770139fca9SMatthew G. Knepley 
35780139fca9SMatthew G. Knepley   PetscFunctionBegin;
35799566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35809566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
35819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dE + 1, &moduli));
35820139fca9SMatthew G. Knepley   moduli[0] = dir;
3583cdaaecf7SMatthew G. Knepley   for (d = 0, e = 0; d < dE; ++d) moduli[d + 1] = d == dir ? 0.0 : (multipliers ? multipliers[e++] : 1.0);
35849566063dSJacob Faibussowitsch   PetscCall(DMGetDS(cdm, &cds));
35859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
35869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetClassId(obj, &id));
35870139fca9SMatthew G. Knepley   if (id != PETSCFE_CLASSID) {
35880139fca9SMatthew G. Knepley     Vec          lCoords;
35890139fca9SMatthew G. Knepley     PetscSection cSection;
35900139fca9SMatthew G. Knepley     PetscScalar *coords;
35910139fca9SMatthew G. Knepley     PetscInt     vStart, vEnd, v;
35920139fca9SMatthew G. Knepley 
35939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
35949566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &cSection));
35959566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35969566063dSJacob Faibussowitsch     PetscCall(VecGetArray(lCoords, &coords));
35970139fca9SMatthew G. Knepley     for (v = vStart; v < vEnd; ++v) {
35980139fca9SMatthew G. Knepley       PetscReal ds;
35990139fca9SMatthew G. Knepley       PetscInt  off, c;
36000139fca9SMatthew G. Knepley 
36019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSection, v, &off));
36020139fca9SMatthew G. Knepley       ds = PetscRealPart(coords[off + dir]);
36030139fca9SMatthew G. Knepley       for (c = 0; c < dE; ++c) coords[off + c] += moduli[c] * ds;
36040139fca9SMatthew G. Knepley     }
36059566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(lCoords, &coords));
36060139fca9SMatthew G. Knepley   } else {
36079566063dSJacob Faibussowitsch     PetscCall(PetscDSSetConstants(cds, dE + 1, moduli));
36089566063dSJacob Faibussowitsch     PetscCall(DMPlexRemapGeometry(dm, 0.0, f0_shear));
36090139fca9SMatthew G. Knepley   }
36109566063dSJacob Faibussowitsch   PetscCall(PetscFree(moduli));
36113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36120139fca9SMatthew G. Knepley }
3613