xref: /petsc/src/dm/impls/plex/plexgeometry.c (revision f5867de0deb04366ef9403a8f3b20f22ff5eb562)
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 
93985bb02SVaclav Hapla   Not Collective (provided DMGetCoordinatesLocalSetUp() has been called already)
103985bb02SVaclav Hapla 
113985bb02SVaclav Hapla   Input Parameters:
123985bb02SVaclav Hapla + dm - The DMPlex object
13d3e1f4ccSVaclav Hapla . coordinates - The Vec of coordinates of the sought points
143985bb02SVaclav Hapla - eps - The tolerance or PETSC_DEFAULT
153985bb02SVaclav Hapla 
163985bb02SVaclav Hapla   Output Parameters:
17d3e1f4ccSVaclav Hapla . points - The IS of found DAG points or -1
183985bb02SVaclav Hapla 
193985bb02SVaclav Hapla   Level: intermediate
203985bb02SVaclav Hapla 
213985bb02SVaclav Hapla   Notes:
22d3e1f4ccSVaclav Hapla   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 
24d3e1f4ccSVaclav Hapla   The output IS is living on PETSC_COMM_SELF and its length is npoints.
25d3e1f4ccSVaclav Hapla   Each rank does the search independently.
26d3e1f4ccSVaclav Hapla   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 
28d3e1f4ccSVaclav Hapla   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 
34db781477SPatrick Sanan .seealso: `DMPlexCreate()`, `DMGetCoordinatesLocal()`
353985bb02SVaclav Hapla @*/
36d3e1f4ccSVaclav Hapla PetscErrorCode DMPlexFindVertices(DM dm, Vec coordinates, PetscReal eps, IS *points)
373985bb02SVaclav Hapla {
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;
9137900f7dSMatthew G. Knepley         for (c = 0; c < cdim; c++) {
92d3e1f4ccSVaclav Hapla           norm += PetscRealPart(PetscSqr(coord[j+c] - allCoords[o+c]));
933985bb02SVaclav Hapla         }
943985bb02SVaclav Hapla         norm = PetscSqrtReal(norm);
953985bb02SVaclav Hapla         if (norm <= eps) {
963985bb02SVaclav Hapla           dagPoints[i] = p;
973985bb02SVaclav Hapla           break;
983985bb02SVaclav Hapla         }
993985bb02SVaclav Hapla       }
1003985bb02SVaclav Hapla     }
101d3e1f4ccSVaclav Hapla   }
1029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(allCoordsVec, &allCoords));
1039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coord));
1049566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, npoints, dagPoints, PETSC_OWN_POINTER, points));
1053985bb02SVaclav Hapla   PetscFunctionReturn(0);
1063985bb02SVaclav Hapla }
1073985bb02SVaclav Hapla 
108fea14342SMatthew G. Knepley static PetscErrorCode DMPlexGetLineIntersection_2D_Internal(const PetscReal segmentA[], const PetscReal segmentB[], PetscReal intersection[], PetscBool *hasIntersection)
109fea14342SMatthew G. Knepley {
110fea14342SMatthew G. Knepley   const PetscReal p0_x  = segmentA[0*2+0];
111fea14342SMatthew G. Knepley   const PetscReal p0_y  = segmentA[0*2+1];
112fea14342SMatthew G. Knepley   const PetscReal p1_x  = segmentA[1*2+0];
113fea14342SMatthew G. Knepley   const PetscReal p1_y  = segmentA[1*2+1];
114fea14342SMatthew G. Knepley   const PetscReal p2_x  = segmentB[0*2+0];
115fea14342SMatthew G. Knepley   const PetscReal p2_y  = segmentB[0*2+1];
116fea14342SMatthew G. Knepley   const PetscReal p3_x  = segmentB[1*2+0];
117fea14342SMatthew G. Knepley   const PetscReal p3_y  = segmentB[1*2+1];
118fea14342SMatthew G. Knepley   const PetscReal s1_x  = p1_x - p0_x;
119fea14342SMatthew G. Knepley   const PetscReal s1_y  = p1_y - p0_y;
120fea14342SMatthew G. Knepley   const PetscReal s2_x  = p3_x - p2_x;
121fea14342SMatthew G. Knepley   const PetscReal s2_y  = p3_y - p2_y;
122fea14342SMatthew G. Knepley   const PetscReal denom = (-s2_x * s1_y + s1_x * s2_y);
123fea14342SMatthew G. Knepley 
124fea14342SMatthew G. Knepley   PetscFunctionBegin;
125fea14342SMatthew G. Knepley   *hasIntersection = PETSC_FALSE;
126fea14342SMatthew G. Knepley   /* Non-parallel lines */
127fea14342SMatthew G. Knepley   if (denom != 0.0) {
128fea14342SMatthew G. Knepley     const PetscReal s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / denom;
129fea14342SMatthew G. Knepley     const PetscReal t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / denom;
130fea14342SMatthew G. Knepley 
131fea14342SMatthew G. Knepley     if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
132fea14342SMatthew G. Knepley       *hasIntersection = PETSC_TRUE;
133fea14342SMatthew G. Knepley       if (intersection) {
134fea14342SMatthew G. Knepley         intersection[0] = p0_x + (t * s1_x);
135fea14342SMatthew G. Knepley         intersection[1] = p0_y + (t * s1_y);
136fea14342SMatthew G. Knepley       }
137fea14342SMatthew G. Knepley     }
138fea14342SMatthew G. Knepley   }
139fea14342SMatthew G. Knepley   PetscFunctionReturn(0);
140fea14342SMatthew G. Knepley }
141fea14342SMatthew G. Knepley 
142ddce0771SMatthew G. Knepley /* The plane is segmentB x segmentC: https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection */
143ddce0771SMatthew G. Knepley static PetscErrorCode DMPlexGetLinePlaneIntersection_3D_Internal(const PetscReal segmentA[], const PetscReal segmentB[], const PetscReal segmentC[], PetscReal intersection[], PetscBool *hasIntersection)
144ddce0771SMatthew G. Knepley {
145ddce0771SMatthew G. Knepley   const PetscReal p0_x  = segmentA[0*3+0];
146ddce0771SMatthew G. Knepley   const PetscReal p0_y  = segmentA[0*3+1];
147ddce0771SMatthew G. Knepley   const PetscReal p0_z  = segmentA[0*3+2];
148ddce0771SMatthew G. Knepley   const PetscReal p1_x  = segmentA[1*3+0];
149ddce0771SMatthew G. Knepley   const PetscReal p1_y  = segmentA[1*3+1];
150ddce0771SMatthew G. Knepley   const PetscReal p1_z  = segmentA[1*3+2];
151ddce0771SMatthew G. Knepley   const PetscReal q0_x  = segmentB[0*3+0];
152ddce0771SMatthew G. Knepley   const PetscReal q0_y  = segmentB[0*3+1];
153ddce0771SMatthew G. Knepley   const PetscReal q0_z  = segmentB[0*3+2];
154ddce0771SMatthew G. Knepley   const PetscReal q1_x  = segmentB[1*3+0];
155ddce0771SMatthew G. Knepley   const PetscReal q1_y  = segmentB[1*3+1];
156ddce0771SMatthew G. Knepley   const PetscReal q1_z  = segmentB[1*3+2];
157ddce0771SMatthew G. Knepley   const PetscReal r0_x  = segmentC[0*3+0];
158ddce0771SMatthew G. Knepley   const PetscReal r0_y  = segmentC[0*3+1];
159ddce0771SMatthew G. Knepley   const PetscReal r0_z  = segmentC[0*3+2];
160ddce0771SMatthew G. Knepley   const PetscReal r1_x  = segmentC[1*3+0];
161ddce0771SMatthew G. Knepley   const PetscReal r1_y  = segmentC[1*3+1];
162ddce0771SMatthew G. Knepley   const PetscReal r1_z  = segmentC[1*3+2];
163ddce0771SMatthew G. Knepley   const PetscReal s0_x  = p1_x - p0_x;
164ddce0771SMatthew G. Knepley   const PetscReal s0_y  = p1_y - p0_y;
165ddce0771SMatthew G. Knepley   const PetscReal s0_z  = p1_z - p0_z;
166ddce0771SMatthew G. Knepley   const PetscReal s1_x  = q1_x - q0_x;
167ddce0771SMatthew G. Knepley   const PetscReal s1_y  = q1_y - q0_y;
168ddce0771SMatthew G. Knepley   const PetscReal s1_z  = q1_z - q0_z;
169ddce0771SMatthew G. Knepley   const PetscReal s2_x  = r1_x - r0_x;
170ddce0771SMatthew G. Knepley   const PetscReal s2_y  = r1_y - r0_y;
171ddce0771SMatthew G. Knepley   const PetscReal s2_z  = r1_z - r0_z;
172ddce0771SMatthew G. Knepley   const PetscReal s3_x  = s1_y*s2_z - s1_z*s2_y; /* s1 x s2 */
173ddce0771SMatthew G. Knepley   const PetscReal s3_y  = s1_z*s2_x - s1_x*s2_z;
174ddce0771SMatthew G. Knepley   const PetscReal s3_z  = s1_x*s2_y - s1_y*s2_x;
175ddce0771SMatthew G. Knepley   const PetscReal s4_x  = s0_y*s2_z - s0_z*s2_y; /* s0 x s2 */
176ddce0771SMatthew G. Knepley   const PetscReal s4_y  = s0_z*s2_x - s0_x*s2_z;
177ddce0771SMatthew G. Knepley   const PetscReal s4_z  = s0_x*s2_y - s0_y*s2_x;
178ddce0771SMatthew G. Knepley   const PetscReal s5_x  = s1_y*s0_z - s1_z*s0_y; /* s1 x s0 */
179ddce0771SMatthew G. Knepley   const PetscReal s5_y  = s1_z*s0_x - s1_x*s0_z;
180ddce0771SMatthew G. Knepley   const PetscReal s5_z  = s1_x*s0_y - s1_y*s0_x;
181ddce0771SMatthew G. Knepley   const PetscReal denom = -(s0_x*s3_x + s0_y*s3_y + s0_z*s3_z); /* -s0 . (s1 x s2) */
182ddce0771SMatthew G. Knepley 
183ddce0771SMatthew G. Knepley   PetscFunctionBegin;
184ddce0771SMatthew G. Knepley   *hasIntersection = PETSC_FALSE;
185ddce0771SMatthew G. Knepley   /* Line not parallel to plane */
186ddce0771SMatthew G. Knepley   if (denom != 0.0) {
187ddce0771SMatthew G. Knepley     const PetscReal t = (s3_x * (p0_x - q0_x) + s3_y * (p0_y - q0_y) + s3_z * (p0_z - q0_z)) / denom;
188ddce0771SMatthew G. Knepley     const PetscReal u = (s4_x * (p0_x - q0_x) + s4_y * (p0_y - q0_y) + s4_z * (p0_z - q0_z)) / denom;
189ddce0771SMatthew G. Knepley     const PetscReal v = (s5_x * (p0_x - q0_x) + s5_y * (p0_y - q0_y) + s5_z * (p0_z - q0_z)) / denom;
190ddce0771SMatthew G. Knepley 
191ddce0771SMatthew G. Knepley     if (t >= 0 && t <= 1 && u >= 0 && u <= 1 && v >= 0 && v <= 1) {
192ddce0771SMatthew G. Knepley       *hasIntersection = PETSC_TRUE;
193ddce0771SMatthew G. Knepley       if (intersection) {
194ddce0771SMatthew G. Knepley         intersection[0] = p0_x + (t * s0_x);
195ddce0771SMatthew G. Knepley         intersection[1] = p0_y + (t * s0_y);
196ddce0771SMatthew G. Knepley         intersection[2] = p0_z + (t * s0_z);
197ddce0771SMatthew G. Knepley       }
198ddce0771SMatthew G. Knepley     }
199ddce0771SMatthew G. Knepley   }
200ddce0771SMatthew G. Knepley   PetscFunctionReturn(0);
201ddce0771SMatthew G. Knepley }
202ddce0771SMatthew G. Knepley 
20314bbb9f0SLawrence Mitchell static PetscErrorCode DMPlexLocatePoint_Simplex_1D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
20414bbb9f0SLawrence Mitchell {
20514bbb9f0SLawrence Mitchell   const PetscReal eps = PETSC_SQRT_MACHINE_EPSILON;
20614bbb9f0SLawrence Mitchell   const PetscReal x   = PetscRealPart(point[0]);
20714bbb9f0SLawrence Mitchell   PetscReal       v0, J, invJ, detJ;
20814bbb9f0SLawrence Mitchell   PetscReal       xi;
20914bbb9f0SLawrence Mitchell 
21014bbb9f0SLawrence Mitchell   PetscFunctionBegin;
2119566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
21214bbb9f0SLawrence Mitchell   xi   = invJ*(x - v0);
21314bbb9f0SLawrence Mitchell 
21414bbb9f0SLawrence Mitchell   if ((xi >= -eps) && (xi <= 2.+eps)) *cell = c;
21514bbb9f0SLawrence Mitchell   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
21614bbb9f0SLawrence Mitchell   PetscFunctionReturn(0);
21714bbb9f0SLawrence Mitchell }
21814bbb9f0SLawrence Mitchell 
219ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexLocatePoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
220ccd2543fSMatthew G Knepley {
221ccd2543fSMatthew G Knepley   const PetscInt  embedDim = 2;
222f5ebc837SMatthew G. Knepley   const PetscReal eps      = PETSC_SQRT_MACHINE_EPSILON;
223ccd2543fSMatthew G Knepley   PetscReal       x        = PetscRealPart(point[0]);
224ccd2543fSMatthew G Knepley   PetscReal       y        = PetscRealPart(point[1]);
225ccd2543fSMatthew G Knepley   PetscReal       v0[2], J[4], invJ[4], detJ;
226ccd2543fSMatthew G Knepley   PetscReal       xi, eta;
227ccd2543fSMatthew G Knepley 
228ccd2543fSMatthew G Knepley   PetscFunctionBegin;
2299566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
230ccd2543fSMatthew G Knepley   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
231ccd2543fSMatthew G Knepley   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
232ccd2543fSMatthew G Knepley 
233f5ebc837SMatthew G. Knepley   if ((xi >= -eps) && (eta >= -eps) && (xi + eta <= 2.0+eps)) *cell = c;
234c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
235ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
236ccd2543fSMatthew G Knepley }
237ccd2543fSMatthew G Knepley 
23862a38674SMatthew G. Knepley static PetscErrorCode DMPlexClosestPoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscReal cpoint[])
23962a38674SMatthew G. Knepley {
24062a38674SMatthew G. Knepley   const PetscInt  embedDim = 2;
24162a38674SMatthew G. Knepley   PetscReal       x        = PetscRealPart(point[0]);
24262a38674SMatthew G. Knepley   PetscReal       y        = PetscRealPart(point[1]);
24362a38674SMatthew G. Knepley   PetscReal       v0[2], J[4], invJ[4], detJ;
24462a38674SMatthew G. Knepley   PetscReal       xi, eta, r;
24562a38674SMatthew G. Knepley 
24662a38674SMatthew G. Knepley   PetscFunctionBegin;
2479566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
24862a38674SMatthew G. Knepley   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
24962a38674SMatthew G. Knepley   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
25062a38674SMatthew G. Knepley 
25162a38674SMatthew G. Knepley   xi  = PetscMax(xi,  0.0);
25262a38674SMatthew G. Knepley   eta = PetscMax(eta, 0.0);
25362a38674SMatthew G. Knepley   if (xi + eta > 2.0) {
25462a38674SMatthew G. Knepley     r    = (xi + eta)/2.0;
25562a38674SMatthew G. Knepley     xi  /= r;
25662a38674SMatthew G. Knepley     eta /= r;
25762a38674SMatthew G. Knepley   }
25862a38674SMatthew G. Knepley   cpoint[0] = J[0*embedDim+0]*xi + J[0*embedDim+1]*eta + v0[0];
25962a38674SMatthew G. Knepley   cpoint[1] = J[1*embedDim+0]*xi + J[1*embedDim+1]*eta + v0[1];
26062a38674SMatthew G. Knepley   PetscFunctionReturn(0);
26162a38674SMatthew G. Knepley }
26262a38674SMatthew G. Knepley 
263ba2698f1SMatthew G. Knepley static PetscErrorCode DMPlexLocatePoint_Quad_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
264ccd2543fSMatthew G Knepley {
265ccd2543fSMatthew G Knepley   PetscSection       coordSection;
266ccd2543fSMatthew G Knepley   Vec             coordsLocal;
267a1e44745SMatthew G. Knepley   PetscScalar    *coords = NULL;
268ccd2543fSMatthew G Knepley   const PetscInt  faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
269ccd2543fSMatthew G Knepley   PetscReal       x         = PetscRealPart(point[0]);
270ccd2543fSMatthew G Knepley   PetscReal       y         = PetscRealPart(point[1]);
271ccd2543fSMatthew G Knepley   PetscInt        crossings = 0, f;
272ccd2543fSMatthew G Knepley 
273ccd2543fSMatthew G Knepley   PetscFunctionBegin;
2749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
2759566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2769566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords));
277ccd2543fSMatthew G Knepley   for (f = 0; f < 4; ++f) {
278ccd2543fSMatthew G Knepley     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
279ccd2543fSMatthew G Knepley     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
280ccd2543fSMatthew G Knepley     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
281ccd2543fSMatthew G Knepley     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
282ccd2543fSMatthew G Knepley     PetscReal slope = (y_j - y_i) / (x_j - x_i);
283ccd2543fSMatthew G Knepley     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
284ccd2543fSMatthew G Knepley     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
285ccd2543fSMatthew G Knepley     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
286ccd2543fSMatthew G Knepley     if ((cond1 || cond2)  && above) ++crossings;
287ccd2543fSMatthew G Knepley   }
288ccd2543fSMatthew G Knepley   if (crossings % 2) *cell = c;
289c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
2909566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords));
291ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
292ccd2543fSMatthew G Knepley }
293ccd2543fSMatthew G Knepley 
294ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexLocatePoint_Simplex_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
295ccd2543fSMatthew G Knepley {
296ccd2543fSMatthew G Knepley   const PetscInt  embedDim = 3;
29737900f7dSMatthew G. Knepley   const PetscReal eps      = PETSC_SQRT_MACHINE_EPSILON;
298ccd2543fSMatthew G Knepley   PetscReal       v0[3], J[9], invJ[9], detJ;
299ccd2543fSMatthew G Knepley   PetscReal       x = PetscRealPart(point[0]);
300ccd2543fSMatthew G Knepley   PetscReal       y = PetscRealPart(point[1]);
301ccd2543fSMatthew G Knepley   PetscReal       z = PetscRealPart(point[2]);
302ccd2543fSMatthew G Knepley   PetscReal       xi, eta, zeta;
303ccd2543fSMatthew G Knepley 
304ccd2543fSMatthew G Knepley   PetscFunctionBegin;
3059566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
306ccd2543fSMatthew G Knepley   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
307ccd2543fSMatthew G Knepley   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
308ccd2543fSMatthew G Knepley   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
309ccd2543fSMatthew G Knepley 
31037900f7dSMatthew G. Knepley   if ((xi >= -eps) && (eta >= -eps) && (zeta >= -eps) && (xi + eta + zeta <= 2.0+eps)) *cell = c;
311c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
312ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
313ccd2543fSMatthew G Knepley }
314ccd2543fSMatthew G Knepley 
315ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexLocatePoint_General_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
316ccd2543fSMatthew G Knepley {
317ccd2543fSMatthew G Knepley   PetscSection   coordSection;
318ccd2543fSMatthew G Knepley   Vec            coordsLocal;
319872a9804SMatthew G. Knepley   PetscScalar   *coords = NULL;
320fb150da6SMatthew G. Knepley   const PetscInt faces[24] = {0, 3, 2, 1,  5, 4, 7, 6,  3, 0, 4, 5,
321fb150da6SMatthew G. Knepley                               1, 2, 6, 7,  3, 5, 6, 2,  0, 1, 7, 4};
322ccd2543fSMatthew G Knepley   PetscBool      found = PETSC_TRUE;
323ccd2543fSMatthew G Knepley   PetscInt       f;
324ccd2543fSMatthew G Knepley 
325ccd2543fSMatthew G Knepley   PetscFunctionBegin;
3269566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
3279566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
3289566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords));
329ccd2543fSMatthew G Knepley   for (f = 0; f < 6; ++f) {
330ccd2543fSMatthew G Knepley     /* Check the point is under plane */
331ccd2543fSMatthew G Knepley     /*   Get face normal */
332ccd2543fSMatthew G Knepley     PetscReal v_i[3];
333ccd2543fSMatthew G Knepley     PetscReal v_j[3];
334ccd2543fSMatthew G Knepley     PetscReal normal[3];
335ccd2543fSMatthew G Knepley     PetscReal pp[3];
336ccd2543fSMatthew G Knepley     PetscReal dot;
337ccd2543fSMatthew G Knepley 
338ccd2543fSMatthew G Knepley     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
339ccd2543fSMatthew G Knepley     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
340ccd2543fSMatthew G Knepley     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
341ccd2543fSMatthew G Knepley     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
342ccd2543fSMatthew G Knepley     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
343ccd2543fSMatthew G Knepley     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
344ccd2543fSMatthew G Knepley     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
345ccd2543fSMatthew G Knepley     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
346ccd2543fSMatthew G Knepley     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
347ccd2543fSMatthew G Knepley     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
348ccd2543fSMatthew G Knepley     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
349ccd2543fSMatthew G Knepley     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
350ccd2543fSMatthew G Knepley     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
351ccd2543fSMatthew G Knepley 
352ccd2543fSMatthew G Knepley     /* Check that projected point is in face (2D location problem) */
353ccd2543fSMatthew G Knepley     if (dot < 0.0) {
354ccd2543fSMatthew G Knepley       found = PETSC_FALSE;
355ccd2543fSMatthew G Knepley       break;
356ccd2543fSMatthew G Knepley     }
357ccd2543fSMatthew G Knepley   }
358ccd2543fSMatthew G Knepley   if (found) *cell = c;
359c1496c66SMatthew G. Knepley   else *cell = DMLOCATEPOINT_POINT_NOT_FOUND;
3609566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords));
361ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
362ccd2543fSMatthew G Knepley }
363ccd2543fSMatthew G Knepley 
364c4eade1cSMatthew G. Knepley static PetscErrorCode PetscGridHashInitialize_Internal(PetscGridHash box, PetscInt dim, const PetscScalar point[])
365c4eade1cSMatthew G. Knepley {
366c4eade1cSMatthew G. Knepley   PetscInt d;
367c4eade1cSMatthew G. Knepley 
368c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
369c4eade1cSMatthew G. Knepley   box->dim = dim;
370c4eade1cSMatthew G. Knepley   for (d = 0; d < dim; ++d) box->lower[d] = box->upper[d] = PetscRealPart(point[d]);
371c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
372c4eade1cSMatthew G. Knepley }
373c4eade1cSMatthew G. Knepley 
374c4eade1cSMatthew G. Knepley PetscErrorCode PetscGridHashCreate(MPI_Comm comm, PetscInt dim, const PetscScalar point[], PetscGridHash *box)
375c4eade1cSMatthew G. Knepley {
376c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
3779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, box));
3789566063dSJacob Faibussowitsch   PetscCall(PetscGridHashInitialize_Internal(*box, dim, point));
379c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
380c4eade1cSMatthew G. Knepley }
381c4eade1cSMatthew G. Knepley 
382c4eade1cSMatthew G. Knepley PetscErrorCode PetscGridHashEnlarge(PetscGridHash box, const PetscScalar point[])
383c4eade1cSMatthew G. Knepley {
384c4eade1cSMatthew G. Knepley   PetscInt d;
385c4eade1cSMatthew G. Knepley 
386c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
387c4eade1cSMatthew G. Knepley   for (d = 0; d < box->dim; ++d) {
388c4eade1cSMatthew G. Knepley     box->lower[d] = PetscMin(box->lower[d], PetscRealPart(point[d]));
389c4eade1cSMatthew G. Knepley     box->upper[d] = PetscMax(box->upper[d], PetscRealPart(point[d]));
390c4eade1cSMatthew G. Knepley   }
391c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
392c4eade1cSMatthew G. Knepley }
393c4eade1cSMatthew G. Knepley 
39462a38674SMatthew G. Knepley /*
39562a38674SMatthew G. Knepley   PetscGridHashSetGrid - Divide the grid into boxes
39662a38674SMatthew G. Knepley 
39762a38674SMatthew G. Knepley   Not collective
39862a38674SMatthew G. Knepley 
39962a38674SMatthew G. Knepley   Input Parameters:
40062a38674SMatthew G. Knepley + box - The grid hash object
40162a38674SMatthew G. Knepley . n   - The number of boxes in each dimension, or PETSC_DETERMINE
40262a38674SMatthew G. Knepley - h   - The box size in each dimension, only used if n[d] == PETSC_DETERMINE
40362a38674SMatthew G. Knepley 
40462a38674SMatthew G. Knepley   Level: developer
40562a38674SMatthew G. Knepley 
406db781477SPatrick Sanan .seealso: `PetscGridHashCreate()`
40762a38674SMatthew G. Knepley */
408c4eade1cSMatthew G. Knepley PetscErrorCode PetscGridHashSetGrid(PetscGridHash box, const PetscInt n[], const PetscReal h[])
409c4eade1cSMatthew G. Knepley {
410c4eade1cSMatthew G. Knepley   PetscInt d;
411c4eade1cSMatthew G. Knepley 
412c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
413c4eade1cSMatthew G. Knepley   for (d = 0; d < box->dim; ++d) {
414c4eade1cSMatthew G. Knepley     box->extent[d] = box->upper[d] - box->lower[d];
415c4eade1cSMatthew G. Knepley     if (n[d] == PETSC_DETERMINE) {
416c4eade1cSMatthew G. Knepley       box->h[d] = h[d];
417c4eade1cSMatthew G. Knepley       box->n[d] = PetscCeilReal(box->extent[d]/h[d]);
418c4eade1cSMatthew G. Knepley     } else {
419c4eade1cSMatthew G. Knepley       box->n[d] = n[d];
420c4eade1cSMatthew G. Knepley       box->h[d] = box->extent[d]/n[d];
421c4eade1cSMatthew G. Knepley     }
422c4eade1cSMatthew G. Knepley   }
423c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
424c4eade1cSMatthew G. Knepley }
425c4eade1cSMatthew G. Knepley 
42662a38674SMatthew G. Knepley /*
42762a38674SMatthew G. Knepley   PetscGridHashGetEnclosingBox - Find the grid boxes containing each input point
42862a38674SMatthew G. Knepley 
42962a38674SMatthew G. Knepley   Not collective
43062a38674SMatthew G. Knepley 
43162a38674SMatthew G. Knepley   Input Parameters:
43262a38674SMatthew G. Knepley + box       - The grid hash object
43362a38674SMatthew G. Knepley . numPoints - The number of input points
43462a38674SMatthew G. Knepley - points    - The input point coordinates
43562a38674SMatthew G. Knepley 
43662a38674SMatthew G. Knepley   Output Parameters:
43762a38674SMatthew G. Knepley + dboxes    - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim)
43862a38674SMatthew G. Knepley - boxes     - An array of numPoints integers expressing the enclosing box as single number, or NULL
43962a38674SMatthew G. Knepley 
44062a38674SMatthew G. Knepley   Level: developer
44162a38674SMatthew G. Knepley 
442*f5867de0SMatthew G. Knepley   Note:
443*f5867de0SMatthew G. Knepley   This only guarantees that a box contains a point, not that a cell does.
444*f5867de0SMatthew G. Knepley 
445db781477SPatrick Sanan .seealso: `PetscGridHashCreate()`
44662a38674SMatthew G. Knepley */
4471c6dfc3eSMatthew G. Knepley PetscErrorCode PetscGridHashGetEnclosingBox(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[])
448c4eade1cSMatthew G. Knepley {
449c4eade1cSMatthew G. Knepley   const PetscReal *lower = box->lower;
450c4eade1cSMatthew G. Knepley   const PetscReal *upper = box->upper;
451c4eade1cSMatthew G. Knepley   const PetscReal *h     = box->h;
452c4eade1cSMatthew G. Knepley   const PetscInt  *n     = box->n;
453c4eade1cSMatthew G. Knepley   const PetscInt   dim   = box->dim;
454c4eade1cSMatthew G. Knepley   PetscInt         d, p;
455c4eade1cSMatthew G. Knepley 
456c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
457c4eade1cSMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
458c4eade1cSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
4591c6dfc3eSMatthew G. Knepley       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]);
460c4eade1cSMatthew G. Knepley 
4611c6dfc3eSMatthew G. Knepley       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1;
4622a705cacSMatthew G. Knepley       if (dbox == -1   && PetscAbsReal(PetscRealPart(points[p*dim+d]) - lower[d]) < 1.0e-9) dbox = 0;
46363a3b9bcSJacob Faibussowitsch       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",
464087ef6b2SMatthew G. Knepley                                              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);
465c4eade1cSMatthew G. Knepley       dboxes[p*dim+d] = dbox;
466c4eade1cSMatthew G. Knepley     }
467ddce0771SMatthew G. Knepley     if (boxes) for (d = dim-2, boxes[p] = dboxes[p*dim+dim-1]; d >= 0; --d) boxes[p] = boxes[p]*n[d] + dboxes[p*dim+d];
468c4eade1cSMatthew G. Knepley   }
469c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
470c4eade1cSMatthew G. Knepley }
471c4eade1cSMatthew G. Knepley 
472af74b616SDave May /*
473af74b616SDave May  PetscGridHashGetEnclosingBoxQuery - Find the grid boxes containing each input point
474af74b616SDave May 
475af74b616SDave May  Not collective
476af74b616SDave May 
477af74b616SDave May   Input Parameters:
478af74b616SDave May + box         - The grid hash object
479*f5867de0SMatthew G. Knepley . cellSection - The PetscSection mapping cells to boxes
480af74b616SDave May . numPoints   - The number of input points
481af74b616SDave May - points      - The input point coordinates
482af74b616SDave May 
483af74b616SDave May   Output Parameters:
484af74b616SDave May + dboxes - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim)
485af74b616SDave May . boxes  - An array of numPoints integers expressing the enclosing box as single number, or NULL
486af74b616SDave May - found  - Flag indicating if point was located within a box
487af74b616SDave May 
488af74b616SDave May   Level: developer
489af74b616SDave May 
490*f5867de0SMatthew G. Knepley   Note:
491*f5867de0SMatthew G. Knepley   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 the cellSection is already constructed.
492*f5867de0SMatthew G. Knepley 
493db781477SPatrick Sanan .seealso: `PetscGridHashGetEnclosingBox()`
494af74b616SDave May */
495*f5867de0SMatthew G. Knepley PetscErrorCode PetscGridHashGetEnclosingBoxQuery(PetscGridHash box, PetscSection cellSection, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[],PetscBool *found)
496af74b616SDave May {
497af74b616SDave May   const PetscReal *lower = box->lower;
498af74b616SDave May   const PetscReal *upper = box->upper;
499af74b616SDave May   const PetscReal *h     = box->h;
500af74b616SDave May   const PetscInt  *n     = box->n;
501af74b616SDave May   const PetscInt   dim   = box->dim;
502*f5867de0SMatthew G. Knepley   PetscInt         bStart, bEnd, d, p;
503af74b616SDave May 
504af74b616SDave May   PetscFunctionBegin;
505*f5867de0SMatthew G. Knepley   PetscValidHeaderSpecific(cellSection,PETSC_SECTION_CLASSID,2);
506af74b616SDave May   *found = PETSC_FALSE;
507*f5867de0SMatthew G. Knepley   PetscCall(PetscSectionGetChart(box->cellSection, &bStart, &bEnd));
508af74b616SDave May   for (p = 0; p < numPoints; ++p) {
509af74b616SDave May     for (d = 0; d < dim; ++d) {
510af74b616SDave May       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]);
511af74b616SDave May 
512af74b616SDave May       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1;
513*f5867de0SMatthew G. Knepley       if (dbox < 0 || dbox >= n[d]) PetscFunctionReturn(0);
514af74b616SDave May       dboxes[p*dim+d] = dbox;
515af74b616SDave May     }
516ddce0771SMatthew G. Knepley     if (boxes) for (d = dim-2, boxes[p] = dboxes[p*dim+dim-1]; d >= 0; --d) boxes[p] = boxes[p]*n[d] + dboxes[p*dim+d];
517*f5867de0SMatthew G. Knepley     // It is possible for a box to overlap no grid cells
518*f5867de0SMatthew G. Knepley     if (boxes[p] < bStart || boxes[p] >= bEnd) PetscFunctionReturn(0);
519af74b616SDave May   }
520af74b616SDave May   *found = PETSC_TRUE;
521af74b616SDave May   PetscFunctionReturn(0);
522af74b616SDave May }
523af74b616SDave May 
524c4eade1cSMatthew G. Knepley PetscErrorCode PetscGridHashDestroy(PetscGridHash *box)
525c4eade1cSMatthew G. Knepley {
526c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
527c4eade1cSMatthew G. Knepley   if (*box) {
5289566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(*box)->cellSection));
5299566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&(*box)->cells));
5309566063dSJacob Faibussowitsch     PetscCall(DMLabelDestroy(&(*box)->cellsSparse));
531c4eade1cSMatthew G. Knepley   }
5329566063dSJacob Faibussowitsch   PetscCall(PetscFree(*box));
533c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
534c4eade1cSMatthew G. Knepley }
535c4eade1cSMatthew G. Knepley 
536cafe43deSMatthew G. Knepley PetscErrorCode DMPlexLocatePoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cellStart, PetscInt *cell)
537cafe43deSMatthew G. Knepley {
538ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
539cafe43deSMatthew G. Knepley 
540cafe43deSMatthew G. Knepley   PetscFunctionBegin;
5419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cellStart, &ct));
542ba2698f1SMatthew G. Knepley   switch (ct) {
54314bbb9f0SLawrence Mitchell     case DM_POLYTOPE_SEGMENT:
5449566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_1D_Internal(dm, point, cellStart, cell));break;
545ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
5469566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_2D_Internal(dm, point, cellStart, cell));break;
547ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
5489566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Quad_2D_Internal(dm, point, cellStart, cell));break;
549ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
5509566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_3D_Internal(dm, point, cellStart, cell));break;
551ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
5529566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_General_3D_Internal(dm, point, cellStart, cell));break;
55363a3b9bcSJacob Faibussowitsch     default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell %" PetscInt_FMT " with type %s", cellStart, DMPolytopeTypes[ct]);
554cafe43deSMatthew G. Knepley   }
555cafe43deSMatthew G. Knepley   PetscFunctionReturn(0);
556cafe43deSMatthew G. Knepley }
557cafe43deSMatthew G. Knepley 
55862a38674SMatthew G. Knepley /*
55962a38674SMatthew G. Knepley   DMPlexClosestPoint_Internal - Returns the closest point in the cell to the given point
56062a38674SMatthew G. Knepley */
56162a38674SMatthew G. Knepley PetscErrorCode DMPlexClosestPoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cell, PetscReal cpoint[])
56262a38674SMatthew G. Knepley {
563ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
56462a38674SMatthew G. Knepley 
56562a38674SMatthew G. Knepley   PetscFunctionBegin;
5669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
567ba2698f1SMatthew G. Knepley   switch (ct) {
568ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
5699566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_2D_Internal(dm, point, cell, cpoint));break;
57062a38674SMatthew G. Knepley #if 0
571ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
5729566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_2D_Internal(dm, point, cell, cpoint));break;
573ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
5749566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_3D_Internal(dm, point, cell, cpoint));break;
575ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
5769566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_3D_Internal(dm, point, cell, cpoint));break;
57762a38674SMatthew G. Knepley #endif
57863a3b9bcSJacob Faibussowitsch     default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No closest point location for cell %" PetscInt_FMT " with type %s", cell, DMPolytopeTypes[ct]);
57962a38674SMatthew G. Knepley   }
58062a38674SMatthew G. Knepley   PetscFunctionReturn(0);
58162a38674SMatthew G. Knepley }
58262a38674SMatthew G. Knepley 
58362a38674SMatthew G. Knepley /*
58462a38674SMatthew G. Knepley   DMPlexComputeGridHash_Internal - Create a grid hash structure covering the Plex
58562a38674SMatthew G. Knepley 
586d083f849SBarry Smith   Collective on dm
58762a38674SMatthew G. Knepley 
58862a38674SMatthew G. Knepley   Input Parameter:
58962a38674SMatthew G. Knepley . dm - The Plex
59062a38674SMatthew G. Knepley 
59162a38674SMatthew G. Knepley   Output Parameter:
59262a38674SMatthew G. Knepley . localBox - The grid hash object
59362a38674SMatthew G. Knepley 
59462a38674SMatthew G. Knepley   Level: developer
59562a38674SMatthew G. Knepley 
596db781477SPatrick Sanan .seealso: `PetscGridHashCreate()`, `PetscGridHashGetEnclosingBox()`
59762a38674SMatthew G. Knepley */
598cafe43deSMatthew G. Knepley PetscErrorCode DMPlexComputeGridHash_Internal(DM dm, PetscGridHash *localBox)
599cafe43deSMatthew G. Knepley {
600*f5867de0SMatthew G. Knepley   PetscInt           debug = ((DM_Plex *) dm->data)->printLocate;
601cafe43deSMatthew G. Knepley   MPI_Comm           comm;
602cafe43deSMatthew G. Knepley   PetscGridHash      lbox;
603cafe43deSMatthew G. Knepley   Vec                coordinates;
604cafe43deSMatthew G. Knepley   PetscSection       coordSection;
605cafe43deSMatthew G. Knepley   Vec                coordsLocal;
606cafe43deSMatthew G. Knepley   const PetscScalar *coords;
607ddce0771SMatthew G. Knepley   PetscScalar       *edgeCoords;
608722d0f5cSMatthew G. Knepley   PetscInt          *dboxes, *boxes;
609ddce0771SMatthew G. Knepley   PetscInt           n[3] = {2, 2, 2};
610ddce0771SMatthew G. Knepley   PetscInt           dim, N, maxConeSize, cStart, cEnd, c, eStart, eEnd, i;
611ddce0771SMatthew G. Knepley   PetscBool          flg;
612cafe43deSMatthew G. Knepley 
613cafe43deSMatthew G. Knepley   PetscFunctionBegin;
6149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
6159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
6169566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
6179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
6189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
6199566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
6209566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
6219566063dSJacob Faibussowitsch   PetscCall(PetscGridHashCreate(comm, dim, coords, &lbox));
6229566063dSJacob Faibussowitsch   for (i = 0; i < N; i += dim) PetscCall(PetscGridHashEnlarge(lbox, &coords[i]));
6239566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
624ddce0771SMatthew G. Knepley   c    = dim;
6259566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject) dm)->prefix, "-dm_plex_hash_box_faces", n, &c, &flg));
626ddce0771SMatthew G. Knepley   if (flg) {for (i = c; i < dim; ++i) n[i] = n[c-1];}
627ddce0771SMatthew G. Knepley   else     {for (i = 0; i < dim; ++i) n[i] = PetscMax(2, PetscFloorReal(PetscPowReal((PetscReal) (cEnd - cStart), 1.0/dim) * 0.8));}
6289566063dSJacob Faibussowitsch   PetscCall(PetscGridHashSetGrid(lbox, n, NULL));
629*f5867de0SMatthew G. Knepley   if (debug) 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], (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]));
630cafe43deSMatthew G. Knepley #if 0
631cafe43deSMatthew G. Knepley   /* Could define a custom reduction to merge these */
6321c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->lower, gbox->lower, 3, MPIU_REAL, MPI_MIN, comm));
6331c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->upper, gbox->upper, 3, MPIU_REAL, MPI_MAX, comm));
634cafe43deSMatthew G. Knepley #endif
635cafe43deSMatthew G. Knepley   /* Is there a reason to snap the local bounding box to a division of the global box? */
636cafe43deSMatthew G. Knepley   /* Should we compute all overlaps of local boxes? We could do this with a rendevouz scheme partitioning the global box */
637cafe43deSMatthew G. Knepley   /* Create label */
6389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
639b26b5bf9SMatthew G. Knepley   if (dim < 2) eStart = eEnd = -1;
6409566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "cells", &lbox->cellsSparse));
6419566063dSJacob Faibussowitsch   PetscCall(DMLabelCreateIndex(lbox->cellsSparse, cStart, cEnd));
642a8d69d7bSBarry Smith   /* Compute boxes which overlap each cell: https://stackoverflow.com/questions/13790208/triangle-square-intersection-test-in-2d */
6439566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
6449566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6459566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(16 * dim, &dboxes, 16, &boxes, PetscPowInt(maxConeSize, dim) * dim, &edgeCoords));
646cafe43deSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
647cafe43deSMatthew G. Knepley     const PetscReal *h       = lbox->h;
648cafe43deSMatthew G. Knepley     PetscScalar     *ccoords = NULL;
64938353de4SMatthew G. Knepley     PetscInt         csize   = 0;
650ddce0771SMatthew G. Knepley     PetscInt        *closure = NULL;
651ddce0771SMatthew G. Knepley     PetscInt         Ncl, cl, Ne = 0;
652cafe43deSMatthew G. Knepley     PetscScalar      point[3];
653cafe43deSMatthew G. Knepley     PetscInt         dlim[6], d, e, i, j, k;
654cafe43deSMatthew G. Knepley 
655ddce0771SMatthew G. Knepley     /* Get all edges in cell */
6569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
657ddce0771SMatthew G. Knepley     for (cl = 0; cl < Ncl*2; ++cl) {
658ddce0771SMatthew G. Knepley       if ((closure[cl] >= eStart) && (closure[cl] < eEnd)) {
659ddce0771SMatthew G. Knepley         PetscScalar *ecoords = &edgeCoords[Ne*dim*2];
660ddce0771SMatthew G. Knepley         PetscInt     ecsize  = dim*2;
661ddce0771SMatthew G. Knepley 
6629566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, closure[cl], &ecsize, &ecoords));
66363a3b9bcSJacob 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);
664ddce0771SMatthew G. Knepley         ++Ne;
665ddce0771SMatthew G. Knepley       }
666ddce0771SMatthew G. Knepley     }
6679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
668cafe43deSMatthew G. Knepley     /* Find boxes enclosing each vertex */
6699566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &csize, &ccoords));
6709566063dSJacob Faibussowitsch     PetscCall(PetscGridHashGetEnclosingBox(lbox, csize/dim, ccoords, dboxes, boxes));
671722d0f5cSMatthew G. Knepley     /* Mark cells containing the vertices */
672ddce0771SMatthew G. Knepley     for (e = 0; e < csize/dim; ++e) {
67363a3b9bcSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " has vertex in box %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", c, boxes[e], dboxes[e*dim+0], dim > 1 ? dboxes[e*dim+1] : -1, dim > 2 ? dboxes[e*dim+2] : -1));
6749566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(lbox->cellsSparse, c, boxes[e]));
675ddce0771SMatthew G. Knepley     }
676cafe43deSMatthew G. Knepley     /* Get grid of boxes containing these */
677cafe43deSMatthew G. Knepley     for (d = 0;   d < dim; ++d) {dlim[d*2+0] = dlim[d*2+1] = dboxes[d];}
6782291669eSMatthew G. Knepley     for (d = dim; d < 3;   ++d) {dlim[d*2+0] = dlim[d*2+1] = 0;}
679cafe43deSMatthew G. Knepley     for (e = 1; e < dim+1; ++e) {
680cafe43deSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
681cafe43deSMatthew G. Knepley         dlim[d*2+0] = PetscMin(dlim[d*2+0], dboxes[e*dim+d]);
682cafe43deSMatthew G. Knepley         dlim[d*2+1] = PetscMax(dlim[d*2+1], dboxes[e*dim+d]);
683cafe43deSMatthew G. Knepley       }
684cafe43deSMatthew G. Knepley     }
685fea14342SMatthew G. Knepley     /* Check for intersection of box with cell */
686cafe43deSMatthew 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]) {
687cafe43deSMatthew 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]) {
688cafe43deSMatthew 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]) {
689cafe43deSMatthew G. Knepley           const PetscInt box = (k*lbox->n[1] + j)*lbox->n[0] + i;
690cafe43deSMatthew G. Knepley           PetscScalar    cpoint[3];
691fea14342SMatthew G. Knepley           PetscInt       cell, edge, ii, jj, kk;
692cafe43deSMatthew G. Knepley 
69363a3b9bcSJacob Faibussowitsch           if (debug) 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])));
694ddce0771SMatthew G. Knepley           /* Check whether cell contains any vertex of this subbox TODO vectorize this */
695cafe43deSMatthew G. Knepley           for (kk = 0, cpoint[2] = point[2]; kk < (dim > 2 ? 2 : 1); ++kk, cpoint[2] += h[2]) {
696cafe43deSMatthew G. Knepley             for (jj = 0, cpoint[1] = point[1]; jj < (dim > 1 ? 2 : 1); ++jj, cpoint[1] += h[1]) {
697cafe43deSMatthew G. Knepley               for (ii = 0, cpoint[0] = point[0]; ii < 2; ++ii, cpoint[0] += h[0]) {
698cafe43deSMatthew G. Knepley 
6999566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(dm, dim, cpoint, c, &cell));
7000b6bfacdSStefano Zampini                 if (cell >= 0) {
70163a3b9bcSJacob Faibussowitsch                   if (debug) 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));
7029566063dSJacob Faibussowitsch                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box));
7030b6bfacdSStefano Zampini                   jj = kk = 2;
7040b6bfacdSStefano Zampini                   break;
7050b6bfacdSStefano Zampini                 }
706cafe43deSMatthew G. Knepley               }
707cafe43deSMatthew G. Knepley             }
708cafe43deSMatthew G. Knepley           }
709ddce0771SMatthew G. Knepley           /* Check whether cell edge intersects any face of these subboxes TODO vectorize this */
710ddce0771SMatthew G. Knepley           for (edge = 0; edge < Ne; ++edge) {
711a5cae605SSatish Balay             PetscReal segA[6] = {0.,0.,0.,0.,0.,0.};
712a5cae605SSatish Balay             PetscReal segB[6] = {0.,0.,0.,0.,0.,0.};
713a5cae605SSatish Balay             PetscReal segC[6] = {0.,0.,0.,0.,0.,0.};
714fea14342SMatthew G. Knepley 
71563a3b9bcSJacob Faibussowitsch             PetscCheck(dim <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected dim %" PetscInt_FMT " > 3",dim);
716ddce0771SMatthew G. Knepley             for (d = 0; d < dim*2; ++d) segA[d] = PetscRealPart(edgeCoords[edge*dim*2+d]);
717ddce0771SMatthew G. Knepley             /* 1D: (x) -- (x+h)               0 -- 1
718ddce0771SMatthew G. Knepley                2D: (x,   y)   -- (x,   y+h)   (0, 0) -- (0, 1)
719ddce0771SMatthew G. Knepley                    (x+h, y)   -- (x+h, y+h)   (1, 0) -- (1, 1)
720ddce0771SMatthew G. Knepley                    (x,   y)   -- (x+h, y)     (0, 0) -- (1, 0)
721ddce0771SMatthew G. Knepley                    (x,   y+h) -- (x+h, y+h)   (0, 1) -- (1, 1)
722ddce0771SMatthew 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)
723ddce0771SMatthew 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)
724ddce0771SMatthew 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)
725ddce0771SMatthew 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)
726ddce0771SMatthew 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)
727ddce0771SMatthew 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)
728ddce0771SMatthew G. Knepley              */
729ddce0771SMatthew G. Knepley             /* Loop over faces with normal in direction d */
730ddce0771SMatthew G. Knepley             for (d = 0; d < dim; ++d) {
731ddce0771SMatthew G. Knepley               PetscBool intersects = PETSC_FALSE;
732ddce0771SMatthew G. Knepley               PetscInt  e = (d+1)%dim;
733ddce0771SMatthew G. Knepley               PetscInt  f = (d+2)%dim;
734ddce0771SMatthew G. Knepley 
735ddce0771SMatthew G. Knepley               /* There are two faces in each dimension */
736ddce0771SMatthew G. Knepley               for (ii = 0; ii < 2; ++ii) {
737ddce0771SMatthew G. Knepley                 segB[d]     = PetscRealPart(point[d] + ii*h[d]);
738ddce0771SMatthew G. Knepley                 segB[dim+d] = PetscRealPart(point[d] + ii*h[d]);
739ddce0771SMatthew G. Knepley                 segC[d]     = PetscRealPart(point[d] + ii*h[d]);
740ddce0771SMatthew G. Knepley                 segC[dim+d] = PetscRealPart(point[d] + ii*h[d]);
741ddce0771SMatthew G. Knepley                 if (dim > 1) {
742ddce0771SMatthew G. Knepley                   segB[e]     = PetscRealPart(point[e] + 0*h[e]);
743ddce0771SMatthew G. Knepley                   segB[dim+e] = PetscRealPart(point[e] + 1*h[e]);
744ddce0771SMatthew G. Knepley                   segC[e]     = PetscRealPart(point[e] + 0*h[e]);
745ddce0771SMatthew G. Knepley                   segC[dim+e] = PetscRealPart(point[e] + 0*h[e]);
746ddce0771SMatthew G. Knepley                 }
747ddce0771SMatthew G. Knepley                 if (dim > 2) {
748ddce0771SMatthew G. Knepley                   segB[f]     = PetscRealPart(point[f] + 0*h[f]);
749ddce0771SMatthew G. Knepley                   segB[dim+f] = PetscRealPart(point[f] + 0*h[f]);
750ddce0771SMatthew G. Knepley                   segC[f]     = PetscRealPart(point[f] + 0*h[f]);
751ddce0771SMatthew G. Knepley                   segC[dim+f] = PetscRealPart(point[f] + 1*h[f]);
752ddce0771SMatthew G. Knepley                 }
753ddce0771SMatthew G. Knepley                 if (dim == 2) {
7549566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLineIntersection_2D_Internal(segA, segB, NULL, &intersects));
755ddce0771SMatthew G. Knepley                 } else if (dim == 3) {
7569566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLinePlaneIntersection_3D_Internal(segA, segB, segC, NULL, &intersects));
757ddce0771SMatthew G. Knepley                 }
758ddce0771SMatthew G. Knepley                 if (intersects) {
75963a3b9bcSJacob Faibussowitsch                   if (debug) 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]));
7609566063dSJacob Faibussowitsch                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box)); edge = Ne; break;
761ddce0771SMatthew G. Knepley                 }
762ddce0771SMatthew G. Knepley               }
763ddce0771SMatthew G. Knepley             }
764cafe43deSMatthew G. Knepley           }
765fea14342SMatthew G. Knepley         }
766fea14342SMatthew G. Knepley       }
767fea14342SMatthew G. Knepley     }
7689566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &ccoords));
769fea14342SMatthew G. Knepley   }
7709566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dboxes, boxes, edgeCoords));
7719566063dSJacob Faibussowitsch   if (debug) PetscCall(DMLabelView(lbox->cellsSparse, PETSC_VIEWER_STDOUT_SELF));
7729566063dSJacob Faibussowitsch   PetscCall(DMLabelConvertToSection(lbox->cellsSparse, &lbox->cellSection, &lbox->cells));
7739566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lbox->cellsSparse));
774cafe43deSMatthew G. Knepley   *localBox = lbox;
775cafe43deSMatthew G. Knepley   PetscFunctionReturn(0);
776cafe43deSMatthew G. Knepley }
777cafe43deSMatthew G. Knepley 
77862a38674SMatthew G. Knepley PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, DMPointLocationType ltype, PetscSF cellSF)
779ccd2543fSMatthew G Knepley {
780*f5867de0SMatthew G. Knepley   PetscInt        debug = ((DM_Plex *) dm->data)->printLocate;
781cafe43deSMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *) dm->data;
782af74b616SDave May   PetscBool       hash = mesh->useHashLocation, reuse = PETSC_FALSE;
7833a93e3b7SToby Isaac   PetscInt        bs, numPoints, p, numFound, *found = NULL;
784412e9a14SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, numCells, c, d;
785cafe43deSMatthew G. Knepley   const PetscInt *boxCells;
7863a93e3b7SToby Isaac   PetscSFNode    *cells;
787ccd2543fSMatthew G Knepley   PetscScalar    *a;
7883a93e3b7SToby Isaac   PetscMPIInt     result;
789af74b616SDave May   PetscLogDouble  t0,t1;
7909cb35068SDave May   PetscReal       gmin[3],gmax[3];
7919cb35068SDave May   PetscInt        terminating_query_type[] = { 0, 0, 0 };
792ccd2543fSMatthew G Knepley 
793ccd2543fSMatthew G Knepley   PetscFunctionBegin;
7949566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocatePoints,0,0,0,0));
7959566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t0));
7961dca8a05SBarry 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.");
7979566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
7989566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
7999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)cellSF),PETSC_COMM_SELF,&result));
8001dca8a05SBarry Smith   PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PetscObjectComm((PetscObject)cellSF),PETSC_ERR_SUP, "Trying parallel point location: only local point location supported");
80163a3b9bcSJacob 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);
8026858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
8039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
8049566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &numPoints));
8059566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
806ccd2543fSMatthew G Knepley   numPoints /= bs;
807af74b616SDave May   {
808af74b616SDave May     const PetscSFNode *sf_cells;
809af74b616SDave May 
8109566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(cellSF,NULL,NULL,NULL,&sf_cells));
811af74b616SDave May     if (sf_cells) {
8129566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"[DMLocatePoints_Plex] Re-using existing StarForest node list\n"));
813af74b616SDave May       cells = (PetscSFNode*)sf_cells;
814af74b616SDave May       reuse = PETSC_TRUE;
815af74b616SDave May     } else {
8169566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"[DMLocatePoints_Plex] Creating and initializing new StarForest node list\n"));
8179566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numPoints, &cells));
818af74b616SDave May       /* initialize cells if created */
819af74b616SDave May       for (p=0; p<numPoints; p++) {
820af74b616SDave May         cells[p].rank  = 0;
821af74b616SDave May         cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
822af74b616SDave May       }
823af74b616SDave May     }
824af74b616SDave May   }
8259cb35068SDave May   /* define domain bounding box */
8269cb35068SDave May   {
8279cb35068SDave May     Vec coorglobal;
8289cb35068SDave May 
8299566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(dm,&coorglobal));
8309566063dSJacob Faibussowitsch     PetscCall(VecStrideMaxAll(coorglobal,NULL,gmax));
8319566063dSJacob Faibussowitsch     PetscCall(VecStrideMinAll(coorglobal,NULL,gmin));
8329cb35068SDave May   }
833953fc75cSMatthew G. Knepley   if (hash) {
8349566063dSJacob Faibussowitsch     if (!mesh->lbox) {PetscCall(PetscInfo(dm, "Initializing grid hashing"));PetscCall(DMPlexComputeGridHash_Internal(dm, &mesh->lbox));}
835cafe43deSMatthew G. Knepley     /* Designate the local box for each point */
836cafe43deSMatthew G. Knepley     /* Send points to correct process */
837cafe43deSMatthew G. Knepley     /* Search cells that lie in each subbox */
838cafe43deSMatthew G. Knepley     /*   Should we bin points before doing search? */
8399566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(mesh->lbox->cells, &boxCells));
840953fc75cSMatthew G. Knepley   }
8413a93e3b7SToby Isaac   for (p = 0, numFound = 0; p < numPoints; ++p) {
842ccd2543fSMatthew G Knepley     const PetscScalar *point = &a[p*bs];
843e56f9228SJed Brown     PetscInt           dbin[3] = {-1,-1,-1}, bin, cell = -1, cellOffset;
8449cb35068SDave May     PetscBool          point_outside_domain = PETSC_FALSE;
845ccd2543fSMatthew G Knepley 
8469cb35068SDave May     /* check bounding box of domain */
8479cb35068SDave May     for (d=0; d<dim; d++) {
848a5f152d1SDave May       if (PetscRealPart(point[d]) < gmin[d]) { point_outside_domain = PETSC_TRUE; break; }
849a5f152d1SDave May       if (PetscRealPart(point[d]) > gmax[d]) { point_outside_domain = PETSC_TRUE; break; }
8509cb35068SDave May     }
8519cb35068SDave May     if (point_outside_domain) {
852e9b685f5SMatthew G. Knepley       cells[p].rank = 0;
853e9b685f5SMatthew G. Knepley       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
8549cb35068SDave May       terminating_query_type[0]++;
8559cb35068SDave May       continue;
8569cb35068SDave May     }
857ccd2543fSMatthew G Knepley 
858af74b616SDave May     /* check initial values in cells[].index - abort early if found */
859af74b616SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
860af74b616SDave May       c = cells[p].index;
8613a93e3b7SToby Isaac       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
8629566063dSJacob Faibussowitsch       PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
863af74b616SDave May       if (cell >= 0) {
864af74b616SDave May         cells[p].rank = 0;
865af74b616SDave May         cells[p].index = cell;
866af74b616SDave May         numFound++;
867af74b616SDave May       }
868af74b616SDave May     }
8699cb35068SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
8709cb35068SDave May       terminating_query_type[1]++;
8719cb35068SDave May       continue;
8729cb35068SDave May     }
873af74b616SDave May 
874953fc75cSMatthew G. Knepley     if (hash) {
875af74b616SDave May       PetscBool found_box;
876af74b616SDave May 
87763a3b9bcSJacob 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])));
878af74b616SDave May       /* allow for case that point is outside box - abort early */
879*f5867de0SMatthew G. Knepley       PetscCall(PetscGridHashGetEnclosingBoxQuery(mesh->lbox, mesh->lbox->cellSection, 1, point, dbin, &bin,&found_box));
880af74b616SDave May       if (found_box) {
88163a3b9bcSJacob 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]));
882cafe43deSMatthew G. Knepley         /* TODO Lay an interface over this so we can switch between Section (dense) and Label (sparse) */
8839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
8849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
885cafe43deSMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
88663a3b9bcSJacob Faibussowitsch           if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Checking for point in cell %" PetscInt_FMT "\n", boxCells[c]));
8879566063dSJacob Faibussowitsch           PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, boxCells[c], &cell));
8883a93e3b7SToby Isaac           if (cell >= 0) {
88963a3b9bcSJacob Faibussowitsch             if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      FOUND in cell %" PetscInt_FMT "\n", cell));
8903a93e3b7SToby Isaac             cells[p].rank = 0;
8913a93e3b7SToby Isaac             cells[p].index = cell;
8923a93e3b7SToby Isaac             numFound++;
8939cb35068SDave May             terminating_query_type[2]++;
8943a93e3b7SToby Isaac             break;
895ccd2543fSMatthew G Knepley           }
8963a93e3b7SToby Isaac         }
897af74b616SDave May       }
898953fc75cSMatthew G. Knepley     } else {
899953fc75cSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
9009566063dSJacob Faibussowitsch         PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
9013a93e3b7SToby Isaac         if (cell >= 0) {
9023a93e3b7SToby Isaac           cells[p].rank = 0;
9033a93e3b7SToby Isaac           cells[p].index = cell;
9043a93e3b7SToby Isaac           numFound++;
9059cb35068SDave May           terminating_query_type[2]++;
9063a93e3b7SToby Isaac           break;
907953fc75cSMatthew G. Knepley         }
908953fc75cSMatthew G. Knepley       }
9093a93e3b7SToby Isaac     }
910ccd2543fSMatthew G Knepley   }
9119566063dSJacob Faibussowitsch   if (hash) PetscCall(ISRestoreIndices(mesh->lbox->cells, &boxCells));
91262a38674SMatthew G. Knepley   if (ltype == DM_POINTLOCATION_NEAREST && hash && numFound < numPoints) {
91362a38674SMatthew G. Knepley     for (p = 0; p < numPoints; p++) {
91462a38674SMatthew G. Knepley       const PetscScalar *point = &a[p*bs];
915d92c4b9fSToby Isaac       PetscReal          cpoint[3], diff[3], best[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}, dist, distMax = PETSC_MAX_REAL;
916d92c4b9fSToby Isaac       PetscInt           dbin[3] = {-1,-1,-1}, bin, cellOffset, d, bestc = -1;
91762a38674SMatthew G. Knepley 
918e9b685f5SMatthew G. Knepley       if (cells[p].index < 0) {
9199566063dSJacob Faibussowitsch         PetscCall(PetscGridHashGetEnclosingBox(mesh->lbox, 1, point, dbin, &bin));
9209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
9219566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
92262a38674SMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
9239566063dSJacob Faibussowitsch           PetscCall(DMPlexClosestPoint_Internal(dm, dim, point, boxCells[c], cpoint));
924b716b415SMatthew G. Knepley           for (d = 0; d < dim; ++d) diff[d] = cpoint[d] - PetscRealPart(point[d]);
92562a38674SMatthew G. Knepley           dist = DMPlex_NormD_Internal(dim, diff);
92662a38674SMatthew G. Knepley           if (dist < distMax) {
927d92c4b9fSToby Isaac             for (d = 0; d < dim; ++d) best[d] = cpoint[d];
928d92c4b9fSToby Isaac             bestc = boxCells[c];
92962a38674SMatthew G. Knepley             distMax = dist;
93062a38674SMatthew G. Knepley           }
93162a38674SMatthew G. Knepley         }
932d92c4b9fSToby Isaac         if (distMax < PETSC_MAX_REAL) {
933d92c4b9fSToby Isaac           ++numFound;
934d92c4b9fSToby Isaac           cells[p].rank  = 0;
935d92c4b9fSToby Isaac           cells[p].index = bestc;
936d92c4b9fSToby Isaac           for (d = 0; d < dim; ++d) a[p*bs+d] = best[d];
937d92c4b9fSToby Isaac         }
93862a38674SMatthew G. Knepley       }
93962a38674SMatthew G. Knepley     }
94062a38674SMatthew G. Knepley   }
94162a38674SMatthew G. Knepley   /* This code is only be relevant when interfaced to parallel point location */
942cafe43deSMatthew G. Knepley   /* Check for highest numbered proc that claims a point (do we care?) */
9432d1fa6caSMatthew G. Knepley   if (ltype == DM_POINTLOCATION_REMOVE && numFound < numPoints) {
9449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFound,&found));
9453a93e3b7SToby Isaac     for (p = 0, numFound = 0; p < numPoints; p++) {
9463a93e3b7SToby Isaac       if (cells[p].rank >= 0 && cells[p].index >= 0) {
9473a93e3b7SToby Isaac         if (numFound < p) {
9483a93e3b7SToby Isaac           cells[numFound] = cells[p];
9493a93e3b7SToby Isaac         }
9503a93e3b7SToby Isaac         found[numFound++] = p;
9513a93e3b7SToby Isaac       }
9523a93e3b7SToby Isaac     }
9533a93e3b7SToby Isaac   }
9549566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
955af74b616SDave May   if (!reuse) {
9569566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(cellSF, cEnd - cStart, numFound, found, PETSC_OWN_POINTER, cells, PETSC_OWN_POINTER));
957af74b616SDave May   }
9589566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t1));
9599cb35068SDave May   if (hash) {
96063a3b9bcSJacob 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]));
9619cb35068SDave May   } else {
96263a3b9bcSJacob 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]));
9639cb35068SDave May   }
96463a3b9bcSJacob 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))));
9659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocatePoints,0,0,0,0));
966ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
967ccd2543fSMatthew G Knepley }
968ccd2543fSMatthew G Knepley 
969741bfc07SMatthew G. Knepley /*@C
970741bfc07SMatthew G. Knepley   DMPlexComputeProjection2Dto1D - Rewrite coordinates to be the 1D projection of the 2D coordinates
971741bfc07SMatthew G. Knepley 
972741bfc07SMatthew G. Knepley   Not collective
973741bfc07SMatthew G. Knepley 
9746b867d5aSJose E. Roman   Input/Output Parameter:
9756b867d5aSJose E. Roman . coords - The coordinates of a segment, on output the new y-coordinate, and 0 for x
976741bfc07SMatthew G. Knepley 
9776b867d5aSJose E. Roman   Output Parameter:
9786b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
979741bfc07SMatthew G. Knepley 
980741bfc07SMatthew G. Knepley   Level: developer
981741bfc07SMatthew G. Knepley 
982db781477SPatrick Sanan .seealso: `DMPlexComputeProjection3Dto1D()`, `DMPlexComputeProjection3Dto2D()`
983741bfc07SMatthew G. Knepley @*/
984741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection2Dto1D(PetscScalar coords[], PetscReal R[])
98517fe8556SMatthew G. Knepley {
98617fe8556SMatthew G. Knepley   const PetscReal x = PetscRealPart(coords[2] - coords[0]);
98717fe8556SMatthew G. Knepley   const PetscReal y = PetscRealPart(coords[3] - coords[1]);
9888b49ba18SBarry Smith   const PetscReal r = PetscSqrtReal(x*x + y*y), c = x/r, s = y/r;
98917fe8556SMatthew G. Knepley 
99017fe8556SMatthew G. Knepley   PetscFunctionBegin;
9911c99cf0cSGeoffrey Irving   R[0] = c; R[1] = -s;
9921c99cf0cSGeoffrey Irving   R[2] = s; R[3] =  c;
99317fe8556SMatthew G. Knepley   coords[0] = 0.0;
9947f07f362SMatthew G. Knepley   coords[1] = r;
99517fe8556SMatthew G. Knepley   PetscFunctionReturn(0);
99617fe8556SMatthew G. Knepley }
99717fe8556SMatthew G. Knepley 
998741bfc07SMatthew G. Knepley /*@C
999741bfc07SMatthew G. Knepley   DMPlexComputeProjection3Dto1D - Rewrite coordinates to be the 1D projection of the 3D coordinates
100028dbe442SToby Isaac 
1001741bfc07SMatthew G. Knepley   Not collective
100228dbe442SToby Isaac 
10036b867d5aSJose E. Roman   Input/Output Parameter:
10046b867d5aSJose E. Roman . coords - The coordinates of a segment; on output, the new y-coordinate, and 0 for x and z
1005741bfc07SMatthew G. Knepley 
10066b867d5aSJose E. Roman   Output Parameter:
10076b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
1008741bfc07SMatthew G. Knepley 
1009741bfc07SMatthew G. Knepley   Note: 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
1010741bfc07SMatthew G. Knepley 
1011741bfc07SMatthew G. Knepley   Level: developer
1012741bfc07SMatthew G. Knepley 
1013db781477SPatrick Sanan .seealso: `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto2D()`
1014741bfc07SMatthew G. Knepley @*/
1015741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection3Dto1D(PetscScalar coords[], PetscReal R[])
101628dbe442SToby Isaac {
101728dbe442SToby Isaac   PetscReal      x    = PetscRealPart(coords[3] - coords[0]);
101828dbe442SToby Isaac   PetscReal      y    = PetscRealPart(coords[4] - coords[1]);
101928dbe442SToby Isaac   PetscReal      z    = PetscRealPart(coords[5] - coords[2]);
102028dbe442SToby Isaac   PetscReal      r    = PetscSqrtReal(x*x + y*y + z*z);
102128dbe442SToby Isaac   PetscReal      rinv = 1. / r;
102228dbe442SToby Isaac   PetscFunctionBegin;
102328dbe442SToby Isaac 
102428dbe442SToby Isaac   x *= rinv; y *= rinv; z *= rinv;
102528dbe442SToby Isaac   if (x > 0.) {
102628dbe442SToby Isaac     PetscReal inv1pX   = 1./ (1. + x);
102728dbe442SToby Isaac 
102828dbe442SToby Isaac     R[0] = x; R[1] = -y;              R[2] = -z;
102928dbe442SToby Isaac     R[3] = y; R[4] = 1. - y*y*inv1pX; R[5] =     -y*z*inv1pX;
103028dbe442SToby Isaac     R[6] = z; R[7] =     -y*z*inv1pX; R[8] = 1. - z*z*inv1pX;
103128dbe442SToby Isaac   }
103228dbe442SToby Isaac   else {
103328dbe442SToby Isaac     PetscReal inv1mX   = 1./ (1. - x);
103428dbe442SToby Isaac 
103528dbe442SToby Isaac     R[0] = x; R[1] = z;               R[2] = y;
103628dbe442SToby Isaac     R[3] = y; R[4] =     -y*z*inv1mX; R[5] = 1. - y*y*inv1mX;
103728dbe442SToby Isaac     R[6] = z; R[7] = 1. - z*z*inv1mX; R[8] =     -y*z*inv1mX;
103828dbe442SToby Isaac   }
103928dbe442SToby Isaac   coords[0] = 0.0;
104028dbe442SToby Isaac   coords[1] = r;
104128dbe442SToby Isaac   PetscFunctionReturn(0);
104228dbe442SToby Isaac }
104328dbe442SToby Isaac 
1044741bfc07SMatthew G. Knepley /*@
1045c871b86eSJed Brown   DMPlexComputeProjection3Dto2D - Rewrite coordinates of 3 or more coplanar 3D points to a common 2D basis for the
1046c871b86eSJed Brown     plane.  The normal is defined by positive orientation of the first 3 points.
1047741bfc07SMatthew G. Knepley 
1048741bfc07SMatthew G. Knepley   Not collective
1049741bfc07SMatthew G. Knepley 
1050741bfc07SMatthew G. Knepley   Input Parameter:
10516b867d5aSJose E. Roman . coordSize - Length of coordinate array (3x number of points); must be at least 9 (3 points)
1052741bfc07SMatthew G. Knepley 
10536b867d5aSJose E. Roman   Input/Output Parameter:
10546b867d5aSJose E. Roman . coords - The interlaced coordinates of each coplanar 3D point; on output the first
10556b867d5aSJose E. Roman            2*coordSize/3 entries contain interlaced 2D points, with the rest undefined
10566b867d5aSJose E. Roman 
10576b867d5aSJose E. Roman   Output Parameter:
10586b867d5aSJose 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.
1059741bfc07SMatthew G. Knepley 
1060741bfc07SMatthew G. Knepley   Level: developer
1061741bfc07SMatthew G. Knepley 
1062db781477SPatrick Sanan .seealso: `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto1D()`
1063741bfc07SMatthew G. Knepley @*/
1064741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection3Dto2D(PetscInt coordSize, PetscScalar coords[], PetscReal R[])
1065ccd2543fSMatthew G Knepley {
1066c871b86eSJed Brown   PetscReal x1[3], x2[3], n[3], c[3], norm;
1067ccd2543fSMatthew G Knepley   const PetscInt dim = 3;
1068c871b86eSJed Brown   PetscInt       d, p;
1069ccd2543fSMatthew G Knepley 
1070ccd2543fSMatthew G Knepley   PetscFunctionBegin;
1071ccd2543fSMatthew G Knepley   /* 0) Calculate normal vector */
1072ccd2543fSMatthew G Knepley   for (d = 0; d < dim; ++d) {
10731ee9d5ecSMatthew G. Knepley     x1[d] = PetscRealPart(coords[1*dim+d] - coords[0*dim+d]);
10741ee9d5ecSMatthew G. Knepley     x2[d] = PetscRealPart(coords[2*dim+d] - coords[0*dim+d]);
1075ccd2543fSMatthew G Knepley   }
1076c871b86eSJed Brown   // n = x1 \otimes x2
1077ccd2543fSMatthew G Knepley   n[0] = x1[1]*x2[2] - x1[2]*x2[1];
1078ccd2543fSMatthew G Knepley   n[1] = x1[2]*x2[0] - x1[0]*x2[2];
1079ccd2543fSMatthew G Knepley   n[2] = x1[0]*x2[1] - x1[1]*x2[0];
10808b49ba18SBarry Smith   norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
1081c871b86eSJed Brown   for (d = 0; d < dim; d++) n[d] /= norm;
1082c871b86eSJed Brown   norm = PetscSqrtReal(x1[0] * x1[0] + x1[1] * x1[1] + x1[2] * x1[2]);
1083c871b86eSJed Brown   for (d = 0; d < dim; d++) x1[d] /= norm;
1084c871b86eSJed Brown   // x2 = n \otimes x1
1085c871b86eSJed Brown   x2[0] = n[1] * x1[2] - n[2] * x1[1];
1086c871b86eSJed Brown   x2[1] = n[2] * x1[0] - n[0] * x1[2];
1087c871b86eSJed Brown   x2[2] = n[0] * x1[1] - n[1] * x1[0];
1088c871b86eSJed Brown   for (d=0; d<dim; d++) {
1089c871b86eSJed Brown     R[d * dim + 0] = x1[d];
1090c871b86eSJed Brown     R[d * dim + 1] = x2[d];
1091c871b86eSJed Brown     R[d * dim + 2] = n[d];
1092c871b86eSJed Brown     c[d] = PetscRealPart(coords[0*dim + d]);
109373868372SMatthew G. Knepley   }
1094c871b86eSJed Brown   for (p=0; p<coordSize/dim; p++) {
1095c871b86eSJed Brown     PetscReal y[3];
1096c871b86eSJed Brown     for (d=0; d<dim; d++) y[d] = PetscRealPart(coords[p*dim + d]) - c[d];
1097c871b86eSJed 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];
10987f07f362SMatthew G. Knepley   }
1099ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1100ccd2543fSMatthew G Knepley }
1101ccd2543fSMatthew G Knepley 
11026322fe33SJed Brown PETSC_UNUSED
11039fbee547SJacob Faibussowitsch static inline void Volume_Triangle_Internal(PetscReal *vol, PetscReal coords[])
1104834e62ceSMatthew G. Knepley {
1105834e62ceSMatthew G. Knepley   /* Signed volume is 1/2 the determinant
1106834e62ceSMatthew G. Knepley 
1107834e62ceSMatthew G. Knepley    |  1  1  1 |
1108834e62ceSMatthew G. Knepley    | x0 x1 x2 |
1109834e62ceSMatthew G. Knepley    | y0 y1 y2 |
1110834e62ceSMatthew G. Knepley 
1111834e62ceSMatthew G. Knepley      but if x0,y0 is the origin, we have
1112834e62ceSMatthew G. Knepley 
1113834e62ceSMatthew G. Knepley    | x1 x2 |
1114834e62ceSMatthew G. Knepley    | y1 y2 |
1115834e62ceSMatthew G. Knepley   */
1116834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[2] - coords[0], y1 = coords[3] - coords[1];
1117834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[4] - coords[0], y2 = coords[5] - coords[1];
1118834e62ceSMatthew G. Knepley   PetscReal       M[4], detM;
1119834e62ceSMatthew G. Knepley   M[0] = x1; M[1] = x2;
112086623015SMatthew G. Knepley   M[2] = y1; M[3] = y2;
1121923591dfSMatthew G. Knepley   DMPlex_Det2D_Internal(&detM, M);
1122834e62ceSMatthew G. Knepley   *vol = 0.5*detM;
11233bc0b13bSBarry Smith   (void)PetscLogFlops(5.0);
1124834e62ceSMatthew G. Knepley }
1125834e62ceSMatthew G. Knepley 
11266322fe33SJed Brown PETSC_UNUSED
11279fbee547SJacob Faibussowitsch static inline void Volume_Tetrahedron_Internal(PetscReal *vol, PetscReal coords[])
1128834e62ceSMatthew G. Knepley {
1129834e62ceSMatthew G. Knepley   /* Signed volume is 1/6th of the determinant
1130834e62ceSMatthew G. Knepley 
1131834e62ceSMatthew G. Knepley    |  1  1  1  1 |
1132834e62ceSMatthew G. Knepley    | x0 x1 x2 x3 |
1133834e62ceSMatthew G. Knepley    | y0 y1 y2 y3 |
1134834e62ceSMatthew G. Knepley    | z0 z1 z2 z3 |
1135834e62ceSMatthew G. Knepley 
1136834e62ceSMatthew G. Knepley      but if x0,y0,z0 is the origin, we have
1137834e62ceSMatthew G. Knepley 
1138834e62ceSMatthew G. Knepley    | x1 x2 x3 |
1139834e62ceSMatthew G. Knepley    | y1 y2 y3 |
1140834e62ceSMatthew G. Knepley    | z1 z2 z3 |
1141834e62ceSMatthew G. Knepley   */
1142834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[3] - coords[0], y1 = coords[4]  - coords[1], z1 = coords[5]  - coords[2];
1143834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[6] - coords[0], y2 = coords[7]  - coords[1], z2 = coords[8]  - coords[2];
1144834e62ceSMatthew G. Knepley   const PetscReal x3 = coords[9] - coords[0], y3 = coords[10] - coords[1], z3 = coords[11] - coords[2];
11450a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.);
1146834e62ceSMatthew G. Knepley   PetscReal       M[9], detM;
1147834e62ceSMatthew G. Knepley   M[0] = x1; M[1] = x2; M[2] = x3;
1148834e62ceSMatthew G. Knepley   M[3] = y1; M[4] = y2; M[5] = y3;
1149834e62ceSMatthew G. Knepley   M[6] = z1; M[7] = z2; M[8] = z3;
1150923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(&detM, M);
11510a3da2c2SToby Isaac   *vol = -onesixth*detM;
11523bc0b13bSBarry Smith   (void)PetscLogFlops(10.0);
1153834e62ceSMatthew G. Knepley }
1154834e62ceSMatthew G. Knepley 
11559fbee547SJacob Faibussowitsch static inline void Volume_Tetrahedron_Origin_Internal(PetscReal *vol, PetscReal coords[])
11560ec8681fSMatthew G. Knepley {
11570a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.);
1158923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(vol, coords);
11590a3da2c2SToby Isaac   *vol *= -onesixth;
11600ec8681fSMatthew G. Knepley }
11610ec8681fSMatthew G. Knepley 
1162cb92db44SToby Isaac static PetscErrorCode DMPlexComputePointGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1163cb92db44SToby Isaac {
1164cb92db44SToby Isaac   PetscSection   coordSection;
1165cb92db44SToby Isaac   Vec            coordinates;
1166cb92db44SToby Isaac   const PetscScalar *coords;
1167cb92db44SToby Isaac   PetscInt       dim, d, off;
1168cb92db44SToby Isaac 
1169cb92db44SToby Isaac   PetscFunctionBegin;
11709566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
11719566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
11729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(coordSection,e,&dim));
1173cb92db44SToby Isaac   if (!dim) PetscFunctionReturn(0);
11749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(coordSection,e,&off));
11759566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates,&coords));
1176cb92db44SToby Isaac   if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[off + d]);}
11779566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates,&coords));
1178cb92db44SToby Isaac   *detJ = 1.;
1179cb92db44SToby Isaac   if (J) {
1180cb92db44SToby Isaac     for (d = 0; d < dim * dim; d++) J[d] = 0.;
1181cb92db44SToby Isaac     for (d = 0; d < dim; d++) J[d * dim + d] = 1.;
1182cb92db44SToby Isaac     if (invJ) {
1183cb92db44SToby Isaac       for (d = 0; d < dim * dim; d++) invJ[d] = 0.;
1184cb92db44SToby Isaac       for (d = 0; d < dim; d++) invJ[d * dim + d] = 1.;
1185cb92db44SToby Isaac     }
1186cb92db44SToby Isaac   }
1187cb92db44SToby Isaac   PetscFunctionReturn(0);
1188cb92db44SToby Isaac }
1189cb92db44SToby Isaac 
11906858538eSMatthew G. Knepley /*@C
11916858538eSMatthew G. Knepley   DMPlexGetCellCoordinates - Get coordinates for a cell, taking into account periodicity
11926858538eSMatthew G. Knepley 
11936858538eSMatthew G. Knepley   Not collective
11946858538eSMatthew G. Knepley 
11956858538eSMatthew G. Knepley   Input Parameters:
11966858538eSMatthew G. Knepley + dm   - The DM
11976858538eSMatthew G. Knepley - cell - The cell number
11986858538eSMatthew G. Knepley 
11996858538eSMatthew G. Knepley   Output Parameters:
12006858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
12016858538eSMatthew G. Knepley . Nc     - The number of coordinates
12026858538eSMatthew G. Knepley . array  - The coordinate array
12036858538eSMatthew G. Knepley - coords - The cell coordinates
12046858538eSMatthew G. Knepley 
12056858538eSMatthew G. Knepley   Level: developer
12066858538eSMatthew G. Knepley 
12076858538eSMatthew G. Knepley .seealso: DMPlexRestoreCellCoordinates(), DMGetCoordinatesLocal(), DMGetCellCoordinatesLocal()
12086858538eSMatthew G. Knepley @*/
12096858538eSMatthew G. Knepley PetscErrorCode DMPlexGetCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
12106858538eSMatthew G. Knepley {
12116858538eSMatthew G. Knepley   DM                 cdm;
12126858538eSMatthew G. Knepley   Vec                coordinates;
12136858538eSMatthew G. Knepley   PetscSection       cs;
12146858538eSMatthew G. Knepley   const PetscScalar *ccoords;
12156858538eSMatthew G. Knepley   PetscInt           pStart, pEnd;
12166858538eSMatthew G. Knepley 
12176858538eSMatthew G. Knepley   PetscFunctionBeginHot;
12186858538eSMatthew G. Knepley   *isDG   = PETSC_FALSE;
12196858538eSMatthew G. Knepley   *Nc     = 0;
12206858538eSMatthew G. Knepley   *array  = NULL;
12216858538eSMatthew G. Knepley   *coords = NULL;
12226858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12236858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateSection(dm, &cs));
12246858538eSMatthew G. Knepley   if (!cs) goto cg;
12256858538eSMatthew G. Knepley   /* Check that the cell exists in the cellwise section */
12266858538eSMatthew G. Knepley   PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd));
12276858538eSMatthew G. Knepley   if (cell < pStart || cell >= pEnd) goto cg;
12286858538eSMatthew G. Knepley   /* Check for cellwise coordinates for this cell */
12296858538eSMatthew G. Knepley   PetscCall(PetscSectionGetDof(cs, cell, Nc));
12306858538eSMatthew G. Knepley   if (!*Nc) goto cg;
12316858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12326858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocalNoncollective(dm, &coordinates));
12336858538eSMatthew G. Knepley   if (!coordinates) goto cg;
12346858538eSMatthew G. Knepley   /* Get cellwise coordinates */
12356858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12366858538eSMatthew G. Knepley   PetscCall(VecGetArrayRead(coordinates, array));
12376858538eSMatthew G. Knepley   PetscCall(DMPlexPointLocalRead(cdm, cell, *array, &ccoords));
12386858538eSMatthew G. Knepley   PetscCall(DMGetWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
12396858538eSMatthew G. Knepley   PetscCall(PetscArraycpy(*coords, ccoords, *Nc));
12406858538eSMatthew G. Knepley   PetscCall(VecRestoreArrayRead(coordinates, array));
12416858538eSMatthew G. Knepley   *isDG = PETSC_TRUE;
12426858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12436858538eSMatthew G. Knepley cg:
12446858538eSMatthew G. Knepley   /* Use continuous coordinates */
12456858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
12466858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &cs));
12476858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
12486858538eSMatthew G. Knepley   PetscCall(DMPlexVecGetClosure(cdm, cs, coordinates, cell, Nc, coords));
12496858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12506858538eSMatthew G. Knepley }
12516858538eSMatthew G. Knepley 
12526858538eSMatthew G. Knepley /*@C
12536858538eSMatthew G. Knepley   DMPlexRestoreCellCoordinates - Get coordinates for a cell, taking into account periodicity
12546858538eSMatthew G. Knepley 
12556858538eSMatthew G. Knepley   Not collective
12566858538eSMatthew G. Knepley 
12576858538eSMatthew G. Knepley   Input Parameters:
12586858538eSMatthew G. Knepley + dm   - The DM
12596858538eSMatthew G. Knepley - cell - The cell number
12606858538eSMatthew G. Knepley 
12616858538eSMatthew G. Knepley   Output Parameters:
12626858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
12636858538eSMatthew G. Knepley . Nc     - The number of coordinates
12646858538eSMatthew G. Knepley . array  - The coordinate array
12656858538eSMatthew G. Knepley - coords - The cell coordinates
12666858538eSMatthew G. Knepley 
12676858538eSMatthew G. Knepley   Level: developer
12686858538eSMatthew G. Knepley 
12696858538eSMatthew G. Knepley .seealso: DMPlexGetCellCoordinates(), DMGetCoordinatesLocal(), DMGetCellCoordinatesLocal()
12706858538eSMatthew G. Knepley @*/
12716858538eSMatthew G. Knepley PetscErrorCode DMPlexRestoreCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
12726858538eSMatthew G. Knepley {
12736858538eSMatthew G. Knepley   DM           cdm;
12746858538eSMatthew G. Knepley   PetscSection cs;
12756858538eSMatthew G. Knepley   Vec          coordinates;
12766858538eSMatthew G. Knepley 
12776858538eSMatthew G. Knepley   PetscFunctionBeginHot;
12786858538eSMatthew G. Knepley   if (*isDG) {
12796858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12806858538eSMatthew G. Knepley     PetscCall(DMRestoreWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
12816858538eSMatthew G. Knepley   } else {
12826858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
12836858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &cs));
12846858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
12856858538eSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(cdm, cs, coordinates, cell, Nc, (PetscScalar **) coords));
12866858538eSMatthew G. Knepley   }
12876858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12886858538eSMatthew G. Knepley }
12896858538eSMatthew G. Knepley 
129017fe8556SMatthew G. Knepley static PetscErrorCode DMPlexComputeLineGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
129117fe8556SMatthew G. Knepley {
12926858538eSMatthew G. Knepley   const PetscScalar *array;
1293a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
12946858538eSMatthew G. Knepley   PetscInt           numCoords, d;
12956858538eSMatthew G. Knepley   PetscBool          isDG;
129617fe8556SMatthew G. Knepley 
129717fe8556SMatthew G. Knepley   PetscFunctionBegin;
12986858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
129908401ef6SPierre Jolivet   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
13007f07f362SMatthew G. Knepley   *detJ = 0.0;
130128dbe442SToby Isaac   if (numCoords == 6) {
130228dbe442SToby Isaac     const PetscInt dim = 3;
130328dbe442SToby Isaac     PetscReal      R[9], J0;
130428dbe442SToby Isaac 
130528dbe442SToby Isaac     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13069566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto1D(coords, R));
130728dbe442SToby Isaac     if (J) {
130828dbe442SToby Isaac       J0   = 0.5*PetscRealPart(coords[1]);
130928dbe442SToby Isaac       J[0] = R[0]*J0; J[1] = R[1]; J[2] = R[2];
131028dbe442SToby Isaac       J[3] = R[3]*J0; J[4] = R[4]; J[5] = R[5];
131128dbe442SToby Isaac       J[6] = R[6]*J0; J[7] = R[7]; J[8] = R[8];
131228dbe442SToby Isaac       DMPlex_Det3D_Internal(detJ, J);
131328dbe442SToby Isaac       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
1314adac9986SMatthew G. Knepley     }
131528dbe442SToby Isaac   } else if (numCoords == 4) {
13167f07f362SMatthew G. Knepley     const PetscInt dim = 2;
13177f07f362SMatthew G. Knepley     PetscReal      R[4], J0;
13187f07f362SMatthew G. Knepley 
13197f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13209566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection2Dto1D(coords, R));
132117fe8556SMatthew G. Knepley     if (J) {
13227f07f362SMatthew G. Knepley       J0   = 0.5*PetscRealPart(coords[1]);
13237f07f362SMatthew G. Knepley       J[0] = R[0]*J0; J[1] = R[1];
13247f07f362SMatthew G. Knepley       J[2] = R[2]*J0; J[3] = R[3];
1325923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1326923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
1327adac9986SMatthew G. Knepley     }
13287f07f362SMatthew G. Knepley   } else if (numCoords == 2) {
13297f07f362SMatthew G. Knepley     const PetscInt dim = 1;
13307f07f362SMatthew G. Knepley 
13317f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13327f07f362SMatthew G. Knepley     if (J) {
13337f07f362SMatthew G. Knepley       J[0]  = 0.5*(PetscRealPart(coords[1]) - PetscRealPart(coords[0]));
133417fe8556SMatthew G. Knepley       *detJ = J[0];
13359566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(2.0));
13369566063dSJacob Faibussowitsch       if (invJ) {invJ[0] = 1.0/J[0]; PetscCall(PetscLogFlops(1.0));}
1337adac9986SMatthew G. Knepley     }
13386858538eSMatthew 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);
13396858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
134017fe8556SMatthew G. Knepley   PetscFunctionReturn(0);
134117fe8556SMatthew G. Knepley }
134217fe8556SMatthew G. Knepley 
1343ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexComputeTriangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1344ccd2543fSMatthew G Knepley {
13456858538eSMatthew G. Knepley   const PetscScalar *array;
1346a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
13476858538eSMatthew G. Knepley   PetscInt           numCoords, d;
13486858538eSMatthew G. Knepley   PetscBool          isDG;
1349ccd2543fSMatthew G Knepley 
1350ccd2543fSMatthew G Knepley   PetscFunctionBegin;
13516858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
13526858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
13537f07f362SMatthew G. Knepley   *detJ = 0.0;
1354ccd2543fSMatthew G Knepley   if (numCoords == 9) {
13557f07f362SMatthew G. Knepley     const PetscInt dim = 3;
13567f07f362SMatthew 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};
13577f07f362SMatthew G. Knepley 
13587f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13599566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
13607f07f362SMatthew G. Knepley     if (J) {
1361b7ad821dSMatthew G. Knepley       const PetscInt pdim = 2;
1362b7ad821dSMatthew G. Knepley 
1363b7ad821dSMatthew G. Knepley       for (d = 0; d < pdim; d++) {
13646858538eSMatthew G. Knepley         for (PetscInt f = 0; f < pdim; f++) {
1365b7ad821dSMatthew G. Knepley           J0[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*pdim+d]) - PetscRealPart(coords[0*pdim+d]));
1366ccd2543fSMatthew G Knepley         }
13677f07f362SMatthew G. Knepley       }
13689566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1369923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J0);
13707f07f362SMatthew G. Knepley       for (d = 0; d < dim; d++) {
13716858538eSMatthew G. Knepley         for (PetscInt f = 0; f < dim; f++) {
13727f07f362SMatthew G. Knepley           J[d*dim+f] = 0.0;
13736858538eSMatthew G. Knepley           for (PetscInt g = 0; g < dim; g++) {
13747f07f362SMatthew G. Knepley             J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
13757f07f362SMatthew G. Knepley           }
13767f07f362SMatthew G. Knepley         }
13777f07f362SMatthew G. Knepley       }
13789566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
13797f07f362SMatthew G. Knepley     }
1380923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
13817f07f362SMatthew G. Knepley   } else if (numCoords == 6) {
13827f07f362SMatthew G. Knepley     const PetscInt dim = 2;
13837f07f362SMatthew G. Knepley 
13847f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
1385ccd2543fSMatthew G Knepley     if (J) {
1386ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
13876858538eSMatthew G. Knepley         for (PetscInt f = 0; f < dim; f++) {
1388ccd2543fSMatthew G Knepley           J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
1389ccd2543fSMatthew G Knepley         }
1390ccd2543fSMatthew G Knepley       }
13919566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1392923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1393ccd2543fSMatthew G Knepley     }
1394923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
139563a3b9bcSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this triangle is %" PetscInt_FMT " != 6 or 9", numCoords);
13966858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1397ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1398ccd2543fSMatthew G Knepley }
1399ccd2543fSMatthew G Knepley 
1400412e9a14SMatthew G. Knepley static PetscErrorCode DMPlexComputeRectangleGeometry_Internal(DM dm, PetscInt e, PetscBool isTensor, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1401ccd2543fSMatthew G Knepley {
14026858538eSMatthew G. Knepley   const PetscScalar *array;
1403a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
14046858538eSMatthew G. Knepley   PetscInt           numCoords, d;
14056858538eSMatthew G. Knepley   PetscBool          isDG;
1406ccd2543fSMatthew G Knepley 
1407ccd2543fSMatthew G Knepley   PetscFunctionBegin;
14086858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
14096858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1410dfccc68fSToby Isaac   if (!Nq) {
1411412e9a14SMatthew G. Knepley     PetscInt vorder[4] = {0, 1, 2, 3};
1412412e9a14SMatthew G. Knepley 
1413412e9a14SMatthew G. Knepley     if (isTensor) {vorder[2] = 3; vorder[3] = 2;}
14147f07f362SMatthew G. Knepley     *detJ = 0.0;
141599dec3a6SMatthew G. Knepley     if (numCoords == 12) {
141699dec3a6SMatthew G. Knepley       const PetscInt dim = 3;
141799dec3a6SMatthew 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};
141899dec3a6SMatthew G. Knepley 
1419dfccc68fSToby Isaac       if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
14209566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
142199dec3a6SMatthew G. Knepley       if (J) {
142299dec3a6SMatthew G. Knepley         const PetscInt pdim = 2;
142399dec3a6SMatthew G. Knepley 
142499dec3a6SMatthew G. Knepley         for (d = 0; d < pdim; d++) {
1425412e9a14SMatthew G. Knepley           J0[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*pdim+d]) - PetscRealPart(coords[vorder[0]*pdim+d]));
1426412e9a14SMatthew G. Knepley           J0[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[2]*pdim+d]) - PetscRealPart(coords[vorder[1]*pdim+d]));
142799dec3a6SMatthew G. Knepley         }
14289566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1429923591dfSMatthew G. Knepley         DMPlex_Det3D_Internal(detJ, J0);
143099dec3a6SMatthew G. Knepley         for (d = 0; d < dim; d++) {
14316858538eSMatthew G. Knepley           for (PetscInt f = 0; f < dim; f++) {
143299dec3a6SMatthew G. Knepley             J[d*dim+f] = 0.0;
14336858538eSMatthew G. Knepley             for (PetscInt g = 0; g < dim; g++) {
143499dec3a6SMatthew G. Knepley               J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
143599dec3a6SMatthew G. Knepley             }
143699dec3a6SMatthew G. Knepley           }
143799dec3a6SMatthew G. Knepley         }
14389566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(18.0));
143999dec3a6SMatthew G. Knepley       }
1440923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
144171f58de1SToby Isaac     } else if (numCoords == 8) {
144299dec3a6SMatthew G. Knepley       const PetscInt dim = 2;
144399dec3a6SMatthew G. Knepley 
1444dfccc68fSToby Isaac       if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
1445ccd2543fSMatthew G Knepley       if (J) {
1446ccd2543fSMatthew G Knepley         for (d = 0; d < dim; d++) {
1447412e9a14SMatthew G. Knepley           J[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d]));
1448412e9a14SMatthew G. Knepley           J[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[3]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d]));
1449ccd2543fSMatthew G Knepley         }
14509566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1451923591dfSMatthew G. Knepley         DMPlex_Det2D_Internal(detJ, J);
1452ccd2543fSMatthew G Knepley       }
1453923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
145463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1455dfccc68fSToby Isaac   } else {
1456dfccc68fSToby Isaac     const PetscInt Nv = 4;
1457dfccc68fSToby Isaac     const PetscInt dimR = 2;
1458412e9a14SMatthew G. Knepley     PetscInt  zToPlex[4] = {0, 1, 3, 2};
1459dfccc68fSToby Isaac     PetscReal zOrder[12];
1460dfccc68fSToby Isaac     PetscReal zCoeff[12];
1461dfccc68fSToby Isaac     PetscInt  i, j, k, l, dim;
1462dfccc68fSToby Isaac 
1463412e9a14SMatthew G. Knepley     if (isTensor) {zToPlex[2] = 2; zToPlex[3] = 3;}
1464dfccc68fSToby Isaac     if (numCoords == 12) {
1465dfccc68fSToby Isaac       dim = 3;
1466dfccc68fSToby Isaac     } else if (numCoords == 8) {
1467dfccc68fSToby Isaac       dim = 2;
146863a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1469dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1470dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1471dfccc68fSToby Isaac 
1472dfccc68fSToby Isaac       for (j = 0; j < dim; j++) {
1473dfccc68fSToby Isaac         zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1474dfccc68fSToby Isaac       }
1475dfccc68fSToby Isaac     }
1476dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
14772df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: (1 \mp xi) (1 \mp eta):
14782df84da0SMatthew G. Knepley            \phi^0 = (1 - xi - eta + xi eta) --> 1      = 1/4 ( \phi^0 + \phi^1 + \phi^2 + \phi^3)
14792df84da0SMatthew G. Knepley            \phi^1 = (1 + xi - eta - xi eta) --> xi     = 1/4 (-\phi^0 + \phi^1 - \phi^2 + \phi^3)
14802df84da0SMatthew G. Knepley            \phi^2 = (1 - xi + eta - xi eta) --> eta    = 1/4 (-\phi^0 - \phi^1 + \phi^2 + \phi^3)
14812df84da0SMatthew G. Knepley            \phi^3 = (1 + xi + eta + xi eta) --> xi eta = 1/4 ( \phi^0 - \phi^1 - \phi^2 + \phi^3)
14822df84da0SMatthew G. Knepley       */
1483dfccc68fSToby Isaac       zCoeff[dim * 0 + j] = 0.25 * (  zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1484dfccc68fSToby Isaac       zCoeff[dim * 1 + j] = 0.25 * (- zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1485dfccc68fSToby Isaac       zCoeff[dim * 2 + j] = 0.25 * (- zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1486dfccc68fSToby Isaac       zCoeff[dim * 3 + j] = 0.25 * (  zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1487dfccc68fSToby Isaac     }
1488dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1489dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1];
1490dfccc68fSToby Isaac 
1491dfccc68fSToby Isaac       if (v) {
1492dfccc68fSToby Isaac         PetscReal extPoint[4];
1493dfccc68fSToby Isaac 
1494dfccc68fSToby Isaac         extPoint[0] = 1.;
1495dfccc68fSToby Isaac         extPoint[1] = xi;
1496dfccc68fSToby Isaac         extPoint[2] = eta;
1497dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1498dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1499dfccc68fSToby Isaac           PetscReal val = 0.;
1500dfccc68fSToby Isaac 
1501dfccc68fSToby Isaac           for (k = 0; k < Nv; k++) {
1502dfccc68fSToby Isaac             val += extPoint[k] * zCoeff[dim * k + j];
1503dfccc68fSToby Isaac           }
1504dfccc68fSToby Isaac           v[i * dim + j] = val;
1505dfccc68fSToby Isaac         }
1506dfccc68fSToby Isaac       }
1507dfccc68fSToby Isaac       if (J) {
1508dfccc68fSToby Isaac         PetscReal extJ[8];
1509dfccc68fSToby Isaac 
1510dfccc68fSToby Isaac         extJ[0] = 0.;
1511dfccc68fSToby Isaac         extJ[1] = 0.;
1512dfccc68fSToby Isaac         extJ[2] = 1.;
1513dfccc68fSToby Isaac         extJ[3] = 0.;
1514dfccc68fSToby Isaac         extJ[4] = 0.;
1515dfccc68fSToby Isaac         extJ[5] = 1.;
1516dfccc68fSToby Isaac         extJ[6] = eta;
1517dfccc68fSToby Isaac         extJ[7] = xi;
1518dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1519dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1520dfccc68fSToby Isaac             PetscReal val = 0.;
1521dfccc68fSToby Isaac 
1522dfccc68fSToby Isaac             for (l = 0; l < Nv; l++) {
1523dfccc68fSToby Isaac               val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1524dfccc68fSToby Isaac             }
1525dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1526dfccc68fSToby Isaac           }
1527dfccc68fSToby Isaac         }
1528dfccc68fSToby Isaac         if (dim == 3) { /* put the cross product in the third component of the Jacobian */
1529dfccc68fSToby Isaac           PetscReal x, y, z;
1530dfccc68fSToby Isaac           PetscReal *iJ = &J[i * dim * dim];
1531dfccc68fSToby Isaac           PetscReal norm;
1532dfccc68fSToby Isaac 
1533dfccc68fSToby Isaac           x = iJ[1 * dim + 0] * iJ[2 * dim + 1] - iJ[1 * dim + 1] * iJ[2 * dim + 0];
1534dfccc68fSToby Isaac           y = iJ[0 * dim + 1] * iJ[2 * dim + 0] - iJ[0 * dim + 0] * iJ[2 * dim + 1];
1535dfccc68fSToby Isaac           z = iJ[0 * dim + 0] * iJ[1 * dim + 1] - iJ[0 * dim + 1] * iJ[1 * dim + 0];
1536dfccc68fSToby Isaac           norm = PetscSqrtReal(x * x + y * y + z * z);
1537dfccc68fSToby Isaac           iJ[2] = x / norm;
1538dfccc68fSToby Isaac           iJ[5] = y / norm;
1539dfccc68fSToby Isaac           iJ[8] = z / norm;
1540dfccc68fSToby Isaac           DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1541dfccc68fSToby Isaac           if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1542dfccc68fSToby Isaac         } else {
1543dfccc68fSToby Isaac           DMPlex_Det2D_Internal(&detJ[i], &J[i * dim * dim]);
1544dfccc68fSToby Isaac           if (invJ) {DMPlex_Invert2D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1545dfccc68fSToby Isaac         }
1546dfccc68fSToby Isaac       }
1547dfccc68fSToby Isaac     }
1548dfccc68fSToby Isaac   }
15496858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1550ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1551ccd2543fSMatthew G Knepley }
1552ccd2543fSMatthew G Knepley 
1553ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexComputeTetrahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1554ccd2543fSMatthew G Knepley {
15556858538eSMatthew G. Knepley   const PetscScalar *array;
1556a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1557ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
15586858538eSMatthew G. Knepley   PetscInt           numCoords, d;
15596858538eSMatthew G. Knepley   PetscBool          isDG;
1560ccd2543fSMatthew G Knepley 
1561ccd2543fSMatthew G Knepley   PetscFunctionBegin;
15626858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
15636858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
15647f07f362SMatthew G. Knepley   *detJ = 0.0;
15657f07f362SMatthew G. Knepley   if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
1566ccd2543fSMatthew G Knepley   if (J) {
1567ccd2543fSMatthew G Knepley     for (d = 0; d < dim; d++) {
1568f0df753eSMatthew G. Knepley       /* I orient with outward face normals */
1569f0df753eSMatthew G. Knepley       J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d]));
1570f0df753eSMatthew G. Knepley       J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
1571f0df753eSMatthew G. Knepley       J[d*dim+2] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
1572ccd2543fSMatthew G Knepley     }
15739566063dSJacob Faibussowitsch     PetscCall(PetscLogFlops(18.0));
1574923591dfSMatthew G. Knepley     DMPlex_Det3D_Internal(detJ, J);
1575ccd2543fSMatthew G Knepley   }
1576923591dfSMatthew G. Knepley   if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
15776858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1578ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1579ccd2543fSMatthew G Knepley }
1580ccd2543fSMatthew G Knepley 
1581dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeHexahedronGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1582ccd2543fSMatthew G Knepley {
15836858538eSMatthew G. Knepley   const PetscScalar *array;
1584a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1585ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
15866858538eSMatthew G. Knepley   PetscInt           numCoords, d;
15876858538eSMatthew G. Knepley   PetscBool          isDG;
1588ccd2543fSMatthew G Knepley 
1589ccd2543fSMatthew G Knepley   PetscFunctionBegin;
15906858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
15916858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1592dfccc68fSToby Isaac   if (!Nq) {
15937f07f362SMatthew G. Knepley     *detJ = 0.0;
1594dfccc68fSToby Isaac     if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
1595ccd2543fSMatthew G Knepley     if (J) {
1596ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
1597f0df753eSMatthew G. Knepley         J[d*dim+0] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
1598f0df753eSMatthew G. Knepley         J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
1599f0df753eSMatthew G. Knepley         J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d]));
1600ccd2543fSMatthew G Knepley       }
16019566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
1602923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
1603ccd2543fSMatthew G Knepley     }
1604923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
1605dfccc68fSToby Isaac   } else {
1606dfccc68fSToby Isaac     const PetscInt Nv = 8;
1607dfccc68fSToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
1608dfccc68fSToby Isaac     const PetscInt dim = 3;
1609dfccc68fSToby Isaac     const PetscInt dimR = 3;
1610dfccc68fSToby Isaac     PetscReal zOrder[24];
1611dfccc68fSToby Isaac     PetscReal zCoeff[24];
1612dfccc68fSToby Isaac     PetscInt  i, j, k, l;
1613dfccc68fSToby Isaac 
1614dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1615dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1616dfccc68fSToby Isaac 
1617dfccc68fSToby Isaac       for (j = 0; j < dim; j++) {
1618dfccc68fSToby Isaac         zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1619dfccc68fSToby Isaac       }
1620dfccc68fSToby Isaac     }
1621dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
1622dfccc68fSToby 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]);
1623dfccc68fSToby 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]);
1624dfccc68fSToby 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]);
1625dfccc68fSToby 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]);
1626dfccc68fSToby 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]);
1627dfccc68fSToby 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]);
1628dfccc68fSToby 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]);
1629dfccc68fSToby 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]);
1630dfccc68fSToby Isaac     }
1631dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1632dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], theta = points[dimR * i + 2];
1633dfccc68fSToby Isaac 
1634dfccc68fSToby Isaac       if (v) {
163591d2b7ceSToby Isaac         PetscReal extPoint[8];
1636dfccc68fSToby Isaac 
1637dfccc68fSToby Isaac         extPoint[0] = 1.;
1638dfccc68fSToby Isaac         extPoint[1] = xi;
1639dfccc68fSToby Isaac         extPoint[2] = eta;
1640dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1641dfccc68fSToby Isaac         extPoint[4] = theta;
1642dfccc68fSToby Isaac         extPoint[5] = theta * xi;
1643dfccc68fSToby Isaac         extPoint[6] = theta * eta;
1644dfccc68fSToby Isaac         extPoint[7] = theta * eta * xi;
1645dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1646dfccc68fSToby Isaac           PetscReal val = 0.;
1647dfccc68fSToby Isaac 
1648dfccc68fSToby Isaac           for (k = 0; k < Nv; k++) {
1649dfccc68fSToby Isaac             val += extPoint[k] * zCoeff[dim * k + j];
1650dfccc68fSToby Isaac           }
1651dfccc68fSToby Isaac           v[i * dim + j] = val;
1652dfccc68fSToby Isaac         }
1653dfccc68fSToby Isaac       }
1654dfccc68fSToby Isaac       if (J) {
1655dfccc68fSToby Isaac         PetscReal extJ[24];
1656dfccc68fSToby Isaac 
1657dfccc68fSToby Isaac         extJ[0]  = 0.         ; extJ[1]  = 0.        ; extJ[2]  = 0.      ;
1658dfccc68fSToby Isaac         extJ[3]  = 1.         ; extJ[4]  = 0.        ; extJ[5]  = 0.      ;
1659dfccc68fSToby Isaac         extJ[6]  = 0.         ; extJ[7]  = 1.        ; extJ[8]  = 0.      ;
1660dfccc68fSToby Isaac         extJ[9]  = eta        ; extJ[10] = xi        ; extJ[11] = 0.      ;
1661dfccc68fSToby Isaac         extJ[12] = 0.         ; extJ[13] = 0.        ; extJ[14] = 1.      ;
1662dfccc68fSToby Isaac         extJ[15] = theta      ; extJ[16] = 0.        ; extJ[17] = xi      ;
1663dfccc68fSToby Isaac         extJ[18] = 0.         ; extJ[19] = theta     ; extJ[20] = eta     ;
1664dfccc68fSToby Isaac         extJ[21] = theta * eta; extJ[22] = theta * xi; extJ[23] = eta * xi;
1665dfccc68fSToby Isaac 
1666dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1667dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1668dfccc68fSToby Isaac             PetscReal val = 0.;
1669dfccc68fSToby Isaac 
1670dfccc68fSToby Isaac             for (l = 0; l < Nv; l++) {
1671dfccc68fSToby Isaac               val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1672dfccc68fSToby Isaac             }
1673dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1674dfccc68fSToby Isaac           }
1675dfccc68fSToby Isaac         }
1676dfccc68fSToby Isaac         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1677dfccc68fSToby Isaac         if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1678dfccc68fSToby Isaac       }
1679dfccc68fSToby Isaac     }
1680dfccc68fSToby Isaac   }
16816858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1682ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1683ccd2543fSMatthew G Knepley }
1684ccd2543fSMatthew G Knepley 
16852df84da0SMatthew G. Knepley static PetscErrorCode DMPlexComputeTriangularPrismGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
16862df84da0SMatthew G. Knepley {
16876858538eSMatthew G. Knepley   const PetscScalar *array;
16882df84da0SMatthew G. Knepley   PetscScalar       *coords = NULL;
16892df84da0SMatthew G. Knepley   const PetscInt     dim    = 3;
16906858538eSMatthew G. Knepley   PetscInt           numCoords, d;
16916858538eSMatthew G. Knepley   PetscBool          isDG;
16922df84da0SMatthew G. Knepley 
16932df84da0SMatthew G. Knepley   PetscFunctionBegin;
16946858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16956858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
16962df84da0SMatthew G. Knepley   if (!Nq) {
16972df84da0SMatthew G. Knepley     /* Assume that the map to the reference is affine */
16982df84da0SMatthew G. Knepley     *detJ = 0.0;
16992df84da0SMatthew G. Knepley     if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
17002df84da0SMatthew G. Knepley     if (J) {
17012df84da0SMatthew G. Knepley       for (d = 0; d < dim; d++) {
17022df84da0SMatthew G. Knepley         J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d]));
17032df84da0SMatthew G. Knepley         J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
17042df84da0SMatthew G. Knepley         J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d]));
17052df84da0SMatthew G. Knepley       }
17069566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
17072df84da0SMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
17082df84da0SMatthew G. Knepley     }
17092df84da0SMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
17102df84da0SMatthew G. Knepley   } else {
17112df84da0SMatthew G. Knepley     const PetscInt dim  = 3;
17122df84da0SMatthew G. Knepley     const PetscInt dimR = 3;
17132df84da0SMatthew G. Knepley     const PetscInt Nv   = 6;
17142df84da0SMatthew G. Knepley     PetscReal verts[18];
17152df84da0SMatthew G. Knepley     PetscReal coeff[18];
17162df84da0SMatthew G. Knepley     PetscInt  i, j, k, l;
17172df84da0SMatthew G. Knepley 
17182df84da0SMatthew G. Knepley     for (i = 0; i < Nv; ++i) for (j = 0; j < dim; ++j) verts[dim * i + j] = PetscRealPart(coords[dim * i + j]);
17192df84da0SMatthew G. Knepley     for (j = 0; j < dim; ++j) {
17202df84da0SMatthew G. Knepley       /* Check for triangle,
17212df84da0SMatthew 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)
17222df84da0SMatthew 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)
17232df84da0SMatthew G. Knepley            phi^2 =  1/2 (1 + eta)   chi^2 = delta(-1,  1)
17242df84da0SMatthew G. Knepley 
17252df84da0SMatthew G. Knepley            phi^0 + phi^1 + phi^2 = 1    coef_1   = 1/2 (         chi^1 + chi^2)
17262df84da0SMatthew G. Knepley           -phi^0 + phi^1 - phi^2 = xi   coef_xi  = 1/2 (-chi^0 + chi^1)
17272df84da0SMatthew G. Knepley           -phi^0 - phi^1 + phi^2 = eta  coef_eta = 1/2 (-chi^0         + chi^2)
17282df84da0SMatthew G. Knepley 
17292df84da0SMatthew G. Knepley           < chi_0 chi_1 chi_2> A /  1  1  1 \ / phi_0 \   <chi> I <phi>^T  so we need the inverse transpose
17302df84da0SMatthew G. Knepley                                  | -1  1 -1 | | phi_1 | =
17312df84da0SMatthew G. Knepley                                  \ -1 -1  1 / \ phi_2 /
17322df84da0SMatthew G. Knepley 
17332df84da0SMatthew 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
17342df84da0SMatthew G. Knepley       */
17352df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: {-xi - eta, 1 + xi, 1 + eta} (1 \mp zeta):
17362df84da0SMatthew G. Knepley            \phi^0 = 1/4 (   -xi - eta        + xi zeta + eta zeta) --> /  1  1  1  1  1  1 \ 1
17372df84da0SMatthew G. Knepley            \phi^1 = 1/4 (1      + eta - zeta           - eta zeta) --> | -1  1 -1 -1 -1  1 | eta
17382df84da0SMatthew G. Knepley            \phi^2 = 1/4 (1 + xi       - zeta - xi zeta)            --> | -1 -1  1 -1  1 -1 | xi
17392df84da0SMatthew G. Knepley            \phi^3 = 1/4 (   -xi - eta        - xi zeta - eta zeta) --> | -1 -1 -1  1  1  1 | zeta
17402df84da0SMatthew G. Knepley            \phi^4 = 1/4 (1 + xi       + zeta + xi zeta)            --> |  1  1 -1 -1  1 -1 | xi zeta
17412df84da0SMatthew G. Knepley            \phi^5 = 1/4 (1      + eta + zeta           + eta zeta) --> \  1 -1  1 -1 -1  1 / eta zeta
17422df84da0SMatthew G. Knepley            1/4 /  0  1  1  0  1  1 \
17432df84da0SMatthew G. Knepley                | -1  1  0 -1  0  1 |
17442df84da0SMatthew G. Knepley                | -1  0  1 -1  1  0 |
17452df84da0SMatthew G. Knepley                |  0 -1 -1  0  1  1 |
17462df84da0SMatthew G. Knepley                |  1  0 -1 -1  1  0 |
17472df84da0SMatthew G. Knepley                \  1 -1  0 -1  0  1 /
17482df84da0SMatthew G. Knepley       */
17492df84da0SMatthew G. Knepley       coeff[dim * 0 + j] = (1./4.) * (                      verts[dim * 1 + j] + verts[dim * 2 + j]                      + verts[dim * 4 + j] + verts[dim * 5 + j]);
17502df84da0SMatthew G. Knepley       coeff[dim * 1 + j] = (1./4.) * (-verts[dim * 0 + j] + verts[dim * 1 + j]                      - verts[dim * 3 + j]                      + verts[dim * 5 + j]);
17512df84da0SMatthew G. Knepley       coeff[dim * 2 + j] = (1./4.) * (-verts[dim * 0 + j]                      + verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
17522df84da0SMatthew G. Knepley       coeff[dim * 3 + j] = (1./4.) * (                    - verts[dim * 1 + j] - verts[dim * 2 + j]                      + verts[dim * 4 + j] + verts[dim * 5 + j]);
17532df84da0SMatthew G. Knepley       coeff[dim * 4 + j] = (1./4.) * ( verts[dim * 0 + j]                      - verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
17542df84da0SMatthew G. Knepley       coeff[dim * 5 + j] = (1./4.) * ( verts[dim * 0 + j] - verts[dim * 1 + j]                      - verts[dim * 3 + j]                      + verts[dim * 5 + j]);
17552df84da0SMatthew G. Knepley       /* For reference prism:
17562df84da0SMatthew G. Knepley       {0, 0, 0}
17572df84da0SMatthew G. Knepley       {0, 1, 0}
17582df84da0SMatthew G. Knepley       {1, 0, 0}
17592df84da0SMatthew G. Knepley       {0, 0, 1}
17602df84da0SMatthew G. Knepley       {0, 0, 0}
17612df84da0SMatthew G. Knepley       {0, 0, 0}
17622df84da0SMatthew G. Knepley       */
17632df84da0SMatthew G. Knepley     }
17642df84da0SMatthew G. Knepley     for (i = 0; i < Nq; ++i) {
17652df84da0SMatthew G. Knepley       const PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], zeta = points[dimR * i + 2];
17662df84da0SMatthew G. Knepley 
17672df84da0SMatthew G. Knepley       if (v) {
17682df84da0SMatthew G. Knepley         PetscReal extPoint[6];
17692df84da0SMatthew G. Knepley         PetscInt  c;
17702df84da0SMatthew G. Knepley 
17712df84da0SMatthew G. Knepley         extPoint[0] = 1.;
17722df84da0SMatthew G. Knepley         extPoint[1] = eta;
17732df84da0SMatthew G. Knepley         extPoint[2] = xi;
17742df84da0SMatthew G. Knepley         extPoint[3] = zeta;
17752df84da0SMatthew G. Knepley         extPoint[4] = xi * zeta;
17762df84da0SMatthew G. Knepley         extPoint[5] = eta * zeta;
17772df84da0SMatthew G. Knepley         for (c = 0; c < dim; ++c) {
17782df84da0SMatthew G. Knepley           PetscReal val = 0.;
17792df84da0SMatthew G. Knepley 
17802df84da0SMatthew G. Knepley           for (k = 0; k < Nv; ++k) {
17812df84da0SMatthew G. Knepley             val += extPoint[k] * coeff[k*dim + c];
17822df84da0SMatthew G. Knepley           }
17832df84da0SMatthew G. Knepley           v[i*dim + c] = val;
17842df84da0SMatthew G. Knepley         }
17852df84da0SMatthew G. Knepley       }
17862df84da0SMatthew G. Knepley       if (J) {
17872df84da0SMatthew G. Knepley         PetscReal extJ[18];
17882df84da0SMatthew G. Knepley 
17892df84da0SMatthew G. Knepley         extJ[0]  = 0.  ; extJ[1]  = 0.  ; extJ[2]  = 0. ;
17902df84da0SMatthew G. Knepley         extJ[3]  = 0.  ; extJ[4]  = 1.  ; extJ[5]  = 0. ;
17912df84da0SMatthew G. Knepley         extJ[6]  = 1.  ; extJ[7]  = 0.  ; extJ[8]  = 0. ;
17922df84da0SMatthew G. Knepley         extJ[9]  = 0.  ; extJ[10] = 0.  ; extJ[11] = 1. ;
17932df84da0SMatthew G. Knepley         extJ[12] = zeta; extJ[13] = 0.  ; extJ[14] = xi ;
17942df84da0SMatthew G. Knepley         extJ[15] = 0.  ; extJ[16] = zeta; extJ[17] = eta;
17952df84da0SMatthew G. Knepley 
17962df84da0SMatthew G. Knepley         for (j = 0; j < dim; j++) {
17972df84da0SMatthew G. Knepley           for (k = 0; k < dimR; k++) {
17982df84da0SMatthew G. Knepley             PetscReal val = 0.;
17992df84da0SMatthew G. Knepley 
18002df84da0SMatthew G. Knepley             for (l = 0; l < Nv; l++) {
18012df84da0SMatthew G. Knepley               val += coeff[dim * l + j] * extJ[dimR * l + k];
18022df84da0SMatthew G. Knepley             }
18032df84da0SMatthew G. Knepley             J[i * dim * dim + dim * j + k] = val;
18042df84da0SMatthew G. Knepley           }
18052df84da0SMatthew G. Knepley         }
18062df84da0SMatthew G. Knepley         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
18072df84da0SMatthew G. Knepley         if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
18082df84da0SMatthew G. Knepley       }
18092df84da0SMatthew G. Knepley     }
18102df84da0SMatthew G. Knepley   }
18116858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
18122df84da0SMatthew G. Knepley   PetscFunctionReturn(0);
18132df84da0SMatthew G. Knepley }
18142df84da0SMatthew G. Knepley 
1815dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeCellGeometryFEM_Implicit(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
1816dfccc68fSToby Isaac {
1817ba2698f1SMatthew G. Knepley   DMPolytopeType  ct;
1818dfccc68fSToby Isaac   PetscInt        depth, dim, coordDim, coneSize, i;
1819dfccc68fSToby Isaac   PetscInt        Nq = 0;
1820dfccc68fSToby Isaac   const PetscReal *points = NULL;
1821dfccc68fSToby Isaac   DMLabel         depthLabel;
1822c330f8ffSToby Isaac   PetscReal       xi0[3] = {-1.,-1.,-1.}, v0[3], J0[9], detJ0;
1823dfccc68fSToby Isaac   PetscBool       isAffine = PETSC_TRUE;
1824dfccc68fSToby Isaac 
1825dfccc68fSToby Isaac   PetscFunctionBegin;
18269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
18279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
18289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
18299566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(depthLabel, cell, &dim));
1830dfccc68fSToby Isaac   if (depth == 1 && dim == 1) {
18319566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
1832dfccc68fSToby Isaac   }
18339566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
183463a3b9bcSJacob Faibussowitsch   PetscCheck(coordDim <= 3,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported coordinate dimension %" PetscInt_FMT " > 3", coordDim);
18359566063dSJacob Faibussowitsch   if (quad) PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &points, NULL));
18369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1837ba2698f1SMatthew G. Knepley   switch (ct) {
1838ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_POINT:
18399566063dSJacob Faibussowitsch     PetscCall(DMPlexComputePointGeometry_Internal(dm, cell, v, J, invJ, detJ));
1840dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1841dfccc68fSToby Isaac     break;
1842ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
1843412e9a14SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
18449566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18459566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1846dfccc68fSToby Isaac     break;
1847ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
18489566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18499566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1850dfccc68fSToby Isaac     break;
1851ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
18529566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_FALSE, Nq, points, v, J, invJ, detJ));
1853412e9a14SMatthew G. Knepley     isAffine = PETSC_FALSE;
1854412e9a14SMatthew G. Knepley     break;
1855412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
18569566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_TRUE, Nq, points, v, J, invJ, detJ));
1857dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1858dfccc68fSToby Isaac     break;
1859ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
18609566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18619566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1862dfccc68fSToby Isaac     break;
1863ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
18649566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeHexahedronGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
1865dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1866dfccc68fSToby Isaac     break;
18672df84da0SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
18689566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeTriangularPrismGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
18692df84da0SMatthew G. Knepley     isAffine = PETSC_FALSE;
18702df84da0SMatthew G. Knepley     break;
18712df84da0SMatthew G. Knepley     default: 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))]);
1872dfccc68fSToby Isaac   }
18737318780aSToby Isaac   if (isAffine && Nq) {
1874dfccc68fSToby Isaac     if (v) {
1875dfccc68fSToby Isaac       for (i = 0; i < Nq; i++) {
1876c330f8ffSToby Isaac         CoordinatesRefToReal(coordDim, dim, xi0, v0, J0, &points[dim * i], &v[coordDim * i]);
1877dfccc68fSToby Isaac       }
1878dfccc68fSToby Isaac     }
18797318780aSToby Isaac     if (detJ) {
18807318780aSToby Isaac       for (i = 0; i < Nq; i++) {
18817318780aSToby Isaac         detJ[i] = detJ0;
1882dfccc68fSToby Isaac       }
18837318780aSToby Isaac     }
18847318780aSToby Isaac     if (J) {
18857318780aSToby Isaac       PetscInt k;
18867318780aSToby Isaac 
18877318780aSToby Isaac       for (i = 0, k = 0; i < Nq; i++) {
1888dfccc68fSToby Isaac         PetscInt j;
1889dfccc68fSToby Isaac 
18907318780aSToby Isaac         for (j = 0; j < coordDim * coordDim; j++, k++) {
18917318780aSToby Isaac           J[k] = J0[j];
18927318780aSToby Isaac         }
18937318780aSToby Isaac       }
18947318780aSToby Isaac     }
18957318780aSToby Isaac     if (invJ) {
18967318780aSToby Isaac       PetscInt k;
18977318780aSToby Isaac       switch (coordDim) {
18987318780aSToby Isaac       case 0:
18997318780aSToby Isaac         break;
19007318780aSToby Isaac       case 1:
19017318780aSToby Isaac         invJ[0] = 1./J0[0];
19027318780aSToby Isaac         break;
19037318780aSToby Isaac       case 2:
19047318780aSToby Isaac         DMPlex_Invert2D_Internal(invJ, J0, detJ0);
19057318780aSToby Isaac         break;
19067318780aSToby Isaac       case 3:
19077318780aSToby Isaac         DMPlex_Invert3D_Internal(invJ, J0, detJ0);
19087318780aSToby Isaac         break;
19097318780aSToby Isaac       }
19107318780aSToby Isaac       for (i = 1, k = coordDim * coordDim; i < Nq; i++) {
19117318780aSToby Isaac         PetscInt j;
19127318780aSToby Isaac 
19137318780aSToby Isaac         for (j = 0; j < coordDim * coordDim; j++, k++) {
19147318780aSToby Isaac           invJ[k] = invJ[j];
19157318780aSToby Isaac         }
1916dfccc68fSToby Isaac       }
1917dfccc68fSToby Isaac     }
1918dfccc68fSToby Isaac   }
1919dfccc68fSToby Isaac   PetscFunctionReturn(0);
1920dfccc68fSToby Isaac }
1921dfccc68fSToby Isaac 
1922ccd2543fSMatthew G Knepley /*@C
19238e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryAffineFEM - Assuming an affine map, compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
1924ccd2543fSMatthew G Knepley 
1925d083f849SBarry Smith   Collective on dm
1926ccd2543fSMatthew G Knepley 
19274165533cSJose E. Roman   Input Parameters:
1928ccd2543fSMatthew G Knepley + dm   - the DM
1929ccd2543fSMatthew G Knepley - cell - the cell
1930ccd2543fSMatthew G Knepley 
19314165533cSJose E. Roman   Output Parameters:
19329b172b3aSMatthew Knepley + v0   - the translation part of this affine transform, meaning the translation to the origin (not the first vertex of the reference cell)
1933ccd2543fSMatthew G Knepley . J    - the Jacobian of the transform from the reference element
1934ccd2543fSMatthew G Knepley . invJ - the inverse of the Jacobian
1935ccd2543fSMatthew G Knepley - detJ - the Jacobian determinant
1936ccd2543fSMatthew G Knepley 
1937ccd2543fSMatthew G Knepley   Level: advanced
1938ccd2543fSMatthew G Knepley 
1939ccd2543fSMatthew G Knepley   Fortran Notes:
1940ccd2543fSMatthew G Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
1941ccd2543fSMatthew G Knepley   include petsc.h90 in your code.
1942ccd2543fSMatthew G Knepley 
1943db781477SPatrick Sanan .seealso: `DMPlexComputeCellGeometryFEM()`, `DMGetCoordinateSection()`, `DMGetCoordinates()`
1944ccd2543fSMatthew G Knepley @*/
19458e0841e0SMatthew G. Knepley PetscErrorCode DMPlexComputeCellGeometryAffineFEM(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
1946ccd2543fSMatthew G Knepley {
1947ccd2543fSMatthew G Knepley   PetscFunctionBegin;
19489566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, NULL, v0, J, invJ, detJ));
19498e0841e0SMatthew G. Knepley   PetscFunctionReturn(0);
19508e0841e0SMatthew G. Knepley }
19518e0841e0SMatthew G. Knepley 
1952dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeCellGeometryFEM_FE(DM dm, PetscFE fe, PetscInt point, PetscQuadrature quad, PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
19538e0841e0SMatthew G. Knepley {
19546858538eSMatthew G. Knepley   const PetscScalar *array;
19558e0841e0SMatthew G. Knepley   PetscScalar       *coords = NULL;
19566858538eSMatthew G. Knepley   PetscInt           numCoords;
19576858538eSMatthew G. Knepley   PetscBool          isDG;
19586858538eSMatthew G. Knepley   PetscQuadrature    feQuad;
19598e0841e0SMatthew G. Knepley   const PetscReal   *quadPoints;
1960ef0bb6c7SMatthew G. Knepley   PetscTabulation    T;
19616858538eSMatthew G. Knepley   PetscInt           dim, cdim, pdim, qdim, Nq, q;
19628e0841e0SMatthew G. Knepley 
19638e0841e0SMatthew G. Knepley   PetscFunctionBegin;
19649566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
19659566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
19666858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
1967dfccc68fSToby Isaac   if (!quad) { /* use the first point of the first functional of the dual space */
1968dfccc68fSToby Isaac     PetscDualSpace dsp;
1969dfccc68fSToby Isaac 
19709566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDualSpace(fe, &dsp));
19719566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(dsp, 0, &quad));
19729566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
1973dfccc68fSToby Isaac     Nq = 1;
1974dfccc68fSToby Isaac   } else {
19759566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
1976dfccc68fSToby Isaac   }
19779566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
19789566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &feQuad));
1979dfccc68fSToby Isaac   if (feQuad == quad) {
19809566063dSJacob Faibussowitsch     PetscCall(PetscFEGetCellTabulation(fe, J ? 1 : 0, &T));
198163a3b9bcSJacob 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);
1982dfccc68fSToby Isaac   } else {
19839566063dSJacob Faibussowitsch     PetscCall(PetscFECreateTabulation(fe, 1, Nq, quadPoints, J ? 1 : 0, &T));
1984dfccc68fSToby Isaac   }
198563a3b9bcSJacob Faibussowitsch   PetscCheck(qdim == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Point dimension %" PetscInt_FMT " != quadrature dimension %" PetscInt_FMT, dim, qdim);
1986ef0bb6c7SMatthew G. Knepley   {
1987ef0bb6c7SMatthew G. Knepley     const PetscReal *basis    = T->T[0];
1988ef0bb6c7SMatthew G. Knepley     const PetscReal *basisDer = T->T[1];
1989ef0bb6c7SMatthew G. Knepley     PetscReal        detJt;
1990ef0bb6c7SMatthew G. Knepley 
1991a2a9e04cSMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
199263a3b9bcSJacob Faibussowitsch     PetscCheck(Nq == T->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Np %" PetscInt_FMT " != %" PetscInt_FMT, Nq, T->Np);
199363a3b9bcSJacob Faibussowitsch     PetscCheck(pdim == T->Nb,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nb %" PetscInt_FMT " != %" PetscInt_FMT, pdim, T->Nb);
199463a3b9bcSJacob Faibussowitsch     PetscCheck(dim == T->Nc,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nc %" PetscInt_FMT " != %" PetscInt_FMT, dim, T->Nc);
199563a3b9bcSJacob Faibussowitsch     PetscCheck(cdim == T->cdim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "cdim %" PetscInt_FMT " != %" PetscInt_FMT, cdim, T->cdim);
1996a2a9e04cSMatthew G. Knepley #endif
1997dfccc68fSToby Isaac     if (v) {
19989566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(v, Nq*cdim));
1999f960e424SToby Isaac       for (q = 0; q < Nq; ++q) {
2000f960e424SToby Isaac         PetscInt i, k;
2001f960e424SToby Isaac 
2002301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
2003301b184aSMatthew G. Knepley           const PetscInt vertex = k/cdim;
2004301b184aSMatthew G. Knepley           for (i = 0; i < cdim; ++i) {
2005301b184aSMatthew G. Knepley             v[q*cdim + i] += basis[(q*pdim + k)*cdim + i] * PetscRealPart(coords[vertex*cdim + i]);
2006301b184aSMatthew G. Knepley           }
2007301b184aSMatthew G. Knepley         }
20089566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0*pdim*cdim));
2009f960e424SToby Isaac       }
2010f960e424SToby Isaac     }
20118e0841e0SMatthew G. Knepley     if (J) {
20129566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(J, Nq*cdim*cdim));
20138e0841e0SMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
20148e0841e0SMatthew G. Knepley         PetscInt i, j, k, c, r;
20158e0841e0SMatthew G. Knepley 
20168e0841e0SMatthew G. Knepley         /* J = dx_i/d\xi_j = sum[k=0,n-1] dN_k/d\xi_j * x_i(k) */
2017301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
2018301b184aSMatthew G. Knepley           const PetscInt vertex = k/cdim;
2019301b184aSMatthew G. Knepley           for (j = 0; j < dim; ++j) {
2020301b184aSMatthew G. Knepley             for (i = 0; i < cdim; ++i) {
2021301b184aSMatthew G. Knepley               J[(q*cdim + i)*cdim + j] += basisDer[((q*pdim + k)*cdim + i)*dim + j] * PetscRealPart(coords[vertex*cdim + i]);
2022301b184aSMatthew G. Knepley             }
2023301b184aSMatthew G. Knepley           }
2024301b184aSMatthew G. Knepley         }
20259566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0*pdim*dim*cdim));
20268e0841e0SMatthew G. Knepley         if (cdim > dim) {
20278e0841e0SMatthew G. Knepley           for (c = dim; c < cdim; ++c)
20288e0841e0SMatthew G. Knepley             for (r = 0; r < cdim; ++r)
20298e0841e0SMatthew G. Knepley               J[r*cdim+c] = r == c ? 1.0 : 0.0;
20308e0841e0SMatthew G. Knepley         }
2031f960e424SToby Isaac         if (!detJ && !invJ) continue;
2032a63b72c6SToby Isaac         detJt = 0.;
20338e0841e0SMatthew G. Knepley         switch (cdim) {
20348e0841e0SMatthew G. Knepley         case 3:
2035037dc194SToby Isaac           DMPlex_Det3D_Internal(&detJt, &J[q*cdim*dim]);
2036037dc194SToby Isaac           if (invJ) {DMPlex_Invert3D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);}
203717fe8556SMatthew G. Knepley           break;
203849dc4407SMatthew G. Knepley         case 2:
20399f328543SToby Isaac           DMPlex_Det2D_Internal(&detJt, &J[q*cdim*dim]);
2040037dc194SToby Isaac           if (invJ) {DMPlex_Invert2D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);}
204149dc4407SMatthew G. Knepley           break;
20428e0841e0SMatthew G. Knepley         case 1:
2043037dc194SToby Isaac           detJt = J[q*cdim*dim];
2044037dc194SToby Isaac           if (invJ) invJ[q*cdim*dim] = 1.0/detJt;
204549dc4407SMatthew G. Knepley         }
2046f960e424SToby Isaac         if (detJ) detJ[q] = detJt;
204749dc4407SMatthew G. Knepley       }
204808401ef6SPierre Jolivet     } else PetscCheck(!detJ && !invJ,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Need J to compute invJ or detJ");
204949dc4407SMatthew G. Knepley   }
20509566063dSJacob Faibussowitsch   if (feQuad != quad) PetscCall(PetscTabulationDestroy(&T));
20516858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
20528e0841e0SMatthew G. Knepley   PetscFunctionReturn(0);
20538e0841e0SMatthew G. Knepley }
20548e0841e0SMatthew G. Knepley 
20558e0841e0SMatthew G. Knepley /*@C
20568e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryFEM - Compute the Jacobian, inverse Jacobian, and Jacobian determinant at each quadrature point in the given cell
20578e0841e0SMatthew G. Knepley 
2058d083f849SBarry Smith   Collective on dm
20598e0841e0SMatthew G. Knepley 
20604165533cSJose E. Roman   Input Parameters:
20618e0841e0SMatthew G. Knepley + dm   - the DM
20628e0841e0SMatthew G. Knepley . cell - the cell
2063dfccc68fSToby Isaac - quad - the quadrature containing the points in the reference element where the geometry will be evaluated.  If quad == NULL, geometry will be
2064dfccc68fSToby Isaac          evaluated at the first vertex of the reference element
20658e0841e0SMatthew G. Knepley 
20664165533cSJose E. Roman   Output Parameters:
2067dfccc68fSToby Isaac + v    - the image of the transformed quadrature points, otherwise the image of the first vertex in the closure of the reference element
20688e0841e0SMatthew G. Knepley . J    - the Jacobian of the transform from the reference element at each quadrature point
20698e0841e0SMatthew G. Knepley . invJ - the inverse of the Jacobian at each quadrature point
20708e0841e0SMatthew G. Knepley - detJ - the Jacobian determinant at each quadrature point
20718e0841e0SMatthew G. Knepley 
20728e0841e0SMatthew G. Knepley   Level: advanced
20738e0841e0SMatthew G. Knepley 
20748e0841e0SMatthew G. Knepley   Fortran Notes:
20758e0841e0SMatthew G. Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
20768e0841e0SMatthew G. Knepley   include petsc.h90 in your code.
20778e0841e0SMatthew G. Knepley 
2078db781477SPatrick Sanan .seealso: `DMGetCoordinateSection()`, `DMGetCoordinates()`
20798e0841e0SMatthew G. Knepley @*/
2080dfccc68fSToby Isaac PetscErrorCode DMPlexComputeCellGeometryFEM(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
20818e0841e0SMatthew G. Knepley {
2082bb4a5db5SMatthew G. Knepley   DM             cdm;
2083dfccc68fSToby Isaac   PetscFE        fe = NULL;
20848e0841e0SMatthew G. Knepley 
20858e0841e0SMatthew G. Knepley   PetscFunctionBegin;
2086dadcf809SJacob Faibussowitsch   PetscValidRealPointer(detJ, 7);
20879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2088bb4a5db5SMatthew G. Knepley   if (cdm) {
2089dfccc68fSToby Isaac     PetscClassId id;
2090dfccc68fSToby Isaac     PetscInt     numFields;
2091e5e52638SMatthew G. Knepley     PetscDS      prob;
2092dfccc68fSToby Isaac     PetscObject  disc;
2093dfccc68fSToby Isaac 
20949566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(cdm, &numFields));
2095dfccc68fSToby Isaac     if (numFields) {
20969566063dSJacob Faibussowitsch       PetscCall(DMGetDS(cdm, &prob));
20979566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob,0,&disc));
20989566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
2099dfccc68fSToby Isaac       if (id == PETSCFE_CLASSID) {
2100dfccc68fSToby Isaac         fe = (PetscFE) disc;
2101dfccc68fSToby Isaac       }
2102dfccc68fSToby Isaac     }
2103dfccc68fSToby Isaac   }
21049566063dSJacob Faibussowitsch   if (!fe) PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, quad, v, J, invJ, detJ));
21059566063dSJacob Faibussowitsch   else     PetscCall(DMPlexComputeCellGeometryFEM_FE(dm, fe, cell, quad, v, J, invJ, detJ));
2106ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
2107ccd2543fSMatthew G Knepley }
2108834e62ceSMatthew G. Knepley 
21099bf2564aSMatt McGurn static PetscErrorCode DMPlexComputeGeometryFVM_0D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
21109bf2564aSMatt McGurn {
21119bf2564aSMatt McGurn   PetscSection        coordSection;
21129bf2564aSMatt McGurn   Vec                 coordinates;
21139bf2564aSMatt McGurn   const PetscScalar  *coords = NULL;
21149bf2564aSMatt McGurn   PetscInt            d, dof, off;
21159bf2564aSMatt McGurn 
21169bf2564aSMatt McGurn   PetscFunctionBegin;
21179566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
21189566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
21199566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
21209bf2564aSMatt McGurn 
21219bf2564aSMatt McGurn   /* for a point the centroid is just the coord */
21229bf2564aSMatt McGurn   if (centroid) {
21239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
21249566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
21259bf2564aSMatt McGurn     for (d = 0; d < dof; d++){
21269bf2564aSMatt McGurn       centroid[d] = PetscRealPart(coords[off + d]);
21279bf2564aSMatt McGurn     }
21289bf2564aSMatt McGurn   }
21299bf2564aSMatt McGurn   if (normal) {
21309bf2564aSMatt McGurn     const PetscInt *support, *cones;
21319bf2564aSMatt McGurn     PetscInt        supportSize;
21329bf2564aSMatt McGurn     PetscReal       norm, sign;
21339bf2564aSMatt McGurn 
21349bf2564aSMatt McGurn     /* compute the norm based upon the support centroids */
21359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, cell, &supportSize));
21369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, cell, &support));
21379566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, support[0], NULL, normal, NULL));
21389bf2564aSMatt McGurn 
21399bf2564aSMatt McGurn     /* Take the normal from the centroid of the support to the vertex*/
21409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
21419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
21429bf2564aSMatt McGurn     for (d = 0; d < dof; d++){
21439bf2564aSMatt McGurn       normal[d] -= PetscRealPart(coords[off + d]);
21449bf2564aSMatt McGurn     }
21459bf2564aSMatt McGurn 
21469bf2564aSMatt McGurn     /* Determine the sign of the normal based upon its location in the support */
21479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, support[0], &cones));
21489bf2564aSMatt McGurn     sign = cones[0] == cell ? 1.0 : -1.0;
21499bf2564aSMatt McGurn 
21509bf2564aSMatt McGurn     norm = DMPlex_NormD_Internal(dim, normal);
21519bf2564aSMatt McGurn     for (d = 0; d < dim; ++d) normal[d] /= (norm*sign);
21529bf2564aSMatt McGurn   }
21539bf2564aSMatt McGurn   if (vol) {
21549bf2564aSMatt McGurn     *vol = 1.0;
21559bf2564aSMatt McGurn   }
21569566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
21579bf2564aSMatt McGurn   PetscFunctionReturn(0);
21589bf2564aSMatt McGurn }
21599bf2564aSMatt McGurn 
2160011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_1D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2161cc08537eSMatthew G. Knepley {
21626858538eSMatthew G. Knepley   const PetscScalar *array;
2163a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
2164714b99b6SMatthew G. Knepley   PetscInt           coordSize, d;
21656858538eSMatthew G. Knepley   PetscBool          isDG;
2166cc08537eSMatthew G. Knepley 
2167cc08537eSMatthew G. Knepley   PetscFunctionBegin;
21686858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2169cc08537eSMatthew G. Knepley   if (centroid) {
21706858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) centroid[d] = 0.5*PetscRealPart(coords[d] + coords[dim+d]);
2171cc08537eSMatthew G. Knepley   }
2172cc08537eSMatthew G. Knepley   if (normal) {
2173a60a936bSMatthew G. Knepley     PetscReal norm;
2174a60a936bSMatthew G. Knepley 
217508401ef6SPierre Jolivet     PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "We only support 2D edges right now");
21766858538eSMatthew G. Knepley     normal[0] = -PetscRealPart(coords[1] - coords[dim+1]);
21776858538eSMatthew G. Knepley     normal[1] =  PetscRealPart(coords[0] - coords[dim+0]);
2178714b99b6SMatthew G. Knepley     norm      = DMPlex_NormD_Internal(dim, normal);
2179714b99b6SMatthew G. Knepley     for (d = 0; d < dim; ++d) normal[d] /= norm;
2180cc08537eSMatthew G. Knepley   }
2181cc08537eSMatthew G. Knepley   if (vol) {
2182714b99b6SMatthew G. Knepley     *vol = 0.0;
21836858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) *vol += PetscSqr(PetscRealPart(coords[d] - coords[dim+d]));
2184714b99b6SMatthew G. Knepley     *vol = PetscSqrtReal(*vol);
2185cc08537eSMatthew G. Knepley   }
21866858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2187cc08537eSMatthew G. Knepley   PetscFunctionReturn(0);
2188cc08537eSMatthew G. Knepley }
2189cc08537eSMatthew G. Knepley 
2190cc08537eSMatthew G. Knepley /* Centroid_i = (\sum_n A_n Cn_i) / A */
2191011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_2D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2192cc08537eSMatthew G. Knepley {
2193412e9a14SMatthew G. Knepley   DMPolytopeType     ct;
21946858538eSMatthew G. Knepley   const PetscScalar *array;
2195cc08537eSMatthew G. Knepley   PetscScalar       *coords = NULL;
21966858538eSMatthew G. Knepley   PetscInt           coordSize;
21976858538eSMatthew G. Knepley   PetscBool          isDG;
2198793a2a13SMatthew G. Knepley   PetscInt           fv[4] = {0, 1, 2, 3};
21996858538eSMatthew G. Knepley   PetscInt           cdim, numCorners, p, d;
2200cc08537eSMatthew G. Knepley 
2201cc08537eSMatthew G. Knepley   PetscFunctionBegin;
2202793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
22039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2204412e9a14SMatthew G. Knepley   switch (ct) {
22054f99dae5SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR: fv[2] = 3; fv[3] = 2;break;
2206412e9a14SMatthew G. Knepley     default: break;
2207412e9a14SMatthew G. Knepley   }
22089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
22096858538eSMatthew G. Knepley   PetscCall(DMPlexGetConeSize(dm, cell, &numCorners));
22106858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
22113f27a4e6SJed Brown   {
22123f27a4e6SJed Brown     PetscReal c[3] = {0., 0., 0.}, n[3] = {0., 0., 0.}, origin[3] = {0., 0., 0.}, norm;
2213793a2a13SMatthew G. Knepley 
22143f27a4e6SJed Brown     for (d = 0; d < cdim; d++) origin[d] = PetscRealPart(coords[d]);
22154f99dae5SMatthew G. Knepley     for (p = 0; p < numCorners-2; ++p) {
22163f27a4e6SJed Brown       PetscReal e0[3] = {0., 0., 0.}, e1[3] = {0., 0., 0.};
22173f27a4e6SJed Brown       for (d = 0; d < cdim; d++) {
22183f27a4e6SJed Brown         e0[d] = PetscRealPart(coords[cdim*fv[p+1]+d]) - origin[d];
22193f27a4e6SJed Brown         e1[d] = PetscRealPart(coords[cdim*fv[p+2]+d]) - origin[d];
22203f27a4e6SJed Brown       }
22213f27a4e6SJed Brown       const PetscReal dx = e0[1] * e1[2] - e0[2] * e1[1];
22223f27a4e6SJed Brown       const PetscReal dy = e0[2] * e1[0] - e0[0] * e1[2];
22233f27a4e6SJed Brown       const PetscReal dz = e0[0] * e1[1] - e0[1] * e1[0];
22243f27a4e6SJed Brown       const PetscReal a  = PetscSqrtReal(dx*dx + dy*dy + dz*dz);
22254f99dae5SMatthew G. Knepley 
22264f99dae5SMatthew G. Knepley       n[0] += dx;
22274f99dae5SMatthew G. Knepley       n[1] += dy;
22284f99dae5SMatthew G. Knepley       n[2] += dz;
22293f27a4e6SJed Brown       for (d = 0; d < cdim; d++) {
22303f27a4e6SJed Brown         c[d] += a * PetscRealPart(origin[d] + coords[cdim*fv[p+1]+d] + coords[cdim*fv[p+2]+d]) / 3.;
22313f27a4e6SJed Brown       }
2232ceee4971SMatthew G. Knepley     }
22334f99dae5SMatthew G. Knepley     norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
22344f99dae5SMatthew G. Knepley     n[0] /= norm;
22354f99dae5SMatthew G. Knepley     n[1] /= norm;
22364f99dae5SMatthew G. Knepley     n[2] /= norm;
22374f99dae5SMatthew G. Knepley     c[0] /= norm;
22384f99dae5SMatthew G. Knepley     c[1] /= norm;
22394f99dae5SMatthew G. Knepley     c[2] /= norm;
22404f99dae5SMatthew G. Knepley     if (vol) *vol = 0.5*norm;
22414f99dae5SMatthew G. Knepley     if (centroid) for (d = 0; d < cdim; ++d) centroid[d] = c[d];
22424f99dae5SMatthew G. Knepley     if (normal) for (d = 0; d < cdim; ++d) normal[d] = n[d];
22430a1d6728SMatthew G. Knepley   }
22446858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2245cc08537eSMatthew G. Knepley   PetscFunctionReturn(0);
2246cc08537eSMatthew G. Knepley }
2247cc08537eSMatthew G. Knepley 
22480ec8681fSMatthew G. Knepley /* Centroid_i = (\sum_n V_n Cn_i) / V */
2249011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_3D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
22500ec8681fSMatthew G. Knepley {
2251412e9a14SMatthew G. Knepley   DMPolytopeType        ct;
22526858538eSMatthew G. Knepley   const PetscScalar    *array;
22530ec8681fSMatthew G. Knepley   PetscScalar          *coords = NULL;
22546858538eSMatthew G. Knepley   PetscInt              coordSize;
22556858538eSMatthew G. Knepley   PetscBool             isDG;
22563f27a4e6SJed Brown   PetscReal             vsum = 0.0, vtmp, coordsTmp[3*3], origin[3];
22576858538eSMatthew G. Knepley   const PetscInt        order[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
22586858538eSMatthew G. Knepley   const PetscInt       *cone, *faceSizes, *faces;
22596858538eSMatthew G. Knepley   const DMPolytopeType *faceTypes;
2260793a2a13SMatthew G. Knepley   PetscBool             isHybrid = PETSC_FALSE;
22616858538eSMatthew G. Knepley   PetscInt              numFaces, f, fOff = 0, p, d;
22620ec8681fSMatthew G. Knepley 
22630ec8681fSMatthew G. Knepley   PetscFunctionBegin;
226463a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No support for dim %" PetscInt_FMT " > 3", dim);
2265793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
22669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2267412e9a14SMatthew G. Knepley   switch (ct) {
2268412e9a14SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
2269412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
2270412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
2271412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
2272412e9a14SMatthew G. Knepley       isHybrid = PETSC_TRUE;
2273412e9a14SMatthew G. Knepley     default: break;
2274412e9a14SMatthew G. Knepley   }
2275793a2a13SMatthew G. Knepley 
2276d9a81ebdSMatthew G. Knepley   if (centroid) for (d = 0; d < dim; ++d) centroid[d] = 0.0;
22776858538eSMatthew G. Knepley   PetscCall(DMPlexGetCone(dm, cell, &cone));
22786858538eSMatthew G. Knepley 
22796858538eSMatthew G. Knepley   // Using the closure of faces for coordinates does not work in periodic geometries, so we index into the cell coordinates
22806858538eSMatthew G. Knepley   PetscCall(DMPlexGetRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
22816858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
22820ec8681fSMatthew G. Knepley   for (f = 0; f < numFaces; ++f) {
2283793a2a13SMatthew G. Knepley     PetscBool flip = isHybrid && f == 0 ? PETSC_TRUE : PETSC_FALSE; /* The first hybrid face is reversed */
2284793a2a13SMatthew G. Knepley 
22853f27a4e6SJed Brown     // If using zero as the origin vertex for each tetrahedron, an element far from the origin will have positive and
22863f27a4e6SJed Brown     // negative volumes that nearly cancel, thus incurring rounding error. Here we define origin[] as the first vertex
22873f27a4e6SJed Brown     // so that all tetrahedra have positive volume.
22883f27a4e6SJed Brown     if (f == 0) for (d = 0; d < dim; d++) origin[d] = PetscRealPart(coords[d]);
22896858538eSMatthew G. Knepley     switch (faceTypes[f]) {
2290ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
22910ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
22926858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+0]*dim+d]) - origin[d];
22936858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+1]*dim+d]) - origin[d];
22946858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+2]*dim+d]) - origin[d];
22950ec8681fSMatthew G. Knepley       }
22960ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
22976858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
22980ec8681fSMatthew G. Knepley       vsum += vtmp;
22994f25033aSJed Brown       if (centroid) {           /* Centroid of OABC = (a+b+c)/4 */
23000ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23011ee9d5ecSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
23020ec8681fSMatthew G. Knepley         }
23030ec8681fSMatthew G. Knepley       }
23040ec8681fSMatthew G. Knepley       break;
2305ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
2306412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
2307793a2a13SMatthew G. Knepley     {
2308793a2a13SMatthew G. Knepley       PetscInt fv[4] = {0, 1, 2, 3};
2309793a2a13SMatthew G. Knepley 
2310793a2a13SMatthew G. Knepley       /* Side faces for hybrid cells are are stored as tensor products */
2311793a2a13SMatthew G. Knepley       if (isHybrid && f > 1) {fv[2] = 3; fv[3] = 2;}
23120ec8681fSMatthew G. Knepley       /* DO FOR PYRAMID */
23130ec8681fSMatthew G. Knepley       /* First tet */
23140ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
23156858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+fv[0]]*dim+d]) - origin[d];
23166858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+fv[1]]*dim+d]) - origin[d];
23176858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+fv[3]]*dim+d]) - origin[d];
23180ec8681fSMatthew G. Knepley       }
23190ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
23206858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
23210ec8681fSMatthew G. Knepley       vsum += vtmp;
23220ec8681fSMatthew G. Knepley       if (centroid) {
23230ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23240ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
23250ec8681fSMatthew G. Knepley         }
23260ec8681fSMatthew G. Knepley       }
23270ec8681fSMatthew G. Knepley       /* Second tet */
23280ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
23296858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+fv[1]]*dim+d]) - origin[d];
23306858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+fv[2]]*dim+d]) - origin[d];
23316858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+fv[3]]*dim+d]) - origin[d];
23320ec8681fSMatthew G. Knepley       }
23330ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
23346858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
23350ec8681fSMatthew G. Knepley       vsum += vtmp;
23360ec8681fSMatthew G. Knepley       if (centroid) {
23370ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23380ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
23390ec8681fSMatthew G. Knepley         }
23400ec8681fSMatthew G. Knepley       }
23410ec8681fSMatthew G. Knepley       break;
2342793a2a13SMatthew G. Knepley     }
23430ec8681fSMatthew G. Knepley     default:
23446858538eSMatthew G. Knepley       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle face %" PetscInt_FMT " of type %s", cone[f], DMPolytopeTypes[ct]);
23450ec8681fSMatthew G. Knepley     }
23466858538eSMatthew G. Knepley     fOff += faceSizes[f];
23470ec8681fSMatthew G. Knepley   }
23486858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
23496858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
23508763be8eSMatthew G. Knepley   if (vol)     *vol = PetscAbsReal(vsum);
23510ec8681fSMatthew G. Knepley   if (normal)   for (d = 0; d < dim; ++d) normal[d]    = 0.0;
23523f27a4e6SJed Brown   if (centroid) for (d = 0; d < dim; ++d) centroid[d] = centroid[d] / (vsum*4) + origin[d];
23530ec8681fSMatthew G. Knepley   PetscFunctionReturn(0);
23540ec8681fSMatthew G. Knepley }
23550ec8681fSMatthew G. Knepley 
2356834e62ceSMatthew G. Knepley /*@C
2357834e62ceSMatthew G. Knepley   DMPlexComputeCellGeometryFVM - Compute the volume for a given cell
2358834e62ceSMatthew G. Knepley 
2359d083f849SBarry Smith   Collective on dm
2360834e62ceSMatthew G. Knepley 
23614165533cSJose E. Roman   Input Parameters:
2362834e62ceSMatthew G. Knepley + dm   - the DM
2363834e62ceSMatthew G. Knepley - cell - the cell
2364834e62ceSMatthew G. Knepley 
23654165533cSJose E. Roman   Output Parameters:
2366834e62ceSMatthew G. Knepley + volume   - the cell volume
2367cc08537eSMatthew G. Knepley . centroid - the cell centroid
2368cc08537eSMatthew G. Knepley - normal - the cell normal, if appropriate
2369834e62ceSMatthew G. Knepley 
2370834e62ceSMatthew G. Knepley   Level: advanced
2371834e62ceSMatthew G. Knepley 
2372834e62ceSMatthew G. Knepley   Fortran Notes:
2373834e62ceSMatthew G. Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
2374834e62ceSMatthew G. Knepley   include petsc.h90 in your code.
2375834e62ceSMatthew G. Knepley 
2376db781477SPatrick Sanan .seealso: `DMGetCoordinateSection()`, `DMGetCoordinates()`
2377834e62ceSMatthew G. Knepley @*/
2378cc08537eSMatthew G. Knepley PetscErrorCode DMPlexComputeCellGeometryFVM(DM dm, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2379834e62ceSMatthew G. Knepley {
23800ec8681fSMatthew G. Knepley   PetscInt       depth, dim;
2381834e62ceSMatthew G. Knepley 
2382834e62ceSMatthew G. Knepley   PetscFunctionBegin;
23839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
23849566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
238508401ef6SPierre Jolivet   PetscCheck(depth == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh must be interpolated");
23869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPointDepth(dm, cell, &depth));
2387011ea5d8SMatthew G. Knepley   switch (depth) {
23889bf2564aSMatt McGurn   case 0:
23899566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_0D_Internal(dm, dim, cell, vol, centroid, normal));
23909bf2564aSMatt McGurn     break;
2391cc08537eSMatthew G. Knepley   case 1:
23929566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_1D_Internal(dm, dim, cell, vol, centroid, normal));
2393cc08537eSMatthew G. Knepley     break;
2394834e62ceSMatthew G. Knepley   case 2:
23959566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_2D_Internal(dm, dim, cell, vol, centroid, normal));
2396834e62ceSMatthew G. Knepley     break;
2397834e62ceSMatthew G. Knepley   case 3:
23989566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_3D_Internal(dm, dim, cell, vol, centroid, normal));
2399834e62ceSMatthew G. Knepley     break;
2400834e62ceSMatthew G. Knepley   default:
240163a3b9bcSJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %" PetscInt_FMT " (depth %" PetscInt_FMT ") for element geometry computation", dim, depth);
2402834e62ceSMatthew G. Knepley   }
2403834e62ceSMatthew G. Knepley   PetscFunctionReturn(0);
2404834e62ceSMatthew G. Knepley }
2405113c68e6SMatthew G. Knepley 
2406c501906fSMatthew G. Knepley /*@
2407c501906fSMatthew G. Knepley   DMPlexComputeGeometryFEM - Precompute cell geometry for the entire mesh
2408c501906fSMatthew G. Knepley 
2409c501906fSMatthew G. Knepley   Collective on dm
2410c501906fSMatthew G. Knepley 
2411c501906fSMatthew G. Knepley   Input Parameter:
2412c501906fSMatthew G. Knepley . dm - The DMPlex
2413c501906fSMatthew G. Knepley 
2414c501906fSMatthew G. Knepley   Output Parameter:
2415c501906fSMatthew G. Knepley . cellgeom - A vector with the cell geometry data for each cell
2416c501906fSMatthew G. Knepley 
2417c501906fSMatthew G. Knepley   Level: beginner
2418c501906fSMatthew G. Knepley 
2419c501906fSMatthew G. Knepley @*/
2420c0d900a5SMatthew G. Knepley PetscErrorCode DMPlexComputeGeometryFEM(DM dm, Vec *cellgeom)
2421c0d900a5SMatthew G. Knepley {
2422c0d900a5SMatthew G. Knepley   DM             dmCell;
2423c0d900a5SMatthew G. Knepley   Vec            coordinates;
2424c0d900a5SMatthew G. Knepley   PetscSection   coordSection, sectionCell;
2425c0d900a5SMatthew G. Knepley   PetscScalar   *cgeom;
2426412e9a14SMatthew G. Knepley   PetscInt       cStart, cEnd, c;
2427c0d900a5SMatthew G. Knepley 
2428c0d900a5SMatthew G. Knepley   PetscFunctionBegin;
24299566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmCell));
24309566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
24319566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
24329566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection));
24339566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmCell, coordinates));
24349566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionCell));
24359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
24369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd));
2437c0d900a5SMatthew G. Knepley   /* TODO This needs to be multiplied by Nq for non-affine */
24389566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFEGeom))/sizeof(PetscScalar))));
24399566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionCell));
24409566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmCell, sectionCell));
24419566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionCell));
24429566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmCell, cellgeom));
24439566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*cellgeom, &cgeom));
2444c0d900a5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
2445cf0b7c11SKarl Rupp     PetscFEGeom *cg;
2446c0d900a5SMatthew G. Knepley 
24479566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmCell, c, cgeom, &cg));
24489566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(cg, 1));
24499566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dmCell, c, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
245063a3b9bcSJacob Faibussowitsch     PetscCheck(*cg->detJ > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) *cg->detJ, c);
2451c0d900a5SMatthew G. Knepley   }
2452c0d900a5SMatthew G. Knepley   PetscFunctionReturn(0);
2453c0d900a5SMatthew G. Knepley }
2454c0d900a5SMatthew G. Knepley 
2455891a9168SMatthew G. Knepley /*@
2456891a9168SMatthew G. Knepley   DMPlexComputeGeometryFVM - Computes the cell and face geometry for a finite volume method
2457891a9168SMatthew G. Knepley 
2458891a9168SMatthew G. Knepley   Input Parameter:
2459891a9168SMatthew G. Knepley . dm - The DM
2460891a9168SMatthew G. Knepley 
2461891a9168SMatthew G. Knepley   Output Parameters:
2462891a9168SMatthew G. Knepley + cellgeom - A Vec of PetscFVCellGeom data
2463a2b725a8SWilliam Gropp - facegeom - A Vec of PetscFVFaceGeom data
2464891a9168SMatthew G. Knepley 
2465891a9168SMatthew G. Knepley   Level: developer
2466891a9168SMatthew G. Knepley 
2467db781477SPatrick Sanan .seealso: `PetscFVFaceGeom`, `PetscFVCellGeom`, `DMPlexComputeGeometryFEM()`
2468891a9168SMatthew G. Knepley @*/
2469113c68e6SMatthew G. Knepley PetscErrorCode DMPlexComputeGeometryFVM(DM dm, Vec *cellgeom, Vec *facegeom)
2470113c68e6SMatthew G. Knepley {
2471113c68e6SMatthew G. Knepley   DM             dmFace, dmCell;
2472113c68e6SMatthew G. Knepley   DMLabel        ghostLabel;
2473113c68e6SMatthew G. Knepley   PetscSection   sectionFace, sectionCell;
2474113c68e6SMatthew G. Knepley   PetscSection   coordSection;
2475113c68e6SMatthew G. Knepley   Vec            coordinates;
2476113c68e6SMatthew G. Knepley   PetscScalar   *fgeom, *cgeom;
2477113c68e6SMatthew G. Knepley   PetscReal      minradius, gminradius;
2478113c68e6SMatthew G. Knepley   PetscInt       dim, cStart, cEnd, cEndInterior, c, fStart, fEnd, f;
2479113c68e6SMatthew G. Knepley 
2480113c68e6SMatthew G. Knepley   PetscFunctionBegin;
24819566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
24829566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
24839566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2484113c68e6SMatthew G. Knepley   /* Make cell centroids and volumes */
24859566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmCell));
24869566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection));
24879566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmCell, coordinates));
24889566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionCell));
24899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
24909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
24919566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd));
24929566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVCellGeom))/sizeof(PetscScalar))));
24939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionCell));
24949566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmCell, sectionCell));
24959566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionCell));
24969566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmCell, cellgeom));
2497485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
24989566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*cellgeom, &cgeom));
2499113c68e6SMatthew G. Knepley   for (c = cStart; c < cEndInterior; ++c) {
2500113c68e6SMatthew G. Knepley     PetscFVCellGeom *cg;
2501113c68e6SMatthew G. Knepley 
25029566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmCell, c, cgeom, &cg));
25039566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(cg, 1));
25049566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dmCell, c, &cg->volume, cg->centroid, NULL));
2505113c68e6SMatthew G. Knepley   }
2506113c68e6SMatthew G. Knepley   /* Compute face normals and minimum cell radius */
25079566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmFace));
25089566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionFace));
25099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
25109566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionFace, fStart, fEnd));
25119566063dSJacob Faibussowitsch   for (f = fStart; f < fEnd; ++f) PetscCall(PetscSectionSetDof(sectionFace, f, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVFaceGeom))/sizeof(PetscScalar))));
25129566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionFace));
25139566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmFace, sectionFace));
25149566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionFace));
25159566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmFace, facegeom));
25169566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*facegeom, &fgeom));
25179566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2518113c68e6SMatthew G. Knepley   minradius = PETSC_MAX_REAL;
2519113c68e6SMatthew G. Knepley   for (f = fStart; f < fEnd; ++f) {
2520113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2521113c68e6SMatthew G. Knepley     PetscReal        area;
2522412e9a14SMatthew G. Knepley     const PetscInt  *cells;
2523412e9a14SMatthew G. Knepley     PetscInt         ncells, ghost = -1, d, numChildren;
2524113c68e6SMatthew G. Knepley 
25259566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
25269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
25279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &cells));
25289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &ncells));
2529412e9a14SMatthew G. Knepley     /* It is possible to get a face with no support when using partition overlap */
2530412e9a14SMatthew G. Knepley     if (!ncells || ghost >= 0 || numChildren) continue;
25319566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, f, fgeom, &fg));
25329566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, f, &area, fg->centroid, fg->normal));
2533113c68e6SMatthew G. Knepley     for (d = 0; d < dim; ++d) fg->normal[d] *= area;
2534113c68e6SMatthew G. Knepley     /* Flip face orientation if necessary to match ordering in support, and Update minimum radius */
2535113c68e6SMatthew G. Knepley     {
2536113c68e6SMatthew G. Knepley       PetscFVCellGeom *cL, *cR;
2537113c68e6SMatthew G. Knepley       PetscReal       *lcentroid, *rcentroid;
25380453c0cdSMatthew G. Knepley       PetscReal        l[3], r[3], v[3];
2539113c68e6SMatthew G. Knepley 
25409566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cgeom, &cL));
2541113c68e6SMatthew G. Knepley       lcentroid = cells[0] >= cEndInterior ? fg->centroid : cL->centroid;
254206348e87SToby Isaac       if (ncells > 1) {
25439566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cgeom, &cR));
2544113c68e6SMatthew G. Knepley         rcentroid = cells[1] >= cEndInterior ? fg->centroid : cR->centroid;
254506348e87SToby Isaac       }
254606348e87SToby Isaac       else {
254706348e87SToby Isaac         rcentroid = fg->centroid;
254806348e87SToby Isaac       }
25499566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, lcentroid, l));
25509566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, rcentroid, r));
25510453c0cdSMatthew G. Knepley       DMPlex_WaxpyD_Internal(dim, -1, l, r, v);
2552113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) < 0) {
2553113c68e6SMatthew G. Knepley         for (d = 0; d < dim; ++d) fg->normal[d] = -fg->normal[d];
2554113c68e6SMatthew G. Knepley       }
2555113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) <= 0) {
255663a3b9bcSJacob 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]);
255763a3b9bcSJacob 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]);
255863a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Direction for face %" PetscInt_FMT " could not be fixed", f);
2559113c68e6SMatthew G. Knepley       }
2560113c68e6SMatthew G. Knepley       if (cells[0] < cEndInterior) {
2561113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cL->centroid, v);
2562113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2563113c68e6SMatthew G. Knepley       }
256406348e87SToby Isaac       if (ncells > 1 && cells[1] < cEndInterior) {
2565113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cR->centroid, v);
2566113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2567113c68e6SMatthew G. Knepley       }
2568113c68e6SMatthew G. Knepley     }
2569113c68e6SMatthew G. Knepley   }
25701c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&minradius, &gminradius, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm)));
25719566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMinRadius(dm, gminradius));
2572113c68e6SMatthew G. Knepley   /* Compute centroids of ghost cells */
2573113c68e6SMatthew G. Knepley   for (c = cEndInterior; c < cEnd; ++c) {
2574113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2575113c68e6SMatthew G. Knepley     const PetscInt  *cone,    *support;
2576113c68e6SMatthew G. Knepley     PetscInt         coneSize, supportSize, s;
2577113c68e6SMatthew G. Knepley 
25789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmCell, c, &coneSize));
257963a3b9bcSJacob Faibussowitsch     PetscCheck(coneSize == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %" PetscInt_FMT " has cone size %" PetscInt_FMT " != 1", c, coneSize);
25809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmCell, c, &cone));
25819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmCell, cone[0], &supportSize));
258263a3b9bcSJacob Faibussowitsch     PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[0], supportSize);
25839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmCell, cone[0], &support));
25849566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, cone[0], fgeom, &fg));
2585113c68e6SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
2586113c68e6SMatthew G. Knepley       /* Reflect ghost centroid across plane of face */
2587113c68e6SMatthew G. Knepley       if (support[s] == c) {
2588640bce14SSatish Balay         PetscFVCellGeom       *ci;
2589113c68e6SMatthew G. Knepley         PetscFVCellGeom       *cg;
2590113c68e6SMatthew G. Knepley         PetscReal              c2f[3], a;
2591113c68e6SMatthew G. Knepley 
25929566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, support[(s+1)%2], cgeom, &ci));
2593113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, ci->centroid, fg->centroid, c2f); /* cell to face centroid */
2594113c68e6SMatthew G. Knepley         a    = DMPlex_DotRealD_Internal(dim, c2f, fg->normal)/DMPlex_DotRealD_Internal(dim, fg->normal, fg->normal);
25959566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRef(dmCell, support[s], cgeom, &cg));
2596113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, 2*a, fg->normal, ci->centroid, cg->centroid);
2597113c68e6SMatthew G. Knepley         cg->volume = ci->volume;
2598113c68e6SMatthew G. Knepley       }
2599113c68e6SMatthew G. Knepley     }
2600113c68e6SMatthew G. Knepley   }
26019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*facegeom, &fgeom));
26029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*cellgeom, &cgeom));
26039566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmCell));
26049566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmFace));
2605113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2606113c68e6SMatthew G. Knepley }
2607113c68e6SMatthew G. Knepley 
2608113c68e6SMatthew G. Knepley /*@C
2609113c68e6SMatthew G. Knepley   DMPlexGetMinRadius - Returns the minimum distance from any cell centroid to a face
2610113c68e6SMatthew G. Knepley 
2611113c68e6SMatthew G. Knepley   Not collective
2612113c68e6SMatthew G. Knepley 
26134165533cSJose E. Roman   Input Parameter:
2614113c68e6SMatthew G. Knepley . dm - the DM
2615113c68e6SMatthew G. Knepley 
26164165533cSJose E. Roman   Output Parameter:
2617a5b23f4aSJose E. Roman . minradius - the minimum cell radius
2618113c68e6SMatthew G. Knepley 
2619113c68e6SMatthew G. Knepley   Level: developer
2620113c68e6SMatthew G. Knepley 
2621db781477SPatrick Sanan .seealso: `DMGetCoordinates()`
2622113c68e6SMatthew G. Knepley @*/
2623113c68e6SMatthew G. Knepley PetscErrorCode DMPlexGetMinRadius(DM dm, PetscReal *minradius)
2624113c68e6SMatthew G. Knepley {
2625113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2626113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2627dadcf809SJacob Faibussowitsch   PetscValidRealPointer(minradius,2);
2628113c68e6SMatthew G. Knepley   *minradius = ((DM_Plex*) dm->data)->minradius;
2629113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2630113c68e6SMatthew G. Knepley }
2631113c68e6SMatthew G. Knepley 
2632113c68e6SMatthew G. Knepley /*@C
2633113c68e6SMatthew G. Knepley   DMPlexSetMinRadius - Sets the minimum distance from the cell centroid to a face
2634113c68e6SMatthew G. Knepley 
2635113c68e6SMatthew G. Knepley   Logically collective
2636113c68e6SMatthew G. Knepley 
26374165533cSJose E. Roman   Input Parameters:
2638113c68e6SMatthew G. Knepley + dm - the DM
2639a5b23f4aSJose E. Roman - minradius - the minimum cell radius
2640113c68e6SMatthew G. Knepley 
2641113c68e6SMatthew G. Knepley   Level: developer
2642113c68e6SMatthew G. Knepley 
2643db781477SPatrick Sanan .seealso: `DMSetCoordinates()`
2644113c68e6SMatthew G. Knepley @*/
2645113c68e6SMatthew G. Knepley PetscErrorCode DMPlexSetMinRadius(DM dm, PetscReal minradius)
2646113c68e6SMatthew G. Knepley {
2647113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2648113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2649113c68e6SMatthew G. Knepley   ((DM_Plex*) dm->data)->minradius = minradius;
2650113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2651113c68e6SMatthew G. Knepley }
2652856ac710SMatthew G. Knepley 
2653856ac710SMatthew G. Knepley static PetscErrorCode BuildGradientReconstruction_Internal(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2654856ac710SMatthew G. Knepley {
2655856ac710SMatthew G. Knepley   DMLabel        ghostLabel;
2656856ac710SMatthew G. Knepley   PetscScalar   *dx, *grad, **gref;
2657856ac710SMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c, cEndInterior, maxNumFaces;
2658856ac710SMatthew G. Knepley 
2659856ac710SMatthew G. Knepley   PetscFunctionBegin;
26609566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
26619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
26629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2663089217ebSMatthew G. Knepley   cEndInterior = cEndInterior < 0 ? cEnd : cEndInterior;
26649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxNumFaces, NULL));
26659566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
26669566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
26679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref));
2668856ac710SMatthew G. Knepley   for (c = cStart; c < cEndInterior; c++) {
2669856ac710SMatthew G. Knepley     const PetscInt        *faces;
2670856ac710SMatthew G. Knepley     PetscInt               numFaces, usedFaces, f, d;
2671640bce14SSatish Balay     PetscFVCellGeom        *cg;
2672856ac710SMatthew G. Knepley     PetscBool              boundary;
2673856ac710SMatthew G. Knepley     PetscInt               ghost;
2674856ac710SMatthew G. Knepley 
2675a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
2676a79418b7SMatt McGurn     PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2677a79418b7SMatt McGurn     if (ghost >= 0) continue;
2678a79418b7SMatt McGurn 
26799566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
26809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &numFaces));
26819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &faces));
268263a3b9bcSJacob 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);
2683856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
2684640bce14SSatish Balay       PetscFVCellGeom       *cg1;
2685856ac710SMatthew G. Knepley       PetscFVFaceGeom       *fg;
2686856ac710SMatthew G. Knepley       const PetscInt        *fcells;
2687856ac710SMatthew G. Knepley       PetscInt               ncell, side;
2688856ac710SMatthew G. Knepley 
26899566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
26909566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2691856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
26929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, faces[f], &fcells));
2693856ac710SMatthew G. Knepley       side  = (c != fcells[0]); /* c is on left=0 or right=1 of face */
2694856ac710SMatthew G. Knepley       ncell = fcells[!side];    /* the neighbor */
26959566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, faces[f], fgeom, &fg));
26969566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2697856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) dx[usedFaces*dim+d] = cg1->centroid[d] - cg->centroid[d];
2698856ac710SMatthew G. Knepley       gref[usedFaces++] = fg->grad[side];  /* Gradient reconstruction term will go here */
2699856ac710SMatthew G. Knepley     }
270028b400f6SJacob Faibussowitsch     PetscCheck(usedFaces,PETSC_COMM_SELF, PETSC_ERR_USER, "Mesh contains isolated cell (no neighbors). Is it intentional?");
27019566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, usedFaces, dx, grad));
2702856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
27039566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
27049566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2705856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
2706856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) gref[usedFaces][d] = grad[usedFaces*dim+d];
2707856ac710SMatthew G. Knepley       ++usedFaces;
2708856ac710SMatthew G. Knepley     }
2709856ac710SMatthew G. Knepley   }
27109566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
2711856ac710SMatthew G. Knepley   PetscFunctionReturn(0);
2712856ac710SMatthew G. Knepley }
2713856ac710SMatthew G. Knepley 
2714b81db932SToby Isaac static PetscErrorCode BuildGradientReconstruction_Internal_Tree(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2715b81db932SToby Isaac {
2716b81db932SToby Isaac   DMLabel        ghostLabel;
2717b81db932SToby Isaac   PetscScalar   *dx, *grad, **gref;
2718b81db932SToby Isaac   PetscInt       dim, cStart, cEnd, c, cEndInterior, fStart, fEnd, f, nStart, nEnd, maxNumFaces = 0;
2719b81db932SToby Isaac   PetscSection   neighSec;
2720b81db932SToby Isaac   PetscInt     (*neighbors)[2];
2721b81db932SToby Isaac   PetscInt      *counter;
2722b81db932SToby Isaac 
2723b81db932SToby Isaac   PetscFunctionBegin;
27249566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
27259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
27269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2727485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
27289566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm),&neighSec));
27299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(neighSec,cStart,cEndInterior));
27309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
27319566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2732b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2733b81db932SToby Isaac     const PetscInt        *fcells;
2734b81db932SToby Isaac     PetscBool              boundary;
27355bc680faSToby Isaac     PetscInt               ghost = -1;
2736b81db932SToby Isaac     PetscInt               numChildren, numCells, c;
2737b81db932SToby Isaac 
27389566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
27399566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
27409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2741b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
27429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
274306348e87SToby Isaac     if (numCells == 2) {
27449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2745b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2746b81db932SToby Isaac         PetscInt cell = fcells[c];
2747b81db932SToby Isaac 
2748e6885bbbSToby Isaac         if (cell >= cStart && cell < cEndInterior) {
27499566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(neighSec,cell,1));
2750b81db932SToby Isaac         }
2751b81db932SToby Isaac       }
2752b81db932SToby Isaac     }
275306348e87SToby Isaac   }
27549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(neighSec));
27559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(neighSec,&maxNumFaces));
27569566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
2757b81db932SToby Isaac   nStart = 0;
27589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(neighSec,&nEnd));
27599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((nEnd-nStart),&neighbors));
27609566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEndInterior-cStart),&counter));
2761b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2762b81db932SToby Isaac     const PetscInt        *fcells;
2763b81db932SToby Isaac     PetscBool              boundary;
27645bc680faSToby Isaac     PetscInt               ghost = -1;
2765b81db932SToby Isaac     PetscInt               numChildren, numCells, c;
2766b81db932SToby Isaac 
27679566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
27689566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
27699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2770b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
27719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
277206348e87SToby Isaac     if (numCells == 2) {
27739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2774b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2775b81db932SToby Isaac         PetscInt cell = fcells[c], off;
2776b81db932SToby Isaac 
2777e6885bbbSToby Isaac         if (cell >= cStart && cell < cEndInterior) {
27789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(neighSec,cell,&off));
2779b81db932SToby Isaac           off += counter[cell - cStart]++;
2780b81db932SToby Isaac           neighbors[off][0] = f;
2781b81db932SToby Isaac           neighbors[off][1] = fcells[1 - c];
2782b81db932SToby Isaac         }
2783b81db932SToby Isaac       }
2784b81db932SToby Isaac     }
278506348e87SToby Isaac   }
27869566063dSJacob Faibussowitsch   PetscCall(PetscFree(counter));
27879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref));
2788b81db932SToby Isaac   for (c = cStart; c < cEndInterior; c++) {
2789317218b9SToby Isaac     PetscInt               numFaces, f, d, off, ghost = -1;
2790640bce14SSatish Balay     PetscFVCellGeom        *cg;
2791b81db932SToby Isaac 
27929566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
27939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(neighSec, c, &numFaces));
27949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(neighSec, c, &off));
2795a79418b7SMatt McGurn 
2796a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
27979566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2798a79418b7SMatt McGurn     if (ghost >= 0) continue;
2799a79418b7SMatt McGurn 
280063a3b9bcSJacob 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);
2801b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2802640bce14SSatish Balay       PetscFVCellGeom       *cg1;
2803b81db932SToby Isaac       PetscFVFaceGeom       *fg;
2804b81db932SToby Isaac       const PetscInt        *fcells;
2805b81db932SToby Isaac       PetscInt               ncell, side, nface;
2806b81db932SToby Isaac 
2807b81db932SToby Isaac       nface = neighbors[off + f][0];
2808b81db932SToby Isaac       ncell = neighbors[off + f][1];
28099566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm,nface,&fcells));
2810b81db932SToby Isaac       side  = (c != fcells[0]);
28119566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, nface, fgeom, &fg));
28129566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2813b81db932SToby Isaac       for (d = 0; d < dim; ++d) dx[f*dim+d] = cg1->centroid[d] - cg->centroid[d];
2814b81db932SToby Isaac       gref[f] = fg->grad[side];  /* Gradient reconstruction term will go here */
2815b81db932SToby Isaac     }
28169566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, numFaces, dx, grad));
2817b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2818b81db932SToby Isaac       for (d = 0; d < dim; ++d) gref[f][d] = grad[f*dim+d];
2819b81db932SToby Isaac     }
2820b81db932SToby Isaac   }
28219566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
28229566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&neighSec));
28239566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighbors));
2824b81db932SToby Isaac   PetscFunctionReturn(0);
2825b81db932SToby Isaac }
2826b81db932SToby Isaac 
2827856ac710SMatthew G. Knepley /*@
2828856ac710SMatthew G. Knepley   DMPlexComputeGradientFVM - Compute geometric factors for gradient reconstruction, which are stored in the geometry data, and compute layout for gradient data
2829856ac710SMatthew G. Knepley 
2830d083f849SBarry Smith   Collective on dm
2831856ac710SMatthew G. Knepley 
28324165533cSJose E. Roman   Input Parameters:
2833856ac710SMatthew G. Knepley + dm  - The DM
2834856ac710SMatthew G. Knepley . fvm - The PetscFV
28358f9f38e3SMatthew G. Knepley - cellGeometry - The face geometry from DMPlexComputeCellGeometryFVM()
2836856ac710SMatthew G. Knepley 
28376b867d5aSJose E. Roman   Input/Output Parameter:
28386b867d5aSJose E. Roman . faceGeometry - The face geometry from DMPlexComputeFaceGeometryFVM(); on output
28396b867d5aSJose E. Roman                  the geometric factors for gradient calculation are inserted
28406b867d5aSJose E. Roman 
28416b867d5aSJose E. Roman   Output Parameter:
28426b867d5aSJose E. Roman . dmGrad - The DM describing the layout of gradient data
2843856ac710SMatthew G. Knepley 
2844856ac710SMatthew G. Knepley   Level: developer
2845856ac710SMatthew G. Knepley 
2846db781477SPatrick Sanan .seealso: `DMPlexGetFaceGeometryFVM()`, `DMPlexGetCellGeometryFVM()`
2847856ac710SMatthew G. Knepley @*/
2848856ac710SMatthew G. Knepley PetscErrorCode DMPlexComputeGradientFVM(DM dm, PetscFV fvm, Vec faceGeometry, Vec cellGeometry, DM *dmGrad)
2849856ac710SMatthew G. Knepley {
2850856ac710SMatthew G. Knepley   DM             dmFace, dmCell;
2851856ac710SMatthew G. Knepley   PetscScalar   *fgeom, *cgeom;
2852b81db932SToby Isaac   PetscSection   sectionGrad, parentSection;
2853856ac710SMatthew G. Knepley   PetscInt       dim, pdim, cStart, cEnd, cEndInterior, c;
2854856ac710SMatthew G. Knepley 
2855856ac710SMatthew G. Knepley   PetscFunctionBegin;
28569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
28579566063dSJacob Faibussowitsch   PetscCall(PetscFVGetNumComponents(fvm, &pdim));
28589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
28599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2860856ac710SMatthew G. Knepley   /* Construct the interpolant corresponding to each face from the least-square solution over the cell neighborhood */
28619566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
28629566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
28639566063dSJacob Faibussowitsch   PetscCall(VecGetArray(faceGeometry, &fgeom));
28649566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cellGeometry, &cgeom));
28659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTree(dm,&parentSection,NULL,NULL,NULL,NULL));
2866b81db932SToby Isaac   if (!parentSection) {
28679566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2868b5a3613cSMatthew G. Knepley   } else {
28699566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal_Tree(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2870b81db932SToby Isaac   }
28719566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(faceGeometry, &fgeom));
28729566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cellGeometry, &cgeom));
2873856ac710SMatthew G. Knepley   /* Create storage for gradients */
28749566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, dmGrad));
28759566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionGrad));
28769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionGrad, cStart, cEnd));
28779566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionGrad, c, pdim*dim));
28789566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionGrad));
28799566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*dmGrad, sectionGrad));
28809566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionGrad));
2881856ac710SMatthew G. Knepley   PetscFunctionReturn(0);
2882856ac710SMatthew G. Knepley }
2883b27d5b9eSToby Isaac 
2884c501906fSMatthew G. Knepley /*@
2885c501906fSMatthew G. Knepley   DMPlexGetDataFVM - Retrieve precomputed cell geometry
2886c501906fSMatthew G. Knepley 
2887d083f849SBarry Smith   Collective on dm
2888c501906fSMatthew G. Knepley 
28894165533cSJose E. Roman   Input Parameters:
2890c501906fSMatthew G. Knepley + dm  - The DM
28916b867d5aSJose E. Roman - fv  - The PetscFV
2892c501906fSMatthew G. Knepley 
2893c501906fSMatthew G. Knepley   Output Parameters:
2894c501906fSMatthew G. Knepley + cellGeometry - The cell geometry
2895c501906fSMatthew G. Knepley . faceGeometry - The face geometry
28966b867d5aSJose E. Roman - gradDM       - The gradient matrices
2897c501906fSMatthew G. Knepley 
2898c501906fSMatthew G. Knepley   Level: developer
2899c501906fSMatthew G. Knepley 
2900db781477SPatrick Sanan .seealso: `DMPlexComputeGeometryFVM()`
2901c501906fSMatthew G. Knepley @*/
2902b27d5b9eSToby Isaac PetscErrorCode DMPlexGetDataFVM(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM)
2903b27d5b9eSToby Isaac {
2904b27d5b9eSToby Isaac   PetscObject    cellgeomobj, facegeomobj;
2905b27d5b9eSToby Isaac 
2906b27d5b9eSToby Isaac   PetscFunctionBegin;
29079566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2908b27d5b9eSToby Isaac   if (!cellgeomobj) {
2909b27d5b9eSToby Isaac     Vec cellgeomInt, facegeomInt;
2910b27d5b9eSToby Isaac 
29119566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellgeomInt, &facegeomInt));
29129566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_cellgeom_fvm",(PetscObject)cellgeomInt));
29139566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_facegeom_fvm",(PetscObject)facegeomInt));
29149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellgeomInt));
29159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&facegeomInt));
29169566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2917b27d5b9eSToby Isaac   }
29189566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_facegeom_fvm", &facegeomobj));
2919b27d5b9eSToby Isaac   if (cellgeom) *cellgeom = (Vec) cellgeomobj;
2920b27d5b9eSToby Isaac   if (facegeom) *facegeom = (Vec) facegeomobj;
2921b27d5b9eSToby Isaac   if (gradDM) {
2922b27d5b9eSToby Isaac     PetscObject gradobj;
2923b27d5b9eSToby Isaac     PetscBool   computeGradients;
2924b27d5b9eSToby Isaac 
29259566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv,&computeGradients));
2926b27d5b9eSToby Isaac     if (!computeGradients) {
2927b27d5b9eSToby Isaac       *gradDM = NULL;
2928b27d5b9eSToby Isaac       PetscFunctionReturn(0);
2929b27d5b9eSToby Isaac     }
29309566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj));
2931b27d5b9eSToby Isaac     if (!gradobj) {
2932b27d5b9eSToby Isaac       DM dmGradInt;
2933b27d5b9eSToby Isaac 
29349566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeGradientFVM(dm,fv,(Vec) facegeomobj,(Vec) cellgeomobj,&dmGradInt));
29359566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_dmgrad_fvm", (PetscObject)dmGradInt));
29369566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmGradInt));
29379566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj));
2938b27d5b9eSToby Isaac     }
2939b27d5b9eSToby Isaac     *gradDM = (DM) gradobj;
2940b27d5b9eSToby Isaac   }
2941b27d5b9eSToby Isaac   PetscFunctionReturn(0);
2942b27d5b9eSToby Isaac }
2943d6143a4eSToby Isaac 
29449d150b73SToby Isaac static PetscErrorCode DMPlexCoordinatesToReference_NewtonUpdate(PetscInt dimC, PetscInt dimR, PetscScalar *J, PetscScalar *invJ, PetscScalar *work,  PetscReal *resNeg, PetscReal *guess)
29459d150b73SToby Isaac {
29469d150b73SToby Isaac   PetscInt l, m;
29479d150b73SToby Isaac 
2948cd345991SToby Isaac   PetscFunctionBeginHot;
29499d150b73SToby Isaac   if (dimC == dimR && dimR <= 3) {
29509d150b73SToby Isaac     /* invert Jacobian, multiply */
29519d150b73SToby Isaac     PetscScalar det, idet;
29529d150b73SToby Isaac 
29539d150b73SToby Isaac     switch (dimR) {
29549d150b73SToby Isaac     case 1:
29559d150b73SToby Isaac       invJ[0] = 1./ J[0];
29569d150b73SToby Isaac       break;
29579d150b73SToby Isaac     case 2:
29589d150b73SToby Isaac       det = J[0] * J[3] - J[1] * J[2];
29599d150b73SToby Isaac       idet = 1./det;
29609d150b73SToby Isaac       invJ[0] =  J[3] * idet;
29619d150b73SToby Isaac       invJ[1] = -J[1] * idet;
29629d150b73SToby Isaac       invJ[2] = -J[2] * idet;
29639d150b73SToby Isaac       invJ[3] =  J[0] * idet;
29649d150b73SToby Isaac       break;
29659d150b73SToby Isaac     case 3:
29669d150b73SToby Isaac       {
29679d150b73SToby Isaac         invJ[0] = J[4] * J[8] - J[5] * J[7];
29689d150b73SToby Isaac         invJ[1] = J[2] * J[7] - J[1] * J[8];
29699d150b73SToby Isaac         invJ[2] = J[1] * J[5] - J[2] * J[4];
29709d150b73SToby Isaac         det = invJ[0] * J[0] + invJ[1] * J[3] + invJ[2] * J[6];
29719d150b73SToby Isaac         idet = 1./det;
29729d150b73SToby Isaac         invJ[0] *= idet;
29739d150b73SToby Isaac         invJ[1] *= idet;
29749d150b73SToby Isaac         invJ[2] *= idet;
29759d150b73SToby Isaac         invJ[3]  = idet * (J[5] * J[6] - J[3] * J[8]);
29769d150b73SToby Isaac         invJ[4]  = idet * (J[0] * J[8] - J[2] * J[6]);
29779d150b73SToby Isaac         invJ[5]  = idet * (J[2] * J[3] - J[0] * J[5]);
29789d150b73SToby Isaac         invJ[6]  = idet * (J[3] * J[7] - J[4] * J[6]);
29799d150b73SToby Isaac         invJ[7]  = idet * (J[1] * J[6] - J[0] * J[7]);
29809d150b73SToby Isaac         invJ[8]  = idet * (J[0] * J[4] - J[1] * J[3]);
29819d150b73SToby Isaac       }
29829d150b73SToby Isaac       break;
29839d150b73SToby Isaac     }
29849d150b73SToby Isaac     for (l = 0; l < dimR; l++) {
29859d150b73SToby Isaac       for (m = 0; m < dimC; m++) {
2986c6e120d1SToby Isaac         guess[l] += PetscRealPart(invJ[l * dimC + m]) * resNeg[m];
29879d150b73SToby Isaac       }
29889d150b73SToby Isaac     }
29899d150b73SToby Isaac   } else {
29909d150b73SToby Isaac #if defined(PETSC_USE_COMPLEX)
29919d150b73SToby Isaac     char transpose = 'C';
29929d150b73SToby Isaac #else
29939d150b73SToby Isaac     char transpose = 'T';
29949d150b73SToby Isaac #endif
29959d150b73SToby Isaac     PetscBLASInt m = dimR;
29969d150b73SToby Isaac     PetscBLASInt n = dimC;
29979d150b73SToby Isaac     PetscBLASInt one = 1;
29989d150b73SToby Isaac     PetscBLASInt worksize = dimR * dimC, info;
29999d150b73SToby Isaac 
30009d150b73SToby Isaac     for (l = 0; l < dimC; l++) {invJ[l] = resNeg[l];}
30019d150b73SToby Isaac 
30029d150b73SToby Isaac     PetscStackCallBLAS("LAPACKgels",LAPACKgels_(&transpose,&m,&n,&one,J,&m,invJ,&n,work,&worksize, &info));
300308401ef6SPierre Jolivet     PetscCheck(info == 0,PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELS");
30049d150b73SToby Isaac 
3005c6e120d1SToby Isaac     for (l = 0; l < dimR; l++) {guess[l] += PetscRealPart(invJ[l]);}
30069d150b73SToby Isaac   }
30079d150b73SToby Isaac   PetscFunctionReturn(0);
30089d150b73SToby Isaac }
30099d150b73SToby Isaac 
30109d150b73SToby Isaac static PetscErrorCode DMPlexCoordinatesToReference_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
30119d150b73SToby Isaac {
3012c0cbe899SToby Isaac   PetscInt       coordSize, i, j, k, l, m, maxIts = 7, numV = (1 << dimR);
30139d150b73SToby Isaac   PetscScalar    *coordsScalar = NULL;
30149d150b73SToby Isaac   PetscReal      *cellData, *cellCoords, *cellCoeffs, *extJ, *resNeg;
30159d150b73SToby Isaac   PetscScalar    *J, *invJ, *work;
30169d150b73SToby Isaac 
30179d150b73SToby Isaac   PetscFunctionBegin;
30189d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
30199566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
30201dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT,dimC * (1 << dimR), coordSize);
30219566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
30229566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
30239d150b73SToby Isaac   cellCoords = &cellData[0];
30249d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
30259d150b73SToby Isaac   extJ       = &cellData[2 * coordSize];
30269d150b73SToby Isaac   resNeg     = &cellData[2 * coordSize + dimR];
30279d150b73SToby Isaac   invJ       = &J[dimR * dimC];
30289d150b73SToby Isaac   work       = &J[2 * dimR * dimC];
30299d150b73SToby Isaac   if (dimR == 2) {
30309d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
30319d150b73SToby Isaac 
30329d150b73SToby Isaac     for (i = 0; i < 4; i++) {
30339d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
30349d150b73SToby Isaac 
30359d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
30369d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
30379d150b73SToby Isaac       }
30389d150b73SToby Isaac     }
30399d150b73SToby Isaac   } else if (dimR == 3) {
30409d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
30419d150b73SToby Isaac 
30429d150b73SToby Isaac     for (i = 0; i < 8; i++) {
30439d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
30449d150b73SToby Isaac 
30459d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
30469d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
30479d150b73SToby Isaac       }
30489d150b73SToby Isaac     }
30499d150b73SToby Isaac   } else {
30509d150b73SToby Isaac     for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);}
30519d150b73SToby Isaac   }
30529d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
30539d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
30549d150b73SToby Isaac     PetscReal *swap;
30559d150b73SToby Isaac 
30569d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
30579d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
30589d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
30599d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
30609d150b73SToby Isaac       }
30619d150b73SToby Isaac     }
30629d150b73SToby Isaac 
30639d150b73SToby Isaac     if (i < dimR - 1) {
30649d150b73SToby Isaac       swap = cellCoeffs;
30659d150b73SToby Isaac       cellCoeffs = cellCoords;
30669d150b73SToby Isaac       cellCoords = swap;
30679d150b73SToby Isaac     }
30689d150b73SToby Isaac   }
30699566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(refCoords,numPoints * dimR));
30709d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
30719d150b73SToby Isaac     for (i = 0; i < maxIts; i++) {
30729d150b73SToby Isaac       PetscReal *guess = &refCoords[dimR * j];
30739d150b73SToby Isaac 
30749d150b73SToby Isaac       /* compute -residual and Jacobian */
30759d150b73SToby Isaac       for (k = 0; k < dimC; k++) {resNeg[k] = realCoords[dimC * j + k];}
30769d150b73SToby Isaac       for (k = 0; k < dimC * dimR; k++) {J[k] = 0.;}
30779d150b73SToby Isaac       for (k = 0; k < numV; k++) {
30789d150b73SToby Isaac         PetscReal extCoord = 1.;
30799d150b73SToby Isaac         for (l = 0; l < dimR; l++) {
30809d150b73SToby Isaac           PetscReal coord = guess[l];
30819d150b73SToby Isaac           PetscInt  dep   = (k & (1 << l)) >> l;
30829d150b73SToby Isaac 
30839d150b73SToby Isaac           extCoord *= dep * coord + !dep;
30849d150b73SToby Isaac           extJ[l] = dep;
30859d150b73SToby Isaac 
30869d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
30879d150b73SToby Isaac             PetscReal coord = guess[m];
30889d150b73SToby Isaac             PetscInt  dep   = ((k & (1 << m)) >> m) && (m != l);
30899d150b73SToby Isaac             PetscReal mult  = dep * coord + !dep;
30909d150b73SToby Isaac 
30919d150b73SToby Isaac             extJ[l] *= mult;
30929d150b73SToby Isaac           }
30939d150b73SToby Isaac         }
30949d150b73SToby Isaac         for (l = 0; l < dimC; l++) {
30959d150b73SToby Isaac           PetscReal coeff = cellCoeffs[dimC * k + l];
30969d150b73SToby Isaac 
30979d150b73SToby Isaac           resNeg[l] -= coeff * extCoord;
30989d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
30999d150b73SToby Isaac             J[dimR * l + m] += coeff * extJ[m];
31009d150b73SToby Isaac           }
31019d150b73SToby Isaac         }
31029d150b73SToby Isaac       }
310376bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
31040611203eSToby Isaac         PetscReal maxAbs = 0.;
31050611203eSToby Isaac 
31060611203eSToby Isaac         for (l = 0; l < dimC; l++) {
31070611203eSToby Isaac           maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l]));
31080611203eSToby Isaac         }
310963a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm,"cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n",cell,j,i,(double) maxAbs));
31100611203eSToby Isaac       }
31119d150b73SToby Isaac 
31129566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(dimC,dimR,J,invJ,work,resNeg,guess));
31139d150b73SToby Isaac     }
31149d150b73SToby Isaac   }
31159566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
31169566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
31179566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31189d150b73SToby Isaac   PetscFunctionReturn(0);
31199d150b73SToby Isaac }
31209d150b73SToby Isaac 
31219d150b73SToby Isaac static PetscErrorCode DMPlexReferenceToCoordinates_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
31229d150b73SToby Isaac {
31239d150b73SToby Isaac   PetscInt       coordSize, i, j, k, l, numV = (1 << dimR);
31249d150b73SToby Isaac   PetscScalar    *coordsScalar = NULL;
31259d150b73SToby Isaac   PetscReal      *cellData, *cellCoords, *cellCoeffs;
31269d150b73SToby Isaac 
31279d150b73SToby Isaac   PetscFunctionBegin;
31289d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
31299566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31301dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT,dimC * (1 << dimR), coordSize);
31319566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
31329d150b73SToby Isaac   cellCoords = &cellData[0];
31339d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
31349d150b73SToby Isaac   if (dimR == 2) {
31359d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
31369d150b73SToby Isaac 
31379d150b73SToby Isaac     for (i = 0; i < 4; i++) {
31389d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
31399d150b73SToby Isaac 
31409d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
31419d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
31429d150b73SToby Isaac       }
31439d150b73SToby Isaac     }
31449d150b73SToby Isaac   } else if (dimR == 3) {
31459d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
31469d150b73SToby Isaac 
31479d150b73SToby Isaac     for (i = 0; i < 8; i++) {
31489d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
31499d150b73SToby Isaac 
31509d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
31519d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
31529d150b73SToby Isaac       }
31539d150b73SToby Isaac     }
31549d150b73SToby Isaac   } else {
31559d150b73SToby Isaac     for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);}
31569d150b73SToby Isaac   }
31579d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
31589d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
31599d150b73SToby Isaac     PetscReal *swap;
31609d150b73SToby Isaac 
31619d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
31629d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
31639d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
31649d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
31659d150b73SToby Isaac       }
31669d150b73SToby Isaac     }
31679d150b73SToby Isaac 
31689d150b73SToby Isaac     if (i < dimR - 1) {
31699d150b73SToby Isaac       swap = cellCoeffs;
31709d150b73SToby Isaac       cellCoeffs = cellCoords;
31719d150b73SToby Isaac       cellCoords = swap;
31729d150b73SToby Isaac     }
31739d150b73SToby Isaac   }
31749566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(realCoords,numPoints * dimC));
31759d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
31769d150b73SToby Isaac     const PetscReal *guess  = &refCoords[dimR * j];
31779d150b73SToby Isaac     PetscReal       *mapped = &realCoords[dimC * j];
31789d150b73SToby Isaac 
31799d150b73SToby Isaac     for (k = 0; k < numV; k++) {
31809d150b73SToby Isaac       PetscReal extCoord = 1.;
31819d150b73SToby Isaac       for (l = 0; l < dimR; l++) {
31829d150b73SToby Isaac         PetscReal coord = guess[l];
31839d150b73SToby Isaac         PetscInt  dep   = (k & (1 << l)) >> l;
31849d150b73SToby Isaac 
31859d150b73SToby Isaac         extCoord *= dep * coord + !dep;
31869d150b73SToby Isaac       }
31879d150b73SToby Isaac       for (l = 0; l < dimC; l++) {
31889d150b73SToby Isaac         PetscReal coeff = cellCoeffs[dimC * k + l];
31899d150b73SToby Isaac 
31909d150b73SToby Isaac         mapped[l] += coeff * extCoord;
31919d150b73SToby Isaac       }
31929d150b73SToby Isaac     }
31939d150b73SToby Isaac   }
31949566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
31959566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31969d150b73SToby Isaac   PetscFunctionReturn(0);
31979d150b73SToby Isaac }
31989d150b73SToby Isaac 
31999c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
32009c3cf19fSMatthew G. Knepley static PetscErrorCode DMPlexCoordinatesToReference_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt Nc, PetscInt dimR)
32019d150b73SToby Isaac {
32029c3cf19fSMatthew G. Knepley   PetscInt       numComp, pdim, i, j, k, l, m, maxIter = 7, coordSize;
3203c6e120d1SToby Isaac   PetscScalar    *nodes = NULL;
3204c6e120d1SToby Isaac   PetscReal      *invV, *modes;
3205c6e120d1SToby Isaac   PetscReal      *B, *D, *resNeg;
3206c6e120d1SToby Isaac   PetscScalar    *J, *invJ, *work;
32079d150b73SToby Isaac 
32089d150b73SToby Isaac   PetscFunctionBegin;
32099566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32109566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
321163a3b9bcSJacob 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);
32129566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32139d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32149566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim,MPIU_REAL,&modes));
32159d150b73SToby Isaac   invV = fe->invV;
3216012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3217012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3218012b7cc6SMatthew G. Knepley     for (j = 0; j < pdim; ++j) {
3219012b7cc6SMatthew G. Knepley       modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
32209d150b73SToby Isaac     }
32219d150b73SToby Isaac   }
32229566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B));
32239c3cf19fSMatthew G. Knepley   D      = &B[pdim*Nc];
32249c3cf19fSMatthew G. Knepley   resNeg = &D[pdim*Nc * dimR];
32259566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J));
32269c3cf19fSMatthew G. Knepley   invJ = &J[Nc * dimR];
32279c3cf19fSMatthew G. Knepley   work = &invJ[Nc * dimR];
32289d150b73SToby Isaac   for (i = 0; i < numPoints * dimR; i++) {refCoords[i] = 0.;}
32299d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32309b1f03cbSToby 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 */
32319d150b73SToby Isaac       PetscReal *guess = &refCoords[j * dimR];
32329566063dSJacob Faibussowitsch       PetscCall(PetscSpaceEvaluate(fe->basisSpace, 1, guess, B, D, NULL));
32339c3cf19fSMatthew G. Knepley       for (k = 0; k < Nc; k++) {resNeg[k] = realCoords[j * Nc + k];}
32349c3cf19fSMatthew G. Knepley       for (k = 0; k < Nc * dimR; k++) {J[k] = 0.;}
32359c3cf19fSMatthew G. Knepley       for (k = 0; k < pdim; k++) {
32369c3cf19fSMatthew G. Knepley         for (l = 0; l < Nc; l++) {
3237012b7cc6SMatthew G. Knepley           resNeg[l] -= modes[k] * B[k * Nc + l];
32389d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
3239012b7cc6SMatthew G. Knepley             J[l * dimR + m] += modes[k] * D[(k * Nc + l) * dimR + m];
32409d150b73SToby Isaac           }
32419d150b73SToby Isaac         }
32429d150b73SToby Isaac       }
324376bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
32440611203eSToby Isaac         PetscReal maxAbs = 0.;
32450611203eSToby Isaac 
32469c3cf19fSMatthew G. Knepley         for (l = 0; l < Nc; l++) {
32470611203eSToby Isaac           maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l]));
32480611203eSToby Isaac         }
324963a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm,"cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n",cell,j,i,(double) maxAbs));
32500611203eSToby Isaac       }
32519566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(Nc,dimR,J,invJ,work,resNeg,guess));
32529d150b73SToby Isaac     }
32539d150b73SToby Isaac   }
32549566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J));
32559566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B));
32569566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes));
32579566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32589d150b73SToby Isaac   PetscFunctionReturn(0);
32599d150b73SToby Isaac }
32609d150b73SToby Isaac 
32619c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
32629c3cf19fSMatthew G. Knepley static PetscErrorCode DMPlexReferenceToCoordinates_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt Nc, PetscInt dimR)
32639d150b73SToby Isaac {
32649c3cf19fSMatthew G. Knepley   PetscInt       numComp, pdim, i, j, k, l, coordSize;
3265c6e120d1SToby Isaac   PetscScalar    *nodes = NULL;
3266c6e120d1SToby Isaac   PetscReal      *invV, *modes;
32679d150b73SToby Isaac   PetscReal      *B;
32689d150b73SToby Isaac 
32699d150b73SToby Isaac   PetscFunctionBegin;
32709566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32719566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
327263a3b9bcSJacob 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);
32739566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32749d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32759566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim,MPIU_REAL,&modes));
32769d150b73SToby Isaac   invV = fe->invV;
3277012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3278012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3279012b7cc6SMatthew G. Knepley     for (j = 0; j < pdim; ++j) {
3280012b7cc6SMatthew G. Knepley       modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
32819d150b73SToby Isaac     }
32829d150b73SToby Isaac   }
32839566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B));
32849566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(fe->basisSpace, numPoints, refCoords, B, NULL, NULL));
32859c3cf19fSMatthew G. Knepley   for (i = 0; i < numPoints * Nc; i++) {realCoords[i] = 0.;}
32869d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32879c3cf19fSMatthew G. Knepley     PetscReal *mapped = &realCoords[j * Nc];
32889d150b73SToby Isaac 
32899c3cf19fSMatthew G. Knepley     for (k = 0; k < pdim; k++) {
32909c3cf19fSMatthew G. Knepley       for (l = 0; l < Nc; l++) {
329140cf36b3SToby Isaac         mapped[l] += modes[k] * B[(j * pdim + k) * Nc + l];
32929d150b73SToby Isaac       }
32939d150b73SToby Isaac     }
32949d150b73SToby Isaac   }
32959566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B));
32969566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes));
32979566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32989d150b73SToby Isaac   PetscFunctionReturn(0);
32999d150b73SToby Isaac }
33009d150b73SToby Isaac 
3301d6143a4eSToby Isaac /*@
3302d6143a4eSToby Isaac   DMPlexCoordinatesToReference - Pull coordinates back from the mesh to the reference element using a single element
3303d6143a4eSToby Isaac   map.  This inversion will be accurate inside the reference element, but may be inaccurate for mappings that do not
3304d6143a4eSToby Isaac   extend uniquely outside the reference cell (e.g, most non-affine maps)
3305d6143a4eSToby Isaac 
3306d6143a4eSToby Isaac   Not collective
3307d6143a4eSToby Isaac 
3308d6143a4eSToby Isaac   Input Parameters:
3309d6143a4eSToby Isaac + dm         - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or
3310d6143a4eSToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
3311d6143a4eSToby Isaac                as a multilinear map for tensor-product elements
3312d6143a4eSToby Isaac . cell       - the cell whose map is used.
3313d6143a4eSToby Isaac . numPoints  - the number of points to locate
33141b266c99SBarry Smith - realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim())
3315d6143a4eSToby Isaac 
3316d6143a4eSToby Isaac   Output Parameters:
3317d6143a4eSToby Isaac . refCoords  - (numPoints x dimension) array of reference coordinates (see DMGetDimension())
33181b266c99SBarry Smith 
33191b266c99SBarry Smith   Level: intermediate
332073c9229bSMatthew Knepley 
3321db781477SPatrick Sanan .seealso: `DMPlexReferenceToCoordinates()`
3322d6143a4eSToby Isaac @*/
3323d6143a4eSToby Isaac PetscErrorCode DMPlexCoordinatesToReference(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[])
3324d6143a4eSToby Isaac {
3325485ad865SMatthew G. Knepley   PetscInt       dimC, dimR, depth, cStart, cEnd, i;
33269d150b73SToby Isaac   DM             coordDM = NULL;
33279d150b73SToby Isaac   Vec            coords;
33289d150b73SToby Isaac   PetscFE        fe = NULL;
33299d150b73SToby Isaac 
3330d6143a4eSToby Isaac   PetscFunctionBegin;
33319d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
33329566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dimR));
33339566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&dimC));
33349d150b73SToby Isaac   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0);
33359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
33369566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm,&coords));
33379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&coordDM));
33389d150b73SToby Isaac   if (coordDM) {
33399d150b73SToby Isaac     PetscInt coordFields;
33409d150b73SToby Isaac 
33419566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM,&coordFields));
33429d150b73SToby Isaac     if (coordFields) {
33439d150b73SToby Isaac       PetscClassId id;
33449d150b73SToby Isaac       PetscObject  disc;
33459d150b73SToby Isaac 
33469566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM,0,NULL,&disc));
33479566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
33489d150b73SToby Isaac       if (id == PETSCFE_CLASSID) {
33499d150b73SToby Isaac         fe = (PetscFE) disc;
33509d150b73SToby Isaac       }
33519d150b73SToby Isaac     }
33529d150b73SToby Isaac   }
33539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
33541dca8a05SBarry 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);
33559d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
33569d150b73SToby Isaac     PetscInt  coneSize;
33579d150b73SToby Isaac     PetscBool isSimplex, isTensor;
33589d150b73SToby Isaac 
33599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,cell,&coneSize));
33609d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
33619d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
33629d150b73SToby Isaac     if (isSimplex) {
33639d150b73SToby Isaac       PetscReal detJ, *v0, *J, *invJ;
33649d150b73SToby Isaac 
33659566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33669d150b73SToby Isaac       J    = &v0[dimC];
33679d150b73SToby Isaac       invJ = &J[dimC * dimC];
33689566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, invJ, &detJ));
33699d150b73SToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the inverse affine transformation for each point */
3370c330f8ffSToby Isaac         const PetscReal x0[3] = {-1.,-1.,-1.};
3371c330f8ffSToby Isaac 
3372c330f8ffSToby Isaac         CoordinatesRealToRef(dimC, dimR, x0, v0, invJ, &realCoords[dimC * i], &refCoords[dimR * i]);
33739d150b73SToby Isaac       }
33749566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33759d150b73SToby Isaac     } else if (isTensor) {
33769566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_Tensor(coordDM, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
337763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %" PetscInt_FMT,coneSize);
33789d150b73SToby Isaac   } else {
33799566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesToReference_FE(coordDM, fe, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
33809d150b73SToby Isaac   }
33819d150b73SToby Isaac   PetscFunctionReturn(0);
33829d150b73SToby Isaac }
33839d150b73SToby Isaac 
33849d150b73SToby Isaac /*@
33859d150b73SToby Isaac   DMPlexReferenceToCoordinates - Map references coordinates to coordinates in the the mesh for a single element map.
33869d150b73SToby Isaac 
33879d150b73SToby Isaac   Not collective
33889d150b73SToby Isaac 
33899d150b73SToby Isaac   Input Parameters:
33909d150b73SToby Isaac + dm         - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or
33919d150b73SToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
33929d150b73SToby Isaac                as a multilinear map for tensor-product elements
33939d150b73SToby Isaac . cell       - the cell whose map is used.
33949d150b73SToby Isaac . numPoints  - the number of points to locate
3395a2b725a8SWilliam Gropp - refCoords  - (numPoints x dimension) array of reference coordinates (see DMGetDimension())
33969d150b73SToby Isaac 
33979d150b73SToby Isaac   Output Parameters:
33989d150b73SToby Isaac . realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim())
33991b266c99SBarry Smith 
34001b266c99SBarry Smith    Level: intermediate
340173c9229bSMatthew Knepley 
3402db781477SPatrick Sanan .seealso: `DMPlexCoordinatesToReference()`
34039d150b73SToby Isaac @*/
34049d150b73SToby Isaac PetscErrorCode DMPlexReferenceToCoordinates(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[])
34059d150b73SToby Isaac {
3406485ad865SMatthew G. Knepley   PetscInt       dimC, dimR, depth, cStart, cEnd, i;
34079d150b73SToby Isaac   DM             coordDM = NULL;
34089d150b73SToby Isaac   Vec            coords;
34099d150b73SToby Isaac   PetscFE        fe = NULL;
34109d150b73SToby Isaac 
34119d150b73SToby Isaac   PetscFunctionBegin;
34129d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
34139566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dimR));
34149566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&dimC));
34159d150b73SToby Isaac   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0);
34169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
34179566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm,&coords));
34189566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&coordDM));
34199d150b73SToby Isaac   if (coordDM) {
34209d150b73SToby Isaac     PetscInt coordFields;
34219d150b73SToby Isaac 
34229566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM,&coordFields));
34239d150b73SToby Isaac     if (coordFields) {
34249d150b73SToby Isaac       PetscClassId id;
34259d150b73SToby Isaac       PetscObject  disc;
34269d150b73SToby Isaac 
34279566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM,0,NULL,&disc));
34289566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
34299d150b73SToby Isaac       if (id == PETSCFE_CLASSID) {
34309d150b73SToby Isaac         fe = (PetscFE) disc;
34319d150b73SToby Isaac       }
34329d150b73SToby Isaac     }
34339d150b73SToby Isaac   }
34349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
34351dca8a05SBarry 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);
34369d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
34379d150b73SToby Isaac     PetscInt  coneSize;
34389d150b73SToby Isaac     PetscBool isSimplex, isTensor;
34399d150b73SToby Isaac 
34409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,cell,&coneSize));
34419d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
34429d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
34439d150b73SToby Isaac     if (isSimplex) {
34449d150b73SToby Isaac       PetscReal detJ, *v0, *J;
34459d150b73SToby Isaac 
34469566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34479d150b73SToby Isaac       J    = &v0[dimC];
34489566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, NULL, &detJ));
3449c330f8ffSToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the affine transformation for each point */
3450c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
3451c330f8ffSToby Isaac 
3452c330f8ffSToby Isaac         CoordinatesRefToReal(dimC, dimR, xi0, v0, J, &refCoords[dimR * i], &realCoords[dimC * i]);
34539d150b73SToby Isaac       }
34549566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34559d150b73SToby Isaac     } else if (isTensor) {
34569566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates_Tensor(coordDM, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
345763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %" PetscInt_FMT,coneSize);
34589d150b73SToby Isaac   } else {
34599566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates_FE(coordDM, fe, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
34609d150b73SToby Isaac   }
3461d6143a4eSToby Isaac   PetscFunctionReturn(0);
3462d6143a4eSToby Isaac }
34630139fca9SMatthew G. Knepley 
34640139fca9SMatthew G. Knepley /*@C
34650139fca9SMatthew G. Knepley   DMPlexRemapGeometry - This function maps the original DM coordinates to new coordinates.
34660139fca9SMatthew G. Knepley 
34670139fca9SMatthew G. Knepley   Not collective
34680139fca9SMatthew G. Knepley 
34690139fca9SMatthew G. Knepley   Input Parameters:
34700139fca9SMatthew G. Knepley + dm      - The DM
34710139fca9SMatthew G. Knepley . time    - The time
34720139fca9SMatthew G. Knepley - func    - The function transforming current coordinates to new coordaintes
34730139fca9SMatthew G. Knepley 
34740139fca9SMatthew G. Knepley    Calling sequence of func:
34750139fca9SMatthew G. Knepley $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
34760139fca9SMatthew G. Knepley $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
34770139fca9SMatthew G. Knepley $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
34780139fca9SMatthew G. Knepley $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
34790139fca9SMatthew G. Knepley 
34800139fca9SMatthew G. Knepley +  dim          - The spatial dimension
34810139fca9SMatthew G. Knepley .  Nf           - The number of input fields (here 1)
34820139fca9SMatthew G. Knepley .  NfAux        - The number of input auxiliary fields
34830139fca9SMatthew G. Knepley .  uOff         - The offset of the coordinates in u[] (here 0)
34840139fca9SMatthew G. Knepley .  uOff_x       - The offset of the coordinates in u_x[] (here 0)
34850139fca9SMatthew G. Knepley .  u            - The coordinate values at this point in space
34860139fca9SMatthew G. Knepley .  u_t          - The coordinate time derivative at this point in space (here NULL)
34870139fca9SMatthew G. Knepley .  u_x          - The coordinate derivatives at this point in space
34880139fca9SMatthew G. Knepley .  aOff         - The offset of each auxiliary field in u[]
34890139fca9SMatthew G. Knepley .  aOff_x       - The offset of each auxiliary field in u_x[]
34900139fca9SMatthew G. Knepley .  a            - The auxiliary field values at this point in space
34910139fca9SMatthew G. Knepley .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
34920139fca9SMatthew G. Knepley .  a_x          - The auxiliary field derivatives at this point in space
34930139fca9SMatthew G. Knepley .  t            - The current time
34940139fca9SMatthew G. Knepley .  x            - The coordinates of this point (here not used)
34950139fca9SMatthew G. Knepley .  numConstants - The number of constants
34960139fca9SMatthew G. Knepley .  constants    - The value of each constant
34970139fca9SMatthew G. Knepley -  f            - The new coordinates at this point in space
34980139fca9SMatthew G. Knepley 
34990139fca9SMatthew G. Knepley   Level: intermediate
35000139fca9SMatthew G. Knepley 
3501db781477SPatrick Sanan .seealso: `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMProjectFieldLocal()`, `DMProjectFieldLabelLocal()`
35020139fca9SMatthew G. Knepley @*/
35030139fca9SMatthew G. Knepley PetscErrorCode DMPlexRemapGeometry(DM dm, PetscReal time,
35040139fca9SMatthew G. Knepley                                    void (*func)(PetscInt, PetscInt, PetscInt,
35050139fca9SMatthew G. Knepley                                                 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
35060139fca9SMatthew G. Knepley                                                 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
35070139fca9SMatthew G. Knepley                                                 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
35080139fca9SMatthew G. Knepley {
35090139fca9SMatthew G. Knepley   DM             cdm;
35108bf1a49fSMatthew G. Knepley   DMField        cf;
35110139fca9SMatthew G. Knepley   Vec            lCoords, tmpCoords;
35120139fca9SMatthew G. Knepley 
35130139fca9SMatthew G. Knepley   PetscFunctionBegin;
35149566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35159566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(cdm, &tmpCoords));
35179566063dSJacob Faibussowitsch   PetscCall(VecCopy(lCoords, tmpCoords));
35188bf1a49fSMatthew G. Knepley   /* We have to do the coordinate field manually right now since the coordinate DM will not have its own */
35199566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &cf));
35206858538eSMatthew G. Knepley   cdm->coordinates[0].field = cf;
35219566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(cdm, time, tmpCoords, &func, INSERT_VALUES, lCoords));
35226858538eSMatthew G. Knepley   cdm->coordinates[0].field = NULL;
35239566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(cdm, &tmpCoords));
35249566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, lCoords));
35250139fca9SMatthew G. Knepley   PetscFunctionReturn(0);
35260139fca9SMatthew G. Knepley }
35270139fca9SMatthew G. Knepley 
35280139fca9SMatthew G. Knepley /* Shear applies the transformation, assuming we fix z,
35290139fca9SMatthew G. Knepley   / 1  0  m_0 \
35300139fca9SMatthew G. Knepley   | 0  1  m_1 |
35310139fca9SMatthew G. Knepley   \ 0  0   1  /
35320139fca9SMatthew G. Knepley */
35330139fca9SMatthew G. Knepley static void f0_shear(PetscInt dim, PetscInt Nf, PetscInt NfAux,
35340139fca9SMatthew G. Knepley                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
35350139fca9SMatthew G. Knepley                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
35360139fca9SMatthew G. Knepley                      PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar coords[])
35370139fca9SMatthew G. Knepley {
35380139fca9SMatthew G. Knepley   const PetscInt Nc = uOff[1]-uOff[0];
3539c1f1bd54SMatthew G. Knepley   const PetscInt ax = (PetscInt) PetscRealPart(constants[0]);
35400139fca9SMatthew G. Knepley   PetscInt       c;
35410139fca9SMatthew G. Knepley 
35420139fca9SMatthew G. Knepley   for (c = 0; c < Nc; ++c) {
35430139fca9SMatthew G. Knepley     coords[c] = u[c] + constants[c+1]*u[ax];
35440139fca9SMatthew G. Knepley   }
35450139fca9SMatthew G. Knepley }
35460139fca9SMatthew G. Knepley 
35470139fca9SMatthew G. Knepley /*@C
35480139fca9SMatthew G. Knepley   DMPlexShearGeometry - This shears the domain, meaning adds a multiple of the shear coordinate to all other coordinates.
35490139fca9SMatthew G. Knepley 
35500139fca9SMatthew G. Knepley   Not collective
35510139fca9SMatthew G. Knepley 
35520139fca9SMatthew G. Knepley   Input Parameters:
35530139fca9SMatthew G. Knepley + dm          - The DM
35543ee9839eSMatthew G. Knepley . direction   - The shear coordinate direction, e.g. 0 is the x-axis
35550139fca9SMatthew G. Knepley - multipliers - The multiplier m for each direction which is not the shear direction
35560139fca9SMatthew G. Knepley 
35570139fca9SMatthew G. Knepley   Level: intermediate
35580139fca9SMatthew G. Knepley 
3559db781477SPatrick Sanan .seealso: `DMPlexRemapGeometry()`
35600139fca9SMatthew G. Knepley @*/
35613ee9839eSMatthew G. Knepley PetscErrorCode DMPlexShearGeometry(DM dm, DMDirection direction, PetscReal multipliers[])
35620139fca9SMatthew G. Knepley {
35630139fca9SMatthew G. Knepley   DM             cdm;
35640139fca9SMatthew G. Knepley   PetscDS        cds;
35650139fca9SMatthew G. Knepley   PetscObject    obj;
35660139fca9SMatthew G. Knepley   PetscClassId   id;
35670139fca9SMatthew G. Knepley   PetscScalar   *moduli;
35683ee9839eSMatthew G. Knepley   const PetscInt dir = (PetscInt) direction;
35690139fca9SMatthew G. Knepley   PetscInt       dE, d, e;
35700139fca9SMatthew G. Knepley 
35710139fca9SMatthew G. Knepley   PetscFunctionBegin;
35729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35739566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
35749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dE+1, &moduli));
35750139fca9SMatthew G. Knepley   moduli[0] = dir;
3576cdaaecf7SMatthew G. Knepley   for (d = 0, e = 0; d < dE; ++d) moduli[d+1] = d == dir ? 0.0 : (multipliers ? multipliers[e++] : 1.0);
35779566063dSJacob Faibussowitsch   PetscCall(DMGetDS(cdm, &cds));
35789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
35799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetClassId(obj, &id));
35800139fca9SMatthew G. Knepley   if (id != PETSCFE_CLASSID) {
35810139fca9SMatthew G. Knepley     Vec           lCoords;
35820139fca9SMatthew G. Knepley     PetscSection  cSection;
35830139fca9SMatthew G. Knepley     PetscScalar  *coords;
35840139fca9SMatthew G. Knepley     PetscInt      vStart, vEnd, v;
35850139fca9SMatthew G. Knepley 
35869566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
35879566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &cSection));
35889566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35899566063dSJacob Faibussowitsch     PetscCall(VecGetArray(lCoords, &coords));
35900139fca9SMatthew G. Knepley     for (v = vStart; v < vEnd; ++v) {
35910139fca9SMatthew G. Knepley       PetscReal ds;
35920139fca9SMatthew G. Knepley       PetscInt  off, c;
35930139fca9SMatthew G. Knepley 
35949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSection, v, &off));
35950139fca9SMatthew G. Knepley       ds   = PetscRealPart(coords[off+dir]);
35960139fca9SMatthew G. Knepley       for (c = 0; c < dE; ++c) coords[off+c] += moduli[c]*ds;
35970139fca9SMatthew G. Knepley     }
35989566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(lCoords, &coords));
35990139fca9SMatthew G. Knepley   } else {
36009566063dSJacob Faibussowitsch     PetscCall(PetscDSSetConstants(cds, dE+1, moduli));
36019566063dSJacob Faibussowitsch     PetscCall(DMPlexRemapGeometry(dm, 0.0, f0_shear));
36020139fca9SMatthew G. Knepley   }
36039566063dSJacob Faibussowitsch   PetscCall(PetscFree(moduli));
36040139fca9SMatthew G. Knepley   PetscFunctionReturn(0);
36050139fca9SMatthew G. Knepley }
3606