xref: /petsc/src/dm/impls/plex/plexgeometry.c (revision 792fecdfe9134cce4d631112660ddd34f063bc17)
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 
442db781477SPatrick Sanan .seealso: `PetscGridHashCreate()`
44362a38674SMatthew G. Knepley */
4441c6dfc3eSMatthew G. Knepley PetscErrorCode PetscGridHashGetEnclosingBox(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[])
445c4eade1cSMatthew G. Knepley {
446c4eade1cSMatthew G. Knepley   const PetscReal *lower = box->lower;
447c4eade1cSMatthew G. Knepley   const PetscReal *upper = box->upper;
448c4eade1cSMatthew G. Knepley   const PetscReal *h     = box->h;
449c4eade1cSMatthew G. Knepley   const PetscInt  *n     = box->n;
450c4eade1cSMatthew G. Knepley   const PetscInt   dim   = box->dim;
451c4eade1cSMatthew G. Knepley   PetscInt         d, p;
452c4eade1cSMatthew G. Knepley 
453c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
454c4eade1cSMatthew G. Knepley   for (p = 0; p < numPoints; ++p) {
455c4eade1cSMatthew G. Knepley     for (d = 0; d < dim; ++d) {
4561c6dfc3eSMatthew G. Knepley       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]);
457c4eade1cSMatthew G. Knepley 
4581c6dfc3eSMatthew G. Knepley       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1;
4592a705cacSMatthew G. Knepley       if (dbox == -1   && PetscAbsReal(PetscRealPart(points[p*dim+d]) - lower[d]) < 1.0e-9) dbox = 0;
46063a3b9bcSJacob 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",
461087ef6b2SMatthew 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);
462c4eade1cSMatthew G. Knepley       dboxes[p*dim+d] = dbox;
463c4eade1cSMatthew G. Knepley     }
464ddce0771SMatthew 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];
465c4eade1cSMatthew G. Knepley   }
466c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
467c4eade1cSMatthew G. Knepley }
468c4eade1cSMatthew G. Knepley 
469af74b616SDave May /*
470af74b616SDave May  PetscGridHashGetEnclosingBoxQuery - Find the grid boxes containing each input point
471af74b616SDave May 
472af74b616SDave May  Not collective
473af74b616SDave May 
474af74b616SDave May   Input Parameters:
475af74b616SDave May + box       - The grid hash object
476af74b616SDave May . numPoints - The number of input points
477af74b616SDave May - points    - The input point coordinates
478af74b616SDave May 
479af74b616SDave May   Output Parameters:
480af74b616SDave May + dboxes    - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim)
481af74b616SDave May . boxes     - An array of numPoints integers expressing the enclosing box as single number, or NULL
482af74b616SDave May - found     - Flag indicating if point was located within a box
483af74b616SDave May 
484af74b616SDave May   Level: developer
485af74b616SDave May 
486db781477SPatrick Sanan .seealso: `PetscGridHashGetEnclosingBox()`
487af74b616SDave May */
488af74b616SDave May PetscErrorCode PetscGridHashGetEnclosingBoxQuery(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[],PetscBool *found)
489af74b616SDave May {
490af74b616SDave May   const PetscReal *lower = box->lower;
491af74b616SDave May   const PetscReal *upper = box->upper;
492af74b616SDave May   const PetscReal *h     = box->h;
493af74b616SDave May   const PetscInt  *n     = box->n;
494af74b616SDave May   const PetscInt   dim   = box->dim;
495af74b616SDave May   PetscInt         d, p;
496af74b616SDave May 
497af74b616SDave May   PetscFunctionBegin;
498af74b616SDave May   *found = PETSC_FALSE;
499af74b616SDave May   for (p = 0; p < numPoints; ++p) {
500af74b616SDave May     for (d = 0; d < dim; ++d) {
501af74b616SDave May       PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]);
502af74b616SDave May 
503af74b616SDave May       if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1;
504af74b616SDave May       if (dbox < 0 || dbox >= n[d]) {
505af74b616SDave May         PetscFunctionReturn(0);
506af74b616SDave May       }
507af74b616SDave May       dboxes[p*dim+d] = dbox;
508af74b616SDave May     }
509ddce0771SMatthew 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];
510af74b616SDave May   }
511af74b616SDave May   *found = PETSC_TRUE;
512af74b616SDave May   PetscFunctionReturn(0);
513af74b616SDave May }
514af74b616SDave May 
515c4eade1cSMatthew G. Knepley PetscErrorCode PetscGridHashDestroy(PetscGridHash *box)
516c4eade1cSMatthew G. Knepley {
517c4eade1cSMatthew G. Knepley   PetscFunctionBegin;
518c4eade1cSMatthew G. Knepley   if (*box) {
5199566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(*box)->cellSection));
5209566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&(*box)->cells));
5219566063dSJacob Faibussowitsch     PetscCall(DMLabelDestroy(&(*box)->cellsSparse));
522c4eade1cSMatthew G. Knepley   }
5239566063dSJacob Faibussowitsch   PetscCall(PetscFree(*box));
524c4eade1cSMatthew G. Knepley   PetscFunctionReturn(0);
525c4eade1cSMatthew G. Knepley }
526c4eade1cSMatthew G. Knepley 
527cafe43deSMatthew G. Knepley PetscErrorCode DMPlexLocatePoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cellStart, PetscInt *cell)
528cafe43deSMatthew G. Knepley {
529ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
530cafe43deSMatthew G. Knepley 
531cafe43deSMatthew G. Knepley   PetscFunctionBegin;
5329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cellStart, &ct));
533ba2698f1SMatthew G. Knepley   switch (ct) {
53414bbb9f0SLawrence Mitchell     case DM_POLYTOPE_SEGMENT:
5359566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_1D_Internal(dm, point, cellStart, cell));break;
536ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
5379566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_2D_Internal(dm, point, cellStart, cell));break;
538ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
5399566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Quad_2D_Internal(dm, point, cellStart, cell));break;
540ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
5419566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_Simplex_3D_Internal(dm, point, cellStart, cell));break;
542ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
5439566063dSJacob Faibussowitsch     PetscCall(DMPlexLocatePoint_General_3D_Internal(dm, point, cellStart, cell));break;
54463a3b9bcSJacob Faibussowitsch     default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell %" PetscInt_FMT " with type %s", cellStart, DMPolytopeTypes[ct]);
545cafe43deSMatthew G. Knepley   }
546cafe43deSMatthew G. Knepley   PetscFunctionReturn(0);
547cafe43deSMatthew G. Knepley }
548cafe43deSMatthew G. Knepley 
54962a38674SMatthew G. Knepley /*
55062a38674SMatthew G. Knepley   DMPlexClosestPoint_Internal - Returns the closest point in the cell to the given point
55162a38674SMatthew G. Knepley */
55262a38674SMatthew G. Knepley PetscErrorCode DMPlexClosestPoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cell, PetscReal cpoint[])
55362a38674SMatthew G. Knepley {
554ba2698f1SMatthew G. Knepley   DMPolytopeType ct;
55562a38674SMatthew G. Knepley 
55662a38674SMatthew G. Knepley   PetscFunctionBegin;
5579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
558ba2698f1SMatthew G. Knepley   switch (ct) {
559ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
5609566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_2D_Internal(dm, point, cell, cpoint));break;
56162a38674SMatthew G. Knepley #if 0
562ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
5639566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_2D_Internal(dm, point, cell, cpoint));break;
564ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
5659566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_Simplex_3D_Internal(dm, point, cell, cpoint));break;
566ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
5679566063dSJacob Faibussowitsch     PetscCall(DMPlexClosestPoint_General_3D_Internal(dm, point, cell, cpoint));break;
56862a38674SMatthew G. Knepley #endif
56963a3b9bcSJacob Faibussowitsch     default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No closest point location for cell %" PetscInt_FMT " with type %s", cell, DMPolytopeTypes[ct]);
57062a38674SMatthew G. Knepley   }
57162a38674SMatthew G. Knepley   PetscFunctionReturn(0);
57262a38674SMatthew G. Knepley }
57362a38674SMatthew G. Knepley 
57462a38674SMatthew G. Knepley /*
57562a38674SMatthew G. Knepley   DMPlexComputeGridHash_Internal - Create a grid hash structure covering the Plex
57662a38674SMatthew G. Knepley 
577d083f849SBarry Smith   Collective on dm
57862a38674SMatthew G. Knepley 
57962a38674SMatthew G. Knepley   Input Parameter:
58062a38674SMatthew G. Knepley . dm - The Plex
58162a38674SMatthew G. Knepley 
58262a38674SMatthew G. Knepley   Output Parameter:
58362a38674SMatthew G. Knepley . localBox - The grid hash object
58462a38674SMatthew G. Knepley 
58562a38674SMatthew G. Knepley   Level: developer
58662a38674SMatthew G. Knepley 
587db781477SPatrick Sanan .seealso: `PetscGridHashCreate()`, `PetscGridHashGetEnclosingBox()`
58862a38674SMatthew G. Knepley */
589cafe43deSMatthew G. Knepley PetscErrorCode DMPlexComputeGridHash_Internal(DM dm, PetscGridHash *localBox)
590cafe43deSMatthew G. Knepley {
591ddce0771SMatthew G. Knepley   const PetscInt     debug = 0;
592cafe43deSMatthew G. Knepley   MPI_Comm           comm;
593cafe43deSMatthew G. Knepley   PetscGridHash      lbox;
594cafe43deSMatthew G. Knepley   Vec                coordinates;
595cafe43deSMatthew G. Knepley   PetscSection       coordSection;
596cafe43deSMatthew G. Knepley   Vec                coordsLocal;
597cafe43deSMatthew G. Knepley   const PetscScalar *coords;
598ddce0771SMatthew G. Knepley   PetscScalar       *edgeCoords;
599722d0f5cSMatthew G. Knepley   PetscInt          *dboxes, *boxes;
600ddce0771SMatthew G. Knepley   PetscInt           n[3] = {2, 2, 2};
601ddce0771SMatthew G. Knepley   PetscInt           dim, N, maxConeSize, cStart, cEnd, c, eStart, eEnd, i;
602ddce0771SMatthew G. Knepley   PetscBool          flg;
603cafe43deSMatthew G. Knepley 
604cafe43deSMatthew G. Knepley   PetscFunctionBegin;
6059566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
6069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
6079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
6089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
6099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
6109566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(coordinates, &N));
6119566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
6129566063dSJacob Faibussowitsch   PetscCall(PetscGridHashCreate(comm, dim, coords, &lbox));
6139566063dSJacob Faibussowitsch   for (i = 0; i < N; i += dim) PetscCall(PetscGridHashEnlarge(lbox, &coords[i]));
6149566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
615ddce0771SMatthew G. Knepley   c    = dim;
6169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject) dm)->prefix, "-dm_plex_hash_box_faces", n, &c, &flg));
617ddce0771SMatthew G. Knepley   if (flg) {for (i = c; i < dim; ++i) n[i] = n[c-1];}
618ddce0771SMatthew G. Knepley   else     {for (i = 0; i < dim; ++i) n[i] = PetscMax(2, PetscFloorReal(PetscPowReal((PetscReal) (cEnd - cStart), 1.0/dim) * 0.8));}
6199566063dSJacob Faibussowitsch   PetscCall(PetscGridHashSetGrid(lbox, n, NULL));
620cafe43deSMatthew G. Knepley #if 0
621cafe43deSMatthew G. Knepley   /* Could define a custom reduction to merge these */
6221c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->lower, gbox->lower, 3, MPIU_REAL, MPI_MIN, comm));
6231c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lbox->upper, gbox->upper, 3, MPIU_REAL, MPI_MAX, comm));
624cafe43deSMatthew G. Knepley #endif
625cafe43deSMatthew G. Knepley   /* Is there a reason to snap the local bounding box to a division of the global box? */
626cafe43deSMatthew G. Knepley   /* Should we compute all overlaps of local boxes? We could do this with a rendevouz scheme partitioning the global box */
627cafe43deSMatthew G. Knepley   /* Create label */
6289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
629b26b5bf9SMatthew G. Knepley   if (dim < 2) eStart = eEnd = -1;
6309566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "cells", &lbox->cellsSparse));
6319566063dSJacob Faibussowitsch   PetscCall(DMLabelCreateIndex(lbox->cellsSparse, cStart, cEnd));
632a8d69d7bSBarry Smith   /* Compute boxes which overlap each cell: https://stackoverflow.com/questions/13790208/triangle-square-intersection-test-in-2d */
6339566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
6349566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6359566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(16 * dim, &dboxes, 16, &boxes, PetscPowInt(maxConeSize, dim) * dim, &edgeCoords));
636cafe43deSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
637cafe43deSMatthew G. Knepley     const PetscReal *h       = lbox->h;
638cafe43deSMatthew G. Knepley     PetscScalar     *ccoords = NULL;
63938353de4SMatthew G. Knepley     PetscInt         csize   = 0;
640ddce0771SMatthew G. Knepley     PetscInt        *closure = NULL;
641ddce0771SMatthew G. Knepley     PetscInt         Ncl, cl, Ne = 0;
642cafe43deSMatthew G. Knepley     PetscScalar      point[3];
643cafe43deSMatthew G. Knepley     PetscInt         dlim[6], d, e, i, j, k;
644cafe43deSMatthew G. Knepley 
645ddce0771SMatthew G. Knepley     /* Get all edges in cell */
6469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
647ddce0771SMatthew G. Knepley     for (cl = 0; cl < Ncl*2; ++cl) {
648ddce0771SMatthew G. Knepley       if ((closure[cl] >= eStart) && (closure[cl] < eEnd)) {
649ddce0771SMatthew G. Knepley         PetscScalar *ecoords = &edgeCoords[Ne*dim*2];
650ddce0771SMatthew G. Knepley         PetscInt     ecsize  = dim*2;
651ddce0771SMatthew G. Knepley 
6529566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, closure[cl], &ecsize, &ecoords));
65363a3b9bcSJacob 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);
654ddce0771SMatthew G. Knepley         ++Ne;
655ddce0771SMatthew G. Knepley       }
656ddce0771SMatthew G. Knepley     }
6579566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &Ncl, &closure));
658cafe43deSMatthew G. Knepley     /* Find boxes enclosing each vertex */
6599566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &csize, &ccoords));
6609566063dSJacob Faibussowitsch     PetscCall(PetscGridHashGetEnclosingBox(lbox, csize/dim, ccoords, dboxes, boxes));
661722d0f5cSMatthew G. Knepley     /* Mark cells containing the vertices */
662ddce0771SMatthew G. Knepley     for (e = 0; e < csize/dim; ++e) {
66363a3b9bcSJacob 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));
6649566063dSJacob Faibussowitsch       PetscCall(DMLabelSetValue(lbox->cellsSparse, c, boxes[e]));
665ddce0771SMatthew G. Knepley     }
666cafe43deSMatthew G. Knepley     /* Get grid of boxes containing these */
667cafe43deSMatthew G. Knepley     for (d = 0;   d < dim; ++d) {dlim[d*2+0] = dlim[d*2+1] = dboxes[d];}
6682291669eSMatthew G. Knepley     for (d = dim; d < 3;   ++d) {dlim[d*2+0] = dlim[d*2+1] = 0;}
669cafe43deSMatthew G. Knepley     for (e = 1; e < dim+1; ++e) {
670cafe43deSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
671cafe43deSMatthew G. Knepley         dlim[d*2+0] = PetscMin(dlim[d*2+0], dboxes[e*dim+d]);
672cafe43deSMatthew G. Knepley         dlim[d*2+1] = PetscMax(dlim[d*2+1], dboxes[e*dim+d]);
673cafe43deSMatthew G. Knepley       }
674cafe43deSMatthew G. Knepley     }
675fea14342SMatthew G. Knepley     /* Check for intersection of box with cell */
676cafe43deSMatthew 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]) {
677cafe43deSMatthew 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]) {
678cafe43deSMatthew 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]) {
679cafe43deSMatthew G. Knepley           const PetscInt box = (k*lbox->n[1] + j)*lbox->n[0] + i;
680cafe43deSMatthew G. Knepley           PetscScalar    cpoint[3];
681fea14342SMatthew G. Knepley           PetscInt       cell, edge, ii, jj, kk;
682cafe43deSMatthew G. Knepley 
68363a3b9bcSJacob 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])));
684ddce0771SMatthew G. Knepley           /* Check whether cell contains any vertex of this subbox TODO vectorize this */
685cafe43deSMatthew G. Knepley           for (kk = 0, cpoint[2] = point[2]; kk < (dim > 2 ? 2 : 1); ++kk, cpoint[2] += h[2]) {
686cafe43deSMatthew G. Knepley             for (jj = 0, cpoint[1] = point[1]; jj < (dim > 1 ? 2 : 1); ++jj, cpoint[1] += h[1]) {
687cafe43deSMatthew G. Knepley               for (ii = 0, cpoint[0] = point[0]; ii < 2; ++ii, cpoint[0] += h[0]) {
688cafe43deSMatthew G. Knepley 
6899566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(dm, dim, cpoint, c, &cell));
6900b6bfacdSStefano Zampini                 if (cell >= 0) {
69163a3b9bcSJacob 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));
6929566063dSJacob Faibussowitsch                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box));
6930b6bfacdSStefano Zampini                   jj = kk = 2;
6940b6bfacdSStefano Zampini                   break;
6950b6bfacdSStefano Zampini                 }
696cafe43deSMatthew G. Knepley               }
697cafe43deSMatthew G. Knepley             }
698cafe43deSMatthew G. Knepley           }
699ddce0771SMatthew G. Knepley           /* Check whether cell edge intersects any face of these subboxes TODO vectorize this */
700ddce0771SMatthew G. Knepley           for (edge = 0; edge < Ne; ++edge) {
701a5cae605SSatish Balay             PetscReal segA[6] = {0.,0.,0.,0.,0.,0.};
702a5cae605SSatish Balay             PetscReal segB[6] = {0.,0.,0.,0.,0.,0.};
703a5cae605SSatish Balay             PetscReal segC[6] = {0.,0.,0.,0.,0.,0.};
704fea14342SMatthew G. Knepley 
70563a3b9bcSJacob Faibussowitsch             PetscCheck(dim <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected dim %" PetscInt_FMT " > 3",dim);
706ddce0771SMatthew G. Knepley             for (d = 0; d < dim*2; ++d) segA[d] = PetscRealPart(edgeCoords[edge*dim*2+d]);
707ddce0771SMatthew G. Knepley             /* 1D: (x) -- (x+h)               0 -- 1
708ddce0771SMatthew G. Knepley                2D: (x,   y)   -- (x,   y+h)   (0, 0) -- (0, 1)
709ddce0771SMatthew G. Knepley                    (x+h, y)   -- (x+h, y+h)   (1, 0) -- (1, 1)
710ddce0771SMatthew G. Knepley                    (x,   y)   -- (x+h, y)     (0, 0) -- (1, 0)
711ddce0771SMatthew G. Knepley                    (x,   y+h) -- (x+h, y+h)   (0, 1) -- (1, 1)
712ddce0771SMatthew 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)
713ddce0771SMatthew 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)
714ddce0771SMatthew 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)
715ddce0771SMatthew 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)
716ddce0771SMatthew 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)
717ddce0771SMatthew 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)
718ddce0771SMatthew G. Knepley              */
719ddce0771SMatthew G. Knepley             /* Loop over faces with normal in direction d */
720ddce0771SMatthew G. Knepley             for (d = 0; d < dim; ++d) {
721ddce0771SMatthew G. Knepley               PetscBool intersects = PETSC_FALSE;
722ddce0771SMatthew G. Knepley               PetscInt  e = (d+1)%dim;
723ddce0771SMatthew G. Knepley               PetscInt  f = (d+2)%dim;
724ddce0771SMatthew G. Knepley 
725ddce0771SMatthew G. Knepley               /* There are two faces in each dimension */
726ddce0771SMatthew G. Knepley               for (ii = 0; ii < 2; ++ii) {
727ddce0771SMatthew G. Knepley                 segB[d]     = PetscRealPart(point[d] + ii*h[d]);
728ddce0771SMatthew G. Knepley                 segB[dim+d] = PetscRealPart(point[d] + ii*h[d]);
729ddce0771SMatthew G. Knepley                 segC[d]     = PetscRealPart(point[d] + ii*h[d]);
730ddce0771SMatthew G. Knepley                 segC[dim+d] = PetscRealPart(point[d] + ii*h[d]);
731ddce0771SMatthew G. Knepley                 if (dim > 1) {
732ddce0771SMatthew G. Knepley                   segB[e]     = PetscRealPart(point[e] + 0*h[e]);
733ddce0771SMatthew G. Knepley                   segB[dim+e] = PetscRealPart(point[e] + 1*h[e]);
734ddce0771SMatthew G. Knepley                   segC[e]     = PetscRealPart(point[e] + 0*h[e]);
735ddce0771SMatthew G. Knepley                   segC[dim+e] = PetscRealPart(point[e] + 0*h[e]);
736ddce0771SMatthew G. Knepley                 }
737ddce0771SMatthew G. Knepley                 if (dim > 2) {
738ddce0771SMatthew G. Knepley                   segB[f]     = PetscRealPart(point[f] + 0*h[f]);
739ddce0771SMatthew G. Knepley                   segB[dim+f] = PetscRealPart(point[f] + 0*h[f]);
740ddce0771SMatthew G. Knepley                   segC[f]     = PetscRealPart(point[f] + 0*h[f]);
741ddce0771SMatthew G. Knepley                   segC[dim+f] = PetscRealPart(point[f] + 1*h[f]);
742ddce0771SMatthew G. Knepley                 }
743ddce0771SMatthew G. Knepley                 if (dim == 2) {
7449566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLineIntersection_2D_Internal(segA, segB, NULL, &intersects));
745ddce0771SMatthew G. Knepley                 } else if (dim == 3) {
7469566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetLinePlaneIntersection_3D_Internal(segA, segB, segC, NULL, &intersects));
747ddce0771SMatthew G. Knepley                 }
748ddce0771SMatthew G. Knepley                 if (intersects) {
74963a3b9bcSJacob 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]));
7509566063dSJacob Faibussowitsch                   PetscCall(DMLabelSetValue(lbox->cellsSparse, c, box)); edge = Ne; break;
751ddce0771SMatthew G. Knepley                 }
752ddce0771SMatthew G. Knepley               }
753ddce0771SMatthew G. Knepley             }
754cafe43deSMatthew G. Knepley           }
755fea14342SMatthew G. Knepley         }
756fea14342SMatthew G. Knepley       }
757fea14342SMatthew G. Knepley     }
7589566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &ccoords));
759fea14342SMatthew G. Knepley   }
7609566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dboxes, boxes, edgeCoords));
7619566063dSJacob Faibussowitsch   if (debug) PetscCall(DMLabelView(lbox->cellsSparse, PETSC_VIEWER_STDOUT_SELF));
7629566063dSJacob Faibussowitsch   PetscCall(DMLabelConvertToSection(lbox->cellsSparse, &lbox->cellSection, &lbox->cells));
7639566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lbox->cellsSparse));
764cafe43deSMatthew G. Knepley   *localBox = lbox;
765cafe43deSMatthew G. Knepley   PetscFunctionReturn(0);
766cafe43deSMatthew G. Knepley }
767cafe43deSMatthew G. Knepley 
76862a38674SMatthew G. Knepley PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, DMPointLocationType ltype, PetscSF cellSF)
769ccd2543fSMatthew G Knepley {
770ddce0771SMatthew G. Knepley   const PetscInt  debug = 0;
771cafe43deSMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *) dm->data;
772af74b616SDave May   PetscBool       hash = mesh->useHashLocation, reuse = PETSC_FALSE;
7733a93e3b7SToby Isaac   PetscInt        bs, numPoints, p, numFound, *found = NULL;
774412e9a14SMatthew G. Knepley   PetscInt        dim, cStart, cEnd, numCells, c, d;
775cafe43deSMatthew G. Knepley   const PetscInt *boxCells;
7763a93e3b7SToby Isaac   PetscSFNode    *cells;
777ccd2543fSMatthew G Knepley   PetscScalar    *a;
7783a93e3b7SToby Isaac   PetscMPIInt     result;
779af74b616SDave May   PetscLogDouble  t0,t1;
7809cb35068SDave May   PetscReal       gmin[3],gmax[3];
7819cb35068SDave May   PetscInt        terminating_query_type[] = { 0, 0, 0 };
782ccd2543fSMatthew G Knepley 
783ccd2543fSMatthew G Knepley   PetscFunctionBegin;
7849566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_LocatePoints,0,0,0,0));
7859566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t0));
7861dca8a05SBarry 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.");
7879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dim));
7889566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(v, &bs));
7899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)cellSF),PETSC_COMM_SELF,&result));
7901dca8a05SBarry Smith   PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PetscObjectComm((PetscObject)cellSF),PETSC_ERR_SUP, "Trying parallel point location: only local point location supported");
79163a3b9bcSJacob 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);
7926858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
7939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
7949566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &numPoints));
7959566063dSJacob Faibussowitsch   PetscCall(VecGetArray(v, &a));
796ccd2543fSMatthew G Knepley   numPoints /= bs;
797af74b616SDave May   {
798af74b616SDave May     const PetscSFNode *sf_cells;
799af74b616SDave May 
8009566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(cellSF,NULL,NULL,NULL,&sf_cells));
801af74b616SDave May     if (sf_cells) {
8029566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"[DMLocatePoints_Plex] Re-using existing StarForest node list\n"));
803af74b616SDave May       cells = (PetscSFNode*)sf_cells;
804af74b616SDave May       reuse = PETSC_TRUE;
805af74b616SDave May     } else {
8069566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"[DMLocatePoints_Plex] Creating and initializing new StarForest node list\n"));
8079566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numPoints, &cells));
808af74b616SDave May       /* initialize cells if created */
809af74b616SDave May       for (p=0; p<numPoints; p++) {
810af74b616SDave May         cells[p].rank  = 0;
811af74b616SDave May         cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
812af74b616SDave May       }
813af74b616SDave May     }
814af74b616SDave May   }
8159cb35068SDave May   /* define domain bounding box */
8169cb35068SDave May   {
8179cb35068SDave May     Vec coorglobal;
8189cb35068SDave May 
8199566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinates(dm,&coorglobal));
8209566063dSJacob Faibussowitsch     PetscCall(VecStrideMaxAll(coorglobal,NULL,gmax));
8219566063dSJacob Faibussowitsch     PetscCall(VecStrideMinAll(coorglobal,NULL,gmin));
8229cb35068SDave May   }
823953fc75cSMatthew G. Knepley   if (hash) {
8249566063dSJacob Faibussowitsch     if (!mesh->lbox) {PetscCall(PetscInfo(dm, "Initializing grid hashing"));PetscCall(DMPlexComputeGridHash_Internal(dm, &mesh->lbox));}
825cafe43deSMatthew G. Knepley     /* Designate the local box for each point */
826cafe43deSMatthew G. Knepley     /* Send points to correct process */
827cafe43deSMatthew G. Knepley     /* Search cells that lie in each subbox */
828cafe43deSMatthew G. Knepley     /*   Should we bin points before doing search? */
8299566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(mesh->lbox->cells, &boxCells));
830953fc75cSMatthew G. Knepley   }
8313a93e3b7SToby Isaac   for (p = 0, numFound = 0; p < numPoints; ++p) {
832ccd2543fSMatthew G Knepley     const PetscScalar *point = &a[p*bs];
833e56f9228SJed Brown     PetscInt           dbin[3] = {-1,-1,-1}, bin, cell = -1, cellOffset;
8349cb35068SDave May     PetscBool          point_outside_domain = PETSC_FALSE;
835ccd2543fSMatthew G Knepley 
8369cb35068SDave May     /* check bounding box of domain */
8379cb35068SDave May     for (d=0; d<dim; d++) {
838a5f152d1SDave May       if (PetscRealPart(point[d]) < gmin[d]) { point_outside_domain = PETSC_TRUE; break; }
839a5f152d1SDave May       if (PetscRealPart(point[d]) > gmax[d]) { point_outside_domain = PETSC_TRUE; break; }
8409cb35068SDave May     }
8419cb35068SDave May     if (point_outside_domain) {
842e9b685f5SMatthew G. Knepley       cells[p].rank = 0;
843e9b685f5SMatthew G. Knepley       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
8449cb35068SDave May       terminating_query_type[0]++;
8459cb35068SDave May       continue;
8469cb35068SDave May     }
847ccd2543fSMatthew G Knepley 
848af74b616SDave May     /* check initial values in cells[].index - abort early if found */
849af74b616SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
850af74b616SDave May       c = cells[p].index;
8513a93e3b7SToby Isaac       cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND;
8529566063dSJacob Faibussowitsch       PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
853af74b616SDave May       if (cell >= 0) {
854af74b616SDave May         cells[p].rank = 0;
855af74b616SDave May         cells[p].index = cell;
856af74b616SDave May         numFound++;
857af74b616SDave May       }
858af74b616SDave May     }
8599cb35068SDave May     if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) {
8609cb35068SDave May       terminating_query_type[1]++;
8619cb35068SDave May       continue;
8629cb35068SDave May     }
863af74b616SDave May 
864953fc75cSMatthew G. Knepley     if (hash) {
865af74b616SDave May       PetscBool found_box;
866af74b616SDave May 
86763a3b9bcSJacob 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])));
868af74b616SDave May       /* allow for case that point is outside box - abort early */
8699566063dSJacob Faibussowitsch       PetscCall(PetscGridHashGetEnclosingBoxQuery(mesh->lbox, 1, point, dbin, &bin,&found_box));
870af74b616SDave May       if (found_box) {
87163a3b9bcSJacob 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]));
872cafe43deSMatthew G. Knepley         /* TODO Lay an interface over this so we can switch between Section (dense) and Label (sparse) */
8739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
8749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
875cafe43deSMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
87663a3b9bcSJacob Faibussowitsch           if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    Checking for point in cell %" PetscInt_FMT "\n", boxCells[c]));
8779566063dSJacob Faibussowitsch           PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, boxCells[c], &cell));
8783a93e3b7SToby Isaac           if (cell >= 0) {
87963a3b9bcSJacob Faibussowitsch             if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "      FOUND in cell %" PetscInt_FMT "\n", cell));
8803a93e3b7SToby Isaac             cells[p].rank = 0;
8813a93e3b7SToby Isaac             cells[p].index = cell;
8823a93e3b7SToby Isaac             numFound++;
8839cb35068SDave May             terminating_query_type[2]++;
8843a93e3b7SToby Isaac             break;
885ccd2543fSMatthew G Knepley           }
8863a93e3b7SToby Isaac         }
887af74b616SDave May       }
888953fc75cSMatthew G. Knepley     } else {
889953fc75cSMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
8909566063dSJacob Faibussowitsch         PetscCall(DMPlexLocatePoint_Internal(dm, dim, point, c, &cell));
8913a93e3b7SToby Isaac         if (cell >= 0) {
8923a93e3b7SToby Isaac           cells[p].rank = 0;
8933a93e3b7SToby Isaac           cells[p].index = cell;
8943a93e3b7SToby Isaac           numFound++;
8959cb35068SDave May           terminating_query_type[2]++;
8963a93e3b7SToby Isaac           break;
897953fc75cSMatthew G. Knepley         }
898953fc75cSMatthew G. Knepley       }
8993a93e3b7SToby Isaac     }
900ccd2543fSMatthew G Knepley   }
9019566063dSJacob Faibussowitsch   if (hash) PetscCall(ISRestoreIndices(mesh->lbox->cells, &boxCells));
90262a38674SMatthew G. Knepley   if (ltype == DM_POINTLOCATION_NEAREST && hash && numFound < numPoints) {
90362a38674SMatthew G. Knepley     for (p = 0; p < numPoints; p++) {
90462a38674SMatthew G. Knepley       const PetscScalar *point = &a[p*bs];
905d92c4b9fSToby Isaac       PetscReal          cpoint[3], diff[3], best[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}, dist, distMax = PETSC_MAX_REAL;
906d92c4b9fSToby Isaac       PetscInt           dbin[3] = {-1,-1,-1}, bin, cellOffset, d, bestc = -1;
90762a38674SMatthew G. Knepley 
908e9b685f5SMatthew G. Knepley       if (cells[p].index < 0) {
9099566063dSJacob Faibussowitsch         PetscCall(PetscGridHashGetEnclosingBox(mesh->lbox, 1, point, dbin, &bin));
9109566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells));
9119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset));
91262a38674SMatthew G. Knepley         for (c = cellOffset; c < cellOffset + numCells; ++c) {
9139566063dSJacob Faibussowitsch           PetscCall(DMPlexClosestPoint_Internal(dm, dim, point, boxCells[c], cpoint));
914b716b415SMatthew G. Knepley           for (d = 0; d < dim; ++d) diff[d] = cpoint[d] - PetscRealPart(point[d]);
91562a38674SMatthew G. Knepley           dist = DMPlex_NormD_Internal(dim, diff);
91662a38674SMatthew G. Knepley           if (dist < distMax) {
917d92c4b9fSToby Isaac             for (d = 0; d < dim; ++d) best[d] = cpoint[d];
918d92c4b9fSToby Isaac             bestc = boxCells[c];
91962a38674SMatthew G. Knepley             distMax = dist;
92062a38674SMatthew G. Knepley           }
92162a38674SMatthew G. Knepley         }
922d92c4b9fSToby Isaac         if (distMax < PETSC_MAX_REAL) {
923d92c4b9fSToby Isaac           ++numFound;
924d92c4b9fSToby Isaac           cells[p].rank  = 0;
925d92c4b9fSToby Isaac           cells[p].index = bestc;
926d92c4b9fSToby Isaac           for (d = 0; d < dim; ++d) a[p*bs+d] = best[d];
927d92c4b9fSToby Isaac         }
92862a38674SMatthew G. Knepley       }
92962a38674SMatthew G. Knepley     }
93062a38674SMatthew G. Knepley   }
93162a38674SMatthew G. Knepley   /* This code is only be relevant when interfaced to parallel point location */
932cafe43deSMatthew G. Knepley   /* Check for highest numbered proc that claims a point (do we care?) */
9332d1fa6caSMatthew G. Knepley   if (ltype == DM_POINTLOCATION_REMOVE && numFound < numPoints) {
9349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFound,&found));
9353a93e3b7SToby Isaac     for (p = 0, numFound = 0; p < numPoints; p++) {
9363a93e3b7SToby Isaac       if (cells[p].rank >= 0 && cells[p].index >= 0) {
9373a93e3b7SToby Isaac         if (numFound < p) {
9383a93e3b7SToby Isaac           cells[numFound] = cells[p];
9393a93e3b7SToby Isaac         }
9403a93e3b7SToby Isaac         found[numFound++] = p;
9413a93e3b7SToby Isaac       }
9423a93e3b7SToby Isaac     }
9433a93e3b7SToby Isaac   }
9449566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(v, &a));
945af74b616SDave May   if (!reuse) {
9469566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(cellSF, cEnd - cStart, numFound, found, PETSC_OWN_POINTER, cells, PETSC_OWN_POINTER));
947af74b616SDave May   }
9489566063dSJacob Faibussowitsch   PetscCall(PetscTime(&t1));
9499cb35068SDave May   if (hash) {
95063a3b9bcSJacob 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]));
9519cb35068SDave May   } else {
95263a3b9bcSJacob 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]));
9539cb35068SDave May   }
95463a3b9bcSJacob 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))));
9559566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_LocatePoints,0,0,0,0));
956ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
957ccd2543fSMatthew G Knepley }
958ccd2543fSMatthew G Knepley 
959741bfc07SMatthew G. Knepley /*@C
960741bfc07SMatthew G. Knepley   DMPlexComputeProjection2Dto1D - Rewrite coordinates to be the 1D projection of the 2D coordinates
961741bfc07SMatthew G. Knepley 
962741bfc07SMatthew G. Knepley   Not collective
963741bfc07SMatthew G. Knepley 
9646b867d5aSJose E. Roman   Input/Output Parameter:
9656b867d5aSJose E. Roman . coords - The coordinates of a segment, on output the new y-coordinate, and 0 for x
966741bfc07SMatthew G. Knepley 
9676b867d5aSJose E. Roman   Output Parameter:
9686b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
969741bfc07SMatthew G. Knepley 
970741bfc07SMatthew G. Knepley   Level: developer
971741bfc07SMatthew G. Knepley 
972db781477SPatrick Sanan .seealso: `DMPlexComputeProjection3Dto1D()`, `DMPlexComputeProjection3Dto2D()`
973741bfc07SMatthew G. Knepley @*/
974741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection2Dto1D(PetscScalar coords[], PetscReal R[])
97517fe8556SMatthew G. Knepley {
97617fe8556SMatthew G. Knepley   const PetscReal x = PetscRealPart(coords[2] - coords[0]);
97717fe8556SMatthew G. Knepley   const PetscReal y = PetscRealPart(coords[3] - coords[1]);
9788b49ba18SBarry Smith   const PetscReal r = PetscSqrtReal(x*x + y*y), c = x/r, s = y/r;
97917fe8556SMatthew G. Knepley 
98017fe8556SMatthew G. Knepley   PetscFunctionBegin;
9811c99cf0cSGeoffrey Irving   R[0] = c; R[1] = -s;
9821c99cf0cSGeoffrey Irving   R[2] = s; R[3] =  c;
98317fe8556SMatthew G. Knepley   coords[0] = 0.0;
9847f07f362SMatthew G. Knepley   coords[1] = r;
98517fe8556SMatthew G. Knepley   PetscFunctionReturn(0);
98617fe8556SMatthew G. Knepley }
98717fe8556SMatthew G. Knepley 
988741bfc07SMatthew G. Knepley /*@C
989741bfc07SMatthew G. Knepley   DMPlexComputeProjection3Dto1D - Rewrite coordinates to be the 1D projection of the 3D coordinates
99028dbe442SToby Isaac 
991741bfc07SMatthew G. Knepley   Not collective
99228dbe442SToby Isaac 
9936b867d5aSJose E. Roman   Input/Output Parameter:
9946b867d5aSJose E. Roman . coords - The coordinates of a segment; on output, the new y-coordinate, and 0 for x and z
995741bfc07SMatthew G. Knepley 
9966b867d5aSJose E. Roman   Output Parameter:
9976b867d5aSJose E. Roman . R - The rotation which accomplishes the projection
998741bfc07SMatthew G. Knepley 
999741bfc07SMatthew 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
1000741bfc07SMatthew G. Knepley 
1001741bfc07SMatthew G. Knepley   Level: developer
1002741bfc07SMatthew G. Knepley 
1003db781477SPatrick Sanan .seealso: `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto2D()`
1004741bfc07SMatthew G. Knepley @*/
1005741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection3Dto1D(PetscScalar coords[], PetscReal R[])
100628dbe442SToby Isaac {
100728dbe442SToby Isaac   PetscReal      x    = PetscRealPart(coords[3] - coords[0]);
100828dbe442SToby Isaac   PetscReal      y    = PetscRealPart(coords[4] - coords[1]);
100928dbe442SToby Isaac   PetscReal      z    = PetscRealPart(coords[5] - coords[2]);
101028dbe442SToby Isaac   PetscReal      r    = PetscSqrtReal(x*x + y*y + z*z);
101128dbe442SToby Isaac   PetscReal      rinv = 1. / r;
101228dbe442SToby Isaac   PetscFunctionBegin;
101328dbe442SToby Isaac 
101428dbe442SToby Isaac   x *= rinv; y *= rinv; z *= rinv;
101528dbe442SToby Isaac   if (x > 0.) {
101628dbe442SToby Isaac     PetscReal inv1pX   = 1./ (1. + x);
101728dbe442SToby Isaac 
101828dbe442SToby Isaac     R[0] = x; R[1] = -y;              R[2] = -z;
101928dbe442SToby Isaac     R[3] = y; R[4] = 1. - y*y*inv1pX; R[5] =     -y*z*inv1pX;
102028dbe442SToby Isaac     R[6] = z; R[7] =     -y*z*inv1pX; R[8] = 1. - z*z*inv1pX;
102128dbe442SToby Isaac   }
102228dbe442SToby Isaac   else {
102328dbe442SToby Isaac     PetscReal inv1mX   = 1./ (1. - x);
102428dbe442SToby Isaac 
102528dbe442SToby Isaac     R[0] = x; R[1] = z;               R[2] = y;
102628dbe442SToby Isaac     R[3] = y; R[4] =     -y*z*inv1mX; R[5] = 1. - y*y*inv1mX;
102728dbe442SToby Isaac     R[6] = z; R[7] = 1. - z*z*inv1mX; R[8] =     -y*z*inv1mX;
102828dbe442SToby Isaac   }
102928dbe442SToby Isaac   coords[0] = 0.0;
103028dbe442SToby Isaac   coords[1] = r;
103128dbe442SToby Isaac   PetscFunctionReturn(0);
103228dbe442SToby Isaac }
103328dbe442SToby Isaac 
1034741bfc07SMatthew G. Knepley /*@
1035c871b86eSJed Brown   DMPlexComputeProjection3Dto2D - Rewrite coordinates of 3 or more coplanar 3D points to a common 2D basis for the
1036c871b86eSJed Brown     plane.  The normal is defined by positive orientation of the first 3 points.
1037741bfc07SMatthew G. Knepley 
1038741bfc07SMatthew G. Knepley   Not collective
1039741bfc07SMatthew G. Knepley 
1040741bfc07SMatthew G. Knepley   Input Parameter:
10416b867d5aSJose E. Roman . coordSize - Length of coordinate array (3x number of points); must be at least 9 (3 points)
1042741bfc07SMatthew G. Knepley 
10436b867d5aSJose E. Roman   Input/Output Parameter:
10446b867d5aSJose E. Roman . coords - The interlaced coordinates of each coplanar 3D point; on output the first
10456b867d5aSJose E. Roman            2*coordSize/3 entries contain interlaced 2D points, with the rest undefined
10466b867d5aSJose E. Roman 
10476b867d5aSJose E. Roman   Output Parameter:
10486b867d5aSJose 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.
1049741bfc07SMatthew G. Knepley 
1050741bfc07SMatthew G. Knepley   Level: developer
1051741bfc07SMatthew G. Knepley 
1052db781477SPatrick Sanan .seealso: `DMPlexComputeProjection2Dto1D()`, `DMPlexComputeProjection3Dto1D()`
1053741bfc07SMatthew G. Knepley @*/
1054741bfc07SMatthew G. Knepley PetscErrorCode DMPlexComputeProjection3Dto2D(PetscInt coordSize, PetscScalar coords[], PetscReal R[])
1055ccd2543fSMatthew G Knepley {
1056c871b86eSJed Brown   PetscReal x1[3], x2[3], n[3], c[3], norm;
1057ccd2543fSMatthew G Knepley   const PetscInt dim = 3;
1058c871b86eSJed Brown   PetscInt       d, p;
1059ccd2543fSMatthew G Knepley 
1060ccd2543fSMatthew G Knepley   PetscFunctionBegin;
1061ccd2543fSMatthew G Knepley   /* 0) Calculate normal vector */
1062ccd2543fSMatthew G Knepley   for (d = 0; d < dim; ++d) {
10631ee9d5ecSMatthew G. Knepley     x1[d] = PetscRealPart(coords[1*dim+d] - coords[0*dim+d]);
10641ee9d5ecSMatthew G. Knepley     x2[d] = PetscRealPart(coords[2*dim+d] - coords[0*dim+d]);
1065ccd2543fSMatthew G Knepley   }
1066c871b86eSJed Brown   // n = x1 \otimes x2
1067ccd2543fSMatthew G Knepley   n[0] = x1[1]*x2[2] - x1[2]*x2[1];
1068ccd2543fSMatthew G Knepley   n[1] = x1[2]*x2[0] - x1[0]*x2[2];
1069ccd2543fSMatthew G Knepley   n[2] = x1[0]*x2[1] - x1[1]*x2[0];
10708b49ba18SBarry Smith   norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
1071c871b86eSJed Brown   for (d = 0; d < dim; d++) n[d] /= norm;
1072c871b86eSJed Brown   norm = PetscSqrtReal(x1[0] * x1[0] + x1[1] * x1[1] + x1[2] * x1[2]);
1073c871b86eSJed Brown   for (d = 0; d < dim; d++) x1[d] /= norm;
1074c871b86eSJed Brown   // x2 = n \otimes x1
1075c871b86eSJed Brown   x2[0] = n[1] * x1[2] - n[2] * x1[1];
1076c871b86eSJed Brown   x2[1] = n[2] * x1[0] - n[0] * x1[2];
1077c871b86eSJed Brown   x2[2] = n[0] * x1[1] - n[1] * x1[0];
1078c871b86eSJed Brown   for (d=0; d<dim; d++) {
1079c871b86eSJed Brown     R[d * dim + 0] = x1[d];
1080c871b86eSJed Brown     R[d * dim + 1] = x2[d];
1081c871b86eSJed Brown     R[d * dim + 2] = n[d];
1082c871b86eSJed Brown     c[d] = PetscRealPart(coords[0*dim + d]);
108373868372SMatthew G. Knepley   }
1084c871b86eSJed Brown   for (p=0; p<coordSize/dim; p++) {
1085c871b86eSJed Brown     PetscReal y[3];
1086c871b86eSJed Brown     for (d=0; d<dim; d++) y[d] = PetscRealPart(coords[p*dim + d]) - c[d];
1087c871b86eSJed 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];
10887f07f362SMatthew G. Knepley   }
1089ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1090ccd2543fSMatthew G Knepley }
1091ccd2543fSMatthew G Knepley 
10926322fe33SJed Brown PETSC_UNUSED
10939fbee547SJacob Faibussowitsch static inline void Volume_Triangle_Internal(PetscReal *vol, PetscReal coords[])
1094834e62ceSMatthew G. Knepley {
1095834e62ceSMatthew G. Knepley   /* Signed volume is 1/2 the determinant
1096834e62ceSMatthew G. Knepley 
1097834e62ceSMatthew G. Knepley    |  1  1  1 |
1098834e62ceSMatthew G. Knepley    | x0 x1 x2 |
1099834e62ceSMatthew G. Knepley    | y0 y1 y2 |
1100834e62ceSMatthew G. Knepley 
1101834e62ceSMatthew G. Knepley      but if x0,y0 is the origin, we have
1102834e62ceSMatthew G. Knepley 
1103834e62ceSMatthew G. Knepley    | x1 x2 |
1104834e62ceSMatthew G. Knepley    | y1 y2 |
1105834e62ceSMatthew G. Knepley   */
1106834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[2] - coords[0], y1 = coords[3] - coords[1];
1107834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[4] - coords[0], y2 = coords[5] - coords[1];
1108834e62ceSMatthew G. Knepley   PetscReal       M[4], detM;
1109834e62ceSMatthew G. Knepley   M[0] = x1; M[1] = x2;
111086623015SMatthew G. Knepley   M[2] = y1; M[3] = y2;
1111923591dfSMatthew G. Knepley   DMPlex_Det2D_Internal(&detM, M);
1112834e62ceSMatthew G. Knepley   *vol = 0.5*detM;
11133bc0b13bSBarry Smith   (void)PetscLogFlops(5.0);
1114834e62ceSMatthew G. Knepley }
1115834e62ceSMatthew G. Knepley 
11166322fe33SJed Brown PETSC_UNUSED
11179fbee547SJacob Faibussowitsch static inline void Volume_Tetrahedron_Internal(PetscReal *vol, PetscReal coords[])
1118834e62ceSMatthew G. Knepley {
1119834e62ceSMatthew G. Knepley   /* Signed volume is 1/6th of the determinant
1120834e62ceSMatthew G. Knepley 
1121834e62ceSMatthew G. Knepley    |  1  1  1  1 |
1122834e62ceSMatthew G. Knepley    | x0 x1 x2 x3 |
1123834e62ceSMatthew G. Knepley    | y0 y1 y2 y3 |
1124834e62ceSMatthew G. Knepley    | z0 z1 z2 z3 |
1125834e62ceSMatthew G. Knepley 
1126834e62ceSMatthew G. Knepley      but if x0,y0,z0 is the origin, we have
1127834e62ceSMatthew G. Knepley 
1128834e62ceSMatthew G. Knepley    | x1 x2 x3 |
1129834e62ceSMatthew G. Knepley    | y1 y2 y3 |
1130834e62ceSMatthew G. Knepley    | z1 z2 z3 |
1131834e62ceSMatthew G. Knepley   */
1132834e62ceSMatthew G. Knepley   const PetscReal x1 = coords[3] - coords[0], y1 = coords[4]  - coords[1], z1 = coords[5]  - coords[2];
1133834e62ceSMatthew G. Knepley   const PetscReal x2 = coords[6] - coords[0], y2 = coords[7]  - coords[1], z2 = coords[8]  - coords[2];
1134834e62ceSMatthew G. Knepley   const PetscReal x3 = coords[9] - coords[0], y3 = coords[10] - coords[1], z3 = coords[11] - coords[2];
11350a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.);
1136834e62ceSMatthew G. Knepley   PetscReal       M[9], detM;
1137834e62ceSMatthew G. Knepley   M[0] = x1; M[1] = x2; M[2] = x3;
1138834e62ceSMatthew G. Knepley   M[3] = y1; M[4] = y2; M[5] = y3;
1139834e62ceSMatthew G. Knepley   M[6] = z1; M[7] = z2; M[8] = z3;
1140923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(&detM, M);
11410a3da2c2SToby Isaac   *vol = -onesixth*detM;
11423bc0b13bSBarry Smith   (void)PetscLogFlops(10.0);
1143834e62ceSMatthew G. Knepley }
1144834e62ceSMatthew G. Knepley 
11459fbee547SJacob Faibussowitsch static inline void Volume_Tetrahedron_Origin_Internal(PetscReal *vol, PetscReal coords[])
11460ec8681fSMatthew G. Knepley {
11470a3da2c2SToby Isaac   const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.);
1148923591dfSMatthew G. Knepley   DMPlex_Det3D_Internal(vol, coords);
11490a3da2c2SToby Isaac   *vol *= -onesixth;
11500ec8681fSMatthew G. Knepley }
11510ec8681fSMatthew G. Knepley 
1152cb92db44SToby Isaac static PetscErrorCode DMPlexComputePointGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1153cb92db44SToby Isaac {
1154cb92db44SToby Isaac   PetscSection   coordSection;
1155cb92db44SToby Isaac   Vec            coordinates;
1156cb92db44SToby Isaac   const PetscScalar *coords;
1157cb92db44SToby Isaac   PetscInt       dim, d, off;
1158cb92db44SToby Isaac 
1159cb92db44SToby Isaac   PetscFunctionBegin;
11609566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
11619566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
11629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(coordSection,e,&dim));
1163cb92db44SToby Isaac   if (!dim) PetscFunctionReturn(0);
11649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(coordSection,e,&off));
11659566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates,&coords));
1166cb92db44SToby Isaac   if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[off + d]);}
11679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates,&coords));
1168cb92db44SToby Isaac   *detJ = 1.;
1169cb92db44SToby Isaac   if (J) {
1170cb92db44SToby Isaac     for (d = 0; d < dim * dim; d++) J[d] = 0.;
1171cb92db44SToby Isaac     for (d = 0; d < dim; d++) J[d * dim + d] = 1.;
1172cb92db44SToby Isaac     if (invJ) {
1173cb92db44SToby Isaac       for (d = 0; d < dim * dim; d++) invJ[d] = 0.;
1174cb92db44SToby Isaac       for (d = 0; d < dim; d++) invJ[d * dim + d] = 1.;
1175cb92db44SToby Isaac     }
1176cb92db44SToby Isaac   }
1177cb92db44SToby Isaac   PetscFunctionReturn(0);
1178cb92db44SToby Isaac }
1179cb92db44SToby Isaac 
11806858538eSMatthew G. Knepley /*@C
11816858538eSMatthew G. Knepley   DMPlexGetCellCoordinates - Get coordinates for a cell, taking into account periodicity
11826858538eSMatthew G. Knepley 
11836858538eSMatthew G. Knepley   Not collective
11846858538eSMatthew G. Knepley 
11856858538eSMatthew G. Knepley   Input Parameters:
11866858538eSMatthew G. Knepley + dm   - The DM
11876858538eSMatthew G. Knepley - cell - The cell number
11886858538eSMatthew G. Knepley 
11896858538eSMatthew G. Knepley   Output Parameters:
11906858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
11916858538eSMatthew G. Knepley . Nc     - The number of coordinates
11926858538eSMatthew G. Knepley . array  - The coordinate array
11936858538eSMatthew G. Knepley - coords - The cell coordinates
11946858538eSMatthew G. Knepley 
11956858538eSMatthew G. Knepley   Level: developer
11966858538eSMatthew G. Knepley 
11976858538eSMatthew G. Knepley .seealso: DMPlexRestoreCellCoordinates(), DMGetCoordinatesLocal(), DMGetCellCoordinatesLocal()
11986858538eSMatthew G. Knepley @*/
11996858538eSMatthew G. Knepley PetscErrorCode DMPlexGetCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
12006858538eSMatthew G. Knepley {
12016858538eSMatthew G. Knepley   DM                 cdm;
12026858538eSMatthew G. Knepley   Vec                coordinates;
12036858538eSMatthew G. Knepley   PetscSection       cs;
12046858538eSMatthew G. Knepley   const PetscScalar *ccoords;
12056858538eSMatthew G. Knepley   PetscInt           pStart, pEnd;
12066858538eSMatthew G. Knepley 
12076858538eSMatthew G. Knepley   PetscFunctionBeginHot;
12086858538eSMatthew G. Knepley   *isDG   = PETSC_FALSE;
12096858538eSMatthew G. Knepley   *Nc     = 0;
12106858538eSMatthew G. Knepley   *array  = NULL;
12116858538eSMatthew G. Knepley   *coords = NULL;
12126858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12136858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateSection(dm, &cs));
12146858538eSMatthew G. Knepley   if (!cs) goto cg;
12156858538eSMatthew G. Knepley   /* Check that the cell exists in the cellwise section */
12166858538eSMatthew G. Knepley   PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd));
12176858538eSMatthew G. Knepley   if (cell < pStart || cell >= pEnd) goto cg;
12186858538eSMatthew G. Knepley   /* Check for cellwise coordinates for this cell */
12196858538eSMatthew G. Knepley   PetscCall(PetscSectionGetDof(cs, cell, Nc));
12206858538eSMatthew G. Knepley   if (!*Nc) goto cg;
12216858538eSMatthew G. Knepley   /* Check for cellwise coordinates */
12226858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocalNoncollective(dm, &coordinates));
12236858538eSMatthew G. Knepley   if (!coordinates) goto cg;
12246858538eSMatthew G. Knepley   /* Get cellwise coordinates */
12256858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12266858538eSMatthew G. Knepley   PetscCall(VecGetArrayRead(coordinates, array));
12276858538eSMatthew G. Knepley   PetscCall(DMPlexPointLocalRead(cdm, cell, *array, &ccoords));
12286858538eSMatthew G. Knepley   PetscCall(DMGetWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
12296858538eSMatthew G. Knepley   PetscCall(PetscArraycpy(*coords, ccoords, *Nc));
12306858538eSMatthew G. Knepley   PetscCall(VecRestoreArrayRead(coordinates, array));
12316858538eSMatthew G. Knepley   *isDG = PETSC_TRUE;
12326858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12336858538eSMatthew G. Knepley cg:
12346858538eSMatthew G. Knepley   /* Use continuous coordinates */
12356858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
12366858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &cs));
12376858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
12386858538eSMatthew G. Knepley   PetscCall(DMPlexVecGetClosure(cdm, cs, coordinates, cell, Nc, coords));
12396858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12406858538eSMatthew G. Knepley }
12416858538eSMatthew G. Knepley 
12426858538eSMatthew G. Knepley /*@C
12436858538eSMatthew G. Knepley   DMPlexRestoreCellCoordinates - Get coordinates for a cell, taking into account periodicity
12446858538eSMatthew G. Knepley 
12456858538eSMatthew G. Knepley   Not collective
12466858538eSMatthew G. Knepley 
12476858538eSMatthew G. Knepley   Input Parameters:
12486858538eSMatthew G. Knepley + dm   - The DM
12496858538eSMatthew G. Knepley - cell - The cell number
12506858538eSMatthew G. Knepley 
12516858538eSMatthew G. Knepley   Output Parameters:
12526858538eSMatthew G. Knepley + isDG   - Using cellwise coordinates
12536858538eSMatthew G. Knepley . Nc     - The number of coordinates
12546858538eSMatthew G. Knepley . array  - The coordinate array
12556858538eSMatthew G. Knepley - coords - The cell coordinates
12566858538eSMatthew G. Knepley 
12576858538eSMatthew G. Knepley   Level: developer
12586858538eSMatthew G. Knepley 
12596858538eSMatthew G. Knepley .seealso: DMPlexGetCellCoordinates(), DMGetCoordinatesLocal(), DMGetCellCoordinatesLocal()
12606858538eSMatthew G. Knepley @*/
12616858538eSMatthew G. Knepley PetscErrorCode DMPlexRestoreCellCoordinates(DM dm, PetscInt cell, PetscBool *isDG, PetscInt *Nc, const PetscScalar *array[], PetscScalar *coords[])
12626858538eSMatthew G. Knepley {
12636858538eSMatthew G. Knepley   DM           cdm;
12646858538eSMatthew G. Knepley   PetscSection cs;
12656858538eSMatthew G. Knepley   Vec          coordinates;
12666858538eSMatthew G. Knepley 
12676858538eSMatthew G. Knepley   PetscFunctionBeginHot;
12686858538eSMatthew G. Knepley   if (*isDG) {
12696858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12706858538eSMatthew G. Knepley     PetscCall(DMRestoreWorkArray(cdm, *Nc, MPIU_SCALAR, coords));
12716858538eSMatthew G. Knepley   } else {
12726858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
12736858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(dm, &cs));
12746858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalNoncollective(dm, &coordinates));
12756858538eSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(cdm, cs, coordinates, cell, Nc, (PetscScalar **) coords));
12766858538eSMatthew G. Knepley   }
12776858538eSMatthew G. Knepley   PetscFunctionReturn(0);
12786858538eSMatthew G. Knepley }
12796858538eSMatthew G. Knepley 
128017fe8556SMatthew G. Knepley static PetscErrorCode DMPlexComputeLineGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
128117fe8556SMatthew G. Knepley {
12826858538eSMatthew G. Knepley   const PetscScalar *array;
1283a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
12846858538eSMatthew G. Knepley   PetscInt           numCoords, d;
12856858538eSMatthew G. Knepley   PetscBool          isDG;
128617fe8556SMatthew G. Knepley 
128717fe8556SMatthew G. Knepley   PetscFunctionBegin;
12886858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
128908401ef6SPierre Jolivet   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
12907f07f362SMatthew G. Knepley   *detJ = 0.0;
129128dbe442SToby Isaac   if (numCoords == 6) {
129228dbe442SToby Isaac     const PetscInt dim = 3;
129328dbe442SToby Isaac     PetscReal      R[9], J0;
129428dbe442SToby Isaac 
129528dbe442SToby Isaac     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
12969566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto1D(coords, R));
129728dbe442SToby Isaac     if (J) {
129828dbe442SToby Isaac       J0   = 0.5*PetscRealPart(coords[1]);
129928dbe442SToby Isaac       J[0] = R[0]*J0; J[1] = R[1]; J[2] = R[2];
130028dbe442SToby Isaac       J[3] = R[3]*J0; J[4] = R[4]; J[5] = R[5];
130128dbe442SToby Isaac       J[6] = R[6]*J0; J[7] = R[7]; J[8] = R[8];
130228dbe442SToby Isaac       DMPlex_Det3D_Internal(detJ, J);
130328dbe442SToby Isaac       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
1304adac9986SMatthew G. Knepley     }
130528dbe442SToby Isaac   } else if (numCoords == 4) {
13067f07f362SMatthew G. Knepley     const PetscInt dim = 2;
13077f07f362SMatthew G. Knepley     PetscReal      R[4], J0;
13087f07f362SMatthew G. Knepley 
13097f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13109566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection2Dto1D(coords, R));
131117fe8556SMatthew G. Knepley     if (J) {
13127f07f362SMatthew G. Knepley       J0   = 0.5*PetscRealPart(coords[1]);
13137f07f362SMatthew G. Knepley       J[0] = R[0]*J0; J[1] = R[1];
13147f07f362SMatthew G. Knepley       J[2] = R[2]*J0; J[3] = R[3];
1315923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1316923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
1317adac9986SMatthew G. Knepley     }
13187f07f362SMatthew G. Knepley   } else if (numCoords == 2) {
13197f07f362SMatthew G. Knepley     const PetscInt dim = 1;
13207f07f362SMatthew G. Knepley 
13217f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13227f07f362SMatthew G. Knepley     if (J) {
13237f07f362SMatthew G. Knepley       J[0]  = 0.5*(PetscRealPart(coords[1]) - PetscRealPart(coords[0]));
132417fe8556SMatthew G. Knepley       *detJ = J[0];
13259566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(2.0));
13269566063dSJacob Faibussowitsch       if (invJ) {invJ[0] = 1.0/J[0]; PetscCall(PetscLogFlops(1.0));}
1327adac9986SMatthew G. Knepley     }
13286858538eSMatthew 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);
13296858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
133017fe8556SMatthew G. Knepley   PetscFunctionReturn(0);
133117fe8556SMatthew G. Knepley }
133217fe8556SMatthew G. Knepley 
1333ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexComputeTriangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1334ccd2543fSMatthew G Knepley {
13356858538eSMatthew G. Knepley   const PetscScalar *array;
1336a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
13376858538eSMatthew G. Knepley   PetscInt           numCoords, d;
13386858538eSMatthew G. Knepley   PetscBool          isDG;
1339ccd2543fSMatthew G Knepley 
1340ccd2543fSMatthew G Knepley   PetscFunctionBegin;
13416858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
13426858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
13437f07f362SMatthew G. Knepley   *detJ = 0.0;
1344ccd2543fSMatthew G Knepley   if (numCoords == 9) {
13457f07f362SMatthew G. Knepley     const PetscInt dim = 3;
13467f07f362SMatthew 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};
13477f07f362SMatthew G. Knepley 
13487f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
13499566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
13507f07f362SMatthew G. Knepley     if (J) {
1351b7ad821dSMatthew G. Knepley       const PetscInt pdim = 2;
1352b7ad821dSMatthew G. Knepley 
1353b7ad821dSMatthew G. Knepley       for (d = 0; d < pdim; d++) {
13546858538eSMatthew G. Knepley         for (PetscInt f = 0; f < pdim; f++) {
1355b7ad821dSMatthew G. Knepley           J0[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*pdim+d]) - PetscRealPart(coords[0*pdim+d]));
1356ccd2543fSMatthew G Knepley         }
13577f07f362SMatthew G. Knepley       }
13589566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1359923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J0);
13607f07f362SMatthew G. Knepley       for (d = 0; d < dim; d++) {
13616858538eSMatthew G. Knepley         for (PetscInt f = 0; f < dim; f++) {
13627f07f362SMatthew G. Knepley           J[d*dim+f] = 0.0;
13636858538eSMatthew G. Knepley           for (PetscInt g = 0; g < dim; g++) {
13647f07f362SMatthew G. Knepley             J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
13657f07f362SMatthew G. Knepley           }
13667f07f362SMatthew G. Knepley         }
13677f07f362SMatthew G. Knepley       }
13689566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
13697f07f362SMatthew G. Knepley     }
1370923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
13717f07f362SMatthew G. Knepley   } else if (numCoords == 6) {
13727f07f362SMatthew G. Knepley     const PetscInt dim = 2;
13737f07f362SMatthew G. Knepley 
13747f07f362SMatthew G. Knepley     if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
1375ccd2543fSMatthew G Knepley     if (J) {
1376ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
13776858538eSMatthew G. Knepley         for (PetscInt f = 0; f < dim; f++) {
1378ccd2543fSMatthew G Knepley           J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
1379ccd2543fSMatthew G Knepley         }
1380ccd2543fSMatthew G Knepley       }
13819566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(8.0));
1382923591dfSMatthew G. Knepley       DMPlex_Det2D_Internal(detJ, J);
1383ccd2543fSMatthew G Knepley     }
1384923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
138563a3b9bcSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this triangle is %" PetscInt_FMT " != 6 or 9", numCoords);
13866858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1387ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1388ccd2543fSMatthew G Knepley }
1389ccd2543fSMatthew G Knepley 
1390412e9a14SMatthew 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)
1391ccd2543fSMatthew G Knepley {
13926858538eSMatthew G. Knepley   const PetscScalar *array;
1393a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
13946858538eSMatthew G. Knepley   PetscInt           numCoords, d;
13956858538eSMatthew G. Knepley   PetscBool          isDG;
1396ccd2543fSMatthew G Knepley 
1397ccd2543fSMatthew G Knepley   PetscFunctionBegin;
13986858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
13996858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1400dfccc68fSToby Isaac   if (!Nq) {
1401412e9a14SMatthew G. Knepley     PetscInt vorder[4] = {0, 1, 2, 3};
1402412e9a14SMatthew G. Knepley 
1403412e9a14SMatthew G. Knepley     if (isTensor) {vorder[2] = 3; vorder[3] = 2;}
14047f07f362SMatthew G. Knepley     *detJ = 0.0;
140599dec3a6SMatthew G. Knepley     if (numCoords == 12) {
140699dec3a6SMatthew G. Knepley       const PetscInt dim = 3;
140799dec3a6SMatthew 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};
140899dec3a6SMatthew G. Knepley 
1409dfccc68fSToby Isaac       if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
14109566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeProjection3Dto2D(numCoords, coords, R));
141199dec3a6SMatthew G. Knepley       if (J) {
141299dec3a6SMatthew G. Knepley         const PetscInt pdim = 2;
141399dec3a6SMatthew G. Knepley 
141499dec3a6SMatthew G. Knepley         for (d = 0; d < pdim; d++) {
1415412e9a14SMatthew G. Knepley           J0[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*pdim+d]) - PetscRealPart(coords[vorder[0]*pdim+d]));
1416412e9a14SMatthew G. Knepley           J0[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[2]*pdim+d]) - PetscRealPart(coords[vorder[1]*pdim+d]));
141799dec3a6SMatthew G. Knepley         }
14189566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1419923591dfSMatthew G. Knepley         DMPlex_Det3D_Internal(detJ, J0);
142099dec3a6SMatthew G. Knepley         for (d = 0; d < dim; d++) {
14216858538eSMatthew G. Knepley           for (PetscInt f = 0; f < dim; f++) {
142299dec3a6SMatthew G. Knepley             J[d*dim+f] = 0.0;
14236858538eSMatthew G. Knepley             for (PetscInt g = 0; g < dim; g++) {
142499dec3a6SMatthew G. Knepley               J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
142599dec3a6SMatthew G. Knepley             }
142699dec3a6SMatthew G. Knepley           }
142799dec3a6SMatthew G. Knepley         }
14289566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(18.0));
142999dec3a6SMatthew G. Knepley       }
1430923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
143171f58de1SToby Isaac     } else if (numCoords == 8) {
143299dec3a6SMatthew G. Knepley       const PetscInt dim = 2;
143399dec3a6SMatthew G. Knepley 
1434dfccc68fSToby Isaac       if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
1435ccd2543fSMatthew G Knepley       if (J) {
1436ccd2543fSMatthew G Knepley         for (d = 0; d < dim; d++) {
1437412e9a14SMatthew G. Knepley           J[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d]));
1438412e9a14SMatthew G. Knepley           J[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[3]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d]));
1439ccd2543fSMatthew G Knepley         }
14409566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(8.0));
1441923591dfSMatthew G. Knepley         DMPlex_Det2D_Internal(detJ, J);
1442ccd2543fSMatthew G Knepley       }
1443923591dfSMatthew G. Knepley       if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);}
144463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1445dfccc68fSToby Isaac   } else {
1446dfccc68fSToby Isaac     const PetscInt Nv = 4;
1447dfccc68fSToby Isaac     const PetscInt dimR = 2;
1448412e9a14SMatthew G. Knepley     PetscInt  zToPlex[4] = {0, 1, 3, 2};
1449dfccc68fSToby Isaac     PetscReal zOrder[12];
1450dfccc68fSToby Isaac     PetscReal zCoeff[12];
1451dfccc68fSToby Isaac     PetscInt  i, j, k, l, dim;
1452dfccc68fSToby Isaac 
1453412e9a14SMatthew G. Knepley     if (isTensor) {zToPlex[2] = 2; zToPlex[3] = 3;}
1454dfccc68fSToby Isaac     if (numCoords == 12) {
1455dfccc68fSToby Isaac       dim = 3;
1456dfccc68fSToby Isaac     } else if (numCoords == 8) {
1457dfccc68fSToby Isaac       dim = 2;
145863a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %" PetscInt_FMT " != 8 or 12", numCoords);
1459dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1460dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1461dfccc68fSToby Isaac 
1462dfccc68fSToby Isaac       for (j = 0; j < dim; j++) {
1463dfccc68fSToby Isaac         zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1464dfccc68fSToby Isaac       }
1465dfccc68fSToby Isaac     }
1466dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
14672df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: (1 \mp xi) (1 \mp eta):
14682df84da0SMatthew G. Knepley            \phi^0 = (1 - xi - eta + xi eta) --> 1      = 1/4 ( \phi^0 + \phi^1 + \phi^2 + \phi^3)
14692df84da0SMatthew G. Knepley            \phi^1 = (1 + xi - eta - xi eta) --> xi     = 1/4 (-\phi^0 + \phi^1 - \phi^2 + \phi^3)
14702df84da0SMatthew G. Knepley            \phi^2 = (1 - xi + eta - xi eta) --> eta    = 1/4 (-\phi^0 - \phi^1 + \phi^2 + \phi^3)
14712df84da0SMatthew G. Knepley            \phi^3 = (1 + xi + eta + xi eta) --> xi eta = 1/4 ( \phi^0 - \phi^1 - \phi^2 + \phi^3)
14722df84da0SMatthew G. Knepley       */
1473dfccc68fSToby Isaac       zCoeff[dim * 0 + j] = 0.25 * (  zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1474dfccc68fSToby Isaac       zCoeff[dim * 1 + j] = 0.25 * (- zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1475dfccc68fSToby Isaac       zCoeff[dim * 2 + j] = 0.25 * (- zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1476dfccc68fSToby Isaac       zCoeff[dim * 3 + j] = 0.25 * (  zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]);
1477dfccc68fSToby Isaac     }
1478dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1479dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1];
1480dfccc68fSToby Isaac 
1481dfccc68fSToby Isaac       if (v) {
1482dfccc68fSToby Isaac         PetscReal extPoint[4];
1483dfccc68fSToby Isaac 
1484dfccc68fSToby Isaac         extPoint[0] = 1.;
1485dfccc68fSToby Isaac         extPoint[1] = xi;
1486dfccc68fSToby Isaac         extPoint[2] = eta;
1487dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1488dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1489dfccc68fSToby Isaac           PetscReal val = 0.;
1490dfccc68fSToby Isaac 
1491dfccc68fSToby Isaac           for (k = 0; k < Nv; k++) {
1492dfccc68fSToby Isaac             val += extPoint[k] * zCoeff[dim * k + j];
1493dfccc68fSToby Isaac           }
1494dfccc68fSToby Isaac           v[i * dim + j] = val;
1495dfccc68fSToby Isaac         }
1496dfccc68fSToby Isaac       }
1497dfccc68fSToby Isaac       if (J) {
1498dfccc68fSToby Isaac         PetscReal extJ[8];
1499dfccc68fSToby Isaac 
1500dfccc68fSToby Isaac         extJ[0] = 0.;
1501dfccc68fSToby Isaac         extJ[1] = 0.;
1502dfccc68fSToby Isaac         extJ[2] = 1.;
1503dfccc68fSToby Isaac         extJ[3] = 0.;
1504dfccc68fSToby Isaac         extJ[4] = 0.;
1505dfccc68fSToby Isaac         extJ[5] = 1.;
1506dfccc68fSToby Isaac         extJ[6] = eta;
1507dfccc68fSToby Isaac         extJ[7] = xi;
1508dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1509dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1510dfccc68fSToby Isaac             PetscReal val = 0.;
1511dfccc68fSToby Isaac 
1512dfccc68fSToby Isaac             for (l = 0; l < Nv; l++) {
1513dfccc68fSToby Isaac               val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1514dfccc68fSToby Isaac             }
1515dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1516dfccc68fSToby Isaac           }
1517dfccc68fSToby Isaac         }
1518dfccc68fSToby Isaac         if (dim == 3) { /* put the cross product in the third component of the Jacobian */
1519dfccc68fSToby Isaac           PetscReal x, y, z;
1520dfccc68fSToby Isaac           PetscReal *iJ = &J[i * dim * dim];
1521dfccc68fSToby Isaac           PetscReal norm;
1522dfccc68fSToby Isaac 
1523dfccc68fSToby Isaac           x = iJ[1 * dim + 0] * iJ[2 * dim + 1] - iJ[1 * dim + 1] * iJ[2 * dim + 0];
1524dfccc68fSToby Isaac           y = iJ[0 * dim + 1] * iJ[2 * dim + 0] - iJ[0 * dim + 0] * iJ[2 * dim + 1];
1525dfccc68fSToby Isaac           z = iJ[0 * dim + 0] * iJ[1 * dim + 1] - iJ[0 * dim + 1] * iJ[1 * dim + 0];
1526dfccc68fSToby Isaac           norm = PetscSqrtReal(x * x + y * y + z * z);
1527dfccc68fSToby Isaac           iJ[2] = x / norm;
1528dfccc68fSToby Isaac           iJ[5] = y / norm;
1529dfccc68fSToby Isaac           iJ[8] = z / norm;
1530dfccc68fSToby Isaac           DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1531dfccc68fSToby Isaac           if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1532dfccc68fSToby Isaac         } else {
1533dfccc68fSToby Isaac           DMPlex_Det2D_Internal(&detJ[i], &J[i * dim * dim]);
1534dfccc68fSToby Isaac           if (invJ) {DMPlex_Invert2D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1535dfccc68fSToby Isaac         }
1536dfccc68fSToby Isaac       }
1537dfccc68fSToby Isaac     }
1538dfccc68fSToby Isaac   }
15396858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1540ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1541ccd2543fSMatthew G Knepley }
1542ccd2543fSMatthew G Knepley 
1543ccd2543fSMatthew G Knepley static PetscErrorCode DMPlexComputeTetrahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1544ccd2543fSMatthew G Knepley {
15456858538eSMatthew G. Knepley   const PetscScalar *array;
1546a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1547ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
15486858538eSMatthew G. Knepley   PetscInt           numCoords, d;
15496858538eSMatthew G. Knepley   PetscBool          isDG;
1550ccd2543fSMatthew G Knepley 
1551ccd2543fSMatthew G Knepley   PetscFunctionBegin;
15526858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
15536858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
15547f07f362SMatthew G. Knepley   *detJ = 0.0;
15557f07f362SMatthew G. Knepley   if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
1556ccd2543fSMatthew G Knepley   if (J) {
1557ccd2543fSMatthew G Knepley     for (d = 0; d < dim; d++) {
1558f0df753eSMatthew G. Knepley       /* I orient with outward face normals */
1559f0df753eSMatthew G. Knepley       J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d]));
1560f0df753eSMatthew G. Knepley       J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
1561f0df753eSMatthew G. Knepley       J[d*dim+2] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
1562ccd2543fSMatthew G Knepley     }
15639566063dSJacob Faibussowitsch     PetscCall(PetscLogFlops(18.0));
1564923591dfSMatthew G. Knepley     DMPlex_Det3D_Internal(detJ, J);
1565ccd2543fSMatthew G Knepley   }
1566923591dfSMatthew G. Knepley   if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
15676858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1568ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1569ccd2543fSMatthew G Knepley }
1570ccd2543fSMatthew G Knepley 
1571dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeHexahedronGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
1572ccd2543fSMatthew G Knepley {
15736858538eSMatthew G. Knepley   const PetscScalar *array;
1574a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
1575ccd2543fSMatthew G Knepley   const PetscInt     dim    = 3;
15766858538eSMatthew G. Knepley   PetscInt           numCoords, d;
15776858538eSMatthew G. Knepley   PetscBool          isDG;
1578ccd2543fSMatthew G Knepley 
1579ccd2543fSMatthew G Knepley   PetscFunctionBegin;
15806858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
15816858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
1582dfccc68fSToby Isaac   if (!Nq) {
15837f07f362SMatthew G. Knepley     *detJ = 0.0;
1584dfccc68fSToby Isaac     if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
1585ccd2543fSMatthew G Knepley     if (J) {
1586ccd2543fSMatthew G Knepley       for (d = 0; d < dim; d++) {
1587f0df753eSMatthew G. Knepley         J[d*dim+0] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
1588f0df753eSMatthew G. Knepley         J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
1589f0df753eSMatthew G. Knepley         J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d]));
1590ccd2543fSMatthew G Knepley       }
15919566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
1592923591dfSMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
1593ccd2543fSMatthew G Knepley     }
1594923591dfSMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
1595dfccc68fSToby Isaac   } else {
1596dfccc68fSToby Isaac     const PetscInt Nv = 8;
1597dfccc68fSToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
1598dfccc68fSToby Isaac     const PetscInt dim = 3;
1599dfccc68fSToby Isaac     const PetscInt dimR = 3;
1600dfccc68fSToby Isaac     PetscReal zOrder[24];
1601dfccc68fSToby Isaac     PetscReal zCoeff[24];
1602dfccc68fSToby Isaac     PetscInt  i, j, k, l;
1603dfccc68fSToby Isaac 
1604dfccc68fSToby Isaac     for (i = 0; i < Nv; i++) {
1605dfccc68fSToby Isaac       PetscInt zi = zToPlex[i];
1606dfccc68fSToby Isaac 
1607dfccc68fSToby Isaac       for (j = 0; j < dim; j++) {
1608dfccc68fSToby Isaac         zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]);
1609dfccc68fSToby Isaac       }
1610dfccc68fSToby Isaac     }
1611dfccc68fSToby Isaac     for (j = 0; j < dim; j++) {
1612dfccc68fSToby 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]);
1613dfccc68fSToby 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]);
1614dfccc68fSToby 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]);
1615dfccc68fSToby 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]);
1616dfccc68fSToby 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]);
1617dfccc68fSToby 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]);
1618dfccc68fSToby 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]);
1619dfccc68fSToby 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]);
1620dfccc68fSToby Isaac     }
1621dfccc68fSToby Isaac     for (i = 0; i < Nq; i++) {
1622dfccc68fSToby Isaac       PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], theta = points[dimR * i + 2];
1623dfccc68fSToby Isaac 
1624dfccc68fSToby Isaac       if (v) {
162591d2b7ceSToby Isaac         PetscReal extPoint[8];
1626dfccc68fSToby Isaac 
1627dfccc68fSToby Isaac         extPoint[0] = 1.;
1628dfccc68fSToby Isaac         extPoint[1] = xi;
1629dfccc68fSToby Isaac         extPoint[2] = eta;
1630dfccc68fSToby Isaac         extPoint[3] = xi * eta;
1631dfccc68fSToby Isaac         extPoint[4] = theta;
1632dfccc68fSToby Isaac         extPoint[5] = theta * xi;
1633dfccc68fSToby Isaac         extPoint[6] = theta * eta;
1634dfccc68fSToby Isaac         extPoint[7] = theta * eta * xi;
1635dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1636dfccc68fSToby Isaac           PetscReal val = 0.;
1637dfccc68fSToby Isaac 
1638dfccc68fSToby Isaac           for (k = 0; k < Nv; k++) {
1639dfccc68fSToby Isaac             val += extPoint[k] * zCoeff[dim * k + j];
1640dfccc68fSToby Isaac           }
1641dfccc68fSToby Isaac           v[i * dim + j] = val;
1642dfccc68fSToby Isaac         }
1643dfccc68fSToby Isaac       }
1644dfccc68fSToby Isaac       if (J) {
1645dfccc68fSToby Isaac         PetscReal extJ[24];
1646dfccc68fSToby Isaac 
1647dfccc68fSToby Isaac         extJ[0]  = 0.         ; extJ[1]  = 0.        ; extJ[2]  = 0.      ;
1648dfccc68fSToby Isaac         extJ[3]  = 1.         ; extJ[4]  = 0.        ; extJ[5]  = 0.      ;
1649dfccc68fSToby Isaac         extJ[6]  = 0.         ; extJ[7]  = 1.        ; extJ[8]  = 0.      ;
1650dfccc68fSToby Isaac         extJ[9]  = eta        ; extJ[10] = xi        ; extJ[11] = 0.      ;
1651dfccc68fSToby Isaac         extJ[12] = 0.         ; extJ[13] = 0.        ; extJ[14] = 1.      ;
1652dfccc68fSToby Isaac         extJ[15] = theta      ; extJ[16] = 0.        ; extJ[17] = xi      ;
1653dfccc68fSToby Isaac         extJ[18] = 0.         ; extJ[19] = theta     ; extJ[20] = eta     ;
1654dfccc68fSToby Isaac         extJ[21] = theta * eta; extJ[22] = theta * xi; extJ[23] = eta * xi;
1655dfccc68fSToby Isaac 
1656dfccc68fSToby Isaac         for (j = 0; j < dim; j++) {
1657dfccc68fSToby Isaac           for (k = 0; k < dimR; k++) {
1658dfccc68fSToby Isaac             PetscReal val = 0.;
1659dfccc68fSToby Isaac 
1660dfccc68fSToby Isaac             for (l = 0; l < Nv; l++) {
1661dfccc68fSToby Isaac               val += zCoeff[dim * l + j] * extJ[dimR * l + k];
1662dfccc68fSToby Isaac             }
1663dfccc68fSToby Isaac             J[i * dim * dim + dim * j + k] = val;
1664dfccc68fSToby Isaac           }
1665dfccc68fSToby Isaac         }
1666dfccc68fSToby Isaac         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
1667dfccc68fSToby Isaac         if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
1668dfccc68fSToby Isaac       }
1669dfccc68fSToby Isaac     }
1670dfccc68fSToby Isaac   }
16716858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
1672ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
1673ccd2543fSMatthew G Knepley }
1674ccd2543fSMatthew G Knepley 
16752df84da0SMatthew G. Knepley static PetscErrorCode DMPlexComputeTriangularPrismGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
16762df84da0SMatthew G. Knepley {
16776858538eSMatthew G. Knepley   const PetscScalar *array;
16782df84da0SMatthew G. Knepley   PetscScalar       *coords = NULL;
16792df84da0SMatthew G. Knepley   const PetscInt     dim    = 3;
16806858538eSMatthew G. Knepley   PetscInt           numCoords, d;
16816858538eSMatthew G. Knepley   PetscBool          isDG;
16822df84da0SMatthew G. Knepley 
16832df84da0SMatthew G. Knepley   PetscFunctionBegin;
16846858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
16856858538eSMatthew G. Knepley   PetscCheck(!invJ || J, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL");
16862df84da0SMatthew G. Knepley   if (!Nq) {
16872df84da0SMatthew G. Knepley     /* Assume that the map to the reference is affine */
16882df84da0SMatthew G. Knepley     *detJ = 0.0;
16892df84da0SMatthew G. Knepley     if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);}
16902df84da0SMatthew G. Knepley     if (J) {
16912df84da0SMatthew G. Knepley       for (d = 0; d < dim; d++) {
16922df84da0SMatthew G. Knepley         J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d]));
16932df84da0SMatthew G. Knepley         J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
16942df84da0SMatthew G. Knepley         J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d]));
16952df84da0SMatthew G. Knepley       }
16969566063dSJacob Faibussowitsch       PetscCall(PetscLogFlops(18.0));
16972df84da0SMatthew G. Knepley       DMPlex_Det3D_Internal(detJ, J);
16982df84da0SMatthew G. Knepley     }
16992df84da0SMatthew G. Knepley     if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);}
17002df84da0SMatthew G. Knepley   } else {
17012df84da0SMatthew G. Knepley     const PetscInt dim  = 3;
17022df84da0SMatthew G. Knepley     const PetscInt dimR = 3;
17032df84da0SMatthew G. Knepley     const PetscInt Nv   = 6;
17042df84da0SMatthew G. Knepley     PetscReal verts[18];
17052df84da0SMatthew G. Knepley     PetscReal coeff[18];
17062df84da0SMatthew G. Knepley     PetscInt  i, j, k, l;
17072df84da0SMatthew G. Knepley 
17082df84da0SMatthew G. Knepley     for (i = 0; i < Nv; ++i) for (j = 0; j < dim; ++j) verts[dim * i + j] = PetscRealPart(coords[dim * i + j]);
17092df84da0SMatthew G. Knepley     for (j = 0; j < dim; ++j) {
17102df84da0SMatthew G. Knepley       /* Check for triangle,
17112df84da0SMatthew 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)
17122df84da0SMatthew 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)
17132df84da0SMatthew G. Knepley            phi^2 =  1/2 (1 + eta)   chi^2 = delta(-1,  1)
17142df84da0SMatthew G. Knepley 
17152df84da0SMatthew G. Knepley            phi^0 + phi^1 + phi^2 = 1    coef_1   = 1/2 (         chi^1 + chi^2)
17162df84da0SMatthew G. Knepley           -phi^0 + phi^1 - phi^2 = xi   coef_xi  = 1/2 (-chi^0 + chi^1)
17172df84da0SMatthew G. Knepley           -phi^0 - phi^1 + phi^2 = eta  coef_eta = 1/2 (-chi^0         + chi^2)
17182df84da0SMatthew G. Knepley 
17192df84da0SMatthew G. Knepley           < chi_0 chi_1 chi_2> A /  1  1  1 \ / phi_0 \   <chi> I <phi>^T  so we need the inverse transpose
17202df84da0SMatthew G. Knepley                                  | -1  1 -1 | | phi_1 | =
17212df84da0SMatthew G. Knepley                                  \ -1 -1  1 / \ phi_2 /
17222df84da0SMatthew G. Knepley 
17232df84da0SMatthew 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
17242df84da0SMatthew G. Knepley       */
17252df84da0SMatthew G. Knepley       /* Nodal basis for evaluation at the vertices: {-xi - eta, 1 + xi, 1 + eta} (1 \mp zeta):
17262df84da0SMatthew G. Knepley            \phi^0 = 1/4 (   -xi - eta        + xi zeta + eta zeta) --> /  1  1  1  1  1  1 \ 1
17272df84da0SMatthew G. Knepley            \phi^1 = 1/4 (1      + eta - zeta           - eta zeta) --> | -1  1 -1 -1 -1  1 | eta
17282df84da0SMatthew G. Knepley            \phi^2 = 1/4 (1 + xi       - zeta - xi zeta)            --> | -1 -1  1 -1  1 -1 | xi
17292df84da0SMatthew G. Knepley            \phi^3 = 1/4 (   -xi - eta        - xi zeta - eta zeta) --> | -1 -1 -1  1  1  1 | zeta
17302df84da0SMatthew G. Knepley            \phi^4 = 1/4 (1 + xi       + zeta + xi zeta)            --> |  1  1 -1 -1  1 -1 | xi zeta
17312df84da0SMatthew G. Knepley            \phi^5 = 1/4 (1      + eta + zeta           + eta zeta) --> \  1 -1  1 -1 -1  1 / eta zeta
17322df84da0SMatthew G. Knepley            1/4 /  0  1  1  0  1  1 \
17332df84da0SMatthew G. Knepley                | -1  1  0 -1  0  1 |
17342df84da0SMatthew G. Knepley                | -1  0  1 -1  1  0 |
17352df84da0SMatthew G. Knepley                |  0 -1 -1  0  1  1 |
17362df84da0SMatthew G. Knepley                |  1  0 -1 -1  1  0 |
17372df84da0SMatthew G. Knepley                \  1 -1  0 -1  0  1 /
17382df84da0SMatthew G. Knepley       */
17392df84da0SMatthew G. Knepley       coeff[dim * 0 + j] = (1./4.) * (                      verts[dim * 1 + j] + verts[dim * 2 + j]                      + verts[dim * 4 + j] + verts[dim * 5 + j]);
17402df84da0SMatthew G. Knepley       coeff[dim * 1 + j] = (1./4.) * (-verts[dim * 0 + j] + verts[dim * 1 + j]                      - verts[dim * 3 + j]                      + verts[dim * 5 + j]);
17412df84da0SMatthew G. Knepley       coeff[dim * 2 + j] = (1./4.) * (-verts[dim * 0 + j]                      + verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
17422df84da0SMatthew G. Knepley       coeff[dim * 3 + j] = (1./4.) * (                    - verts[dim * 1 + j] - verts[dim * 2 + j]                      + verts[dim * 4 + j] + verts[dim * 5 + j]);
17432df84da0SMatthew G. Knepley       coeff[dim * 4 + j] = (1./4.) * ( verts[dim * 0 + j]                      - verts[dim * 2 + j] - verts[dim * 3 + j] + verts[dim * 4 + j]);
17442df84da0SMatthew G. Knepley       coeff[dim * 5 + j] = (1./4.) * ( verts[dim * 0 + j] - verts[dim * 1 + j]                      - verts[dim * 3 + j]                      + verts[dim * 5 + j]);
17452df84da0SMatthew G. Knepley       /* For reference prism:
17462df84da0SMatthew G. Knepley       {0, 0, 0}
17472df84da0SMatthew G. Knepley       {0, 1, 0}
17482df84da0SMatthew G. Knepley       {1, 0, 0}
17492df84da0SMatthew G. Knepley       {0, 0, 1}
17502df84da0SMatthew G. Knepley       {0, 0, 0}
17512df84da0SMatthew G. Knepley       {0, 0, 0}
17522df84da0SMatthew G. Knepley       */
17532df84da0SMatthew G. Knepley     }
17542df84da0SMatthew G. Knepley     for (i = 0; i < Nq; ++i) {
17552df84da0SMatthew G. Knepley       const PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], zeta = points[dimR * i + 2];
17562df84da0SMatthew G. Knepley 
17572df84da0SMatthew G. Knepley       if (v) {
17582df84da0SMatthew G. Knepley         PetscReal extPoint[6];
17592df84da0SMatthew G. Knepley         PetscInt  c;
17602df84da0SMatthew G. Knepley 
17612df84da0SMatthew G. Knepley         extPoint[0] = 1.;
17622df84da0SMatthew G. Knepley         extPoint[1] = eta;
17632df84da0SMatthew G. Knepley         extPoint[2] = xi;
17642df84da0SMatthew G. Knepley         extPoint[3] = zeta;
17652df84da0SMatthew G. Knepley         extPoint[4] = xi * zeta;
17662df84da0SMatthew G. Knepley         extPoint[5] = eta * zeta;
17672df84da0SMatthew G. Knepley         for (c = 0; c < dim; ++c) {
17682df84da0SMatthew G. Knepley           PetscReal val = 0.;
17692df84da0SMatthew G. Knepley 
17702df84da0SMatthew G. Knepley           for (k = 0; k < Nv; ++k) {
17712df84da0SMatthew G. Knepley             val += extPoint[k] * coeff[k*dim + c];
17722df84da0SMatthew G. Knepley           }
17732df84da0SMatthew G. Knepley           v[i*dim + c] = val;
17742df84da0SMatthew G. Knepley         }
17752df84da0SMatthew G. Knepley       }
17762df84da0SMatthew G. Knepley       if (J) {
17772df84da0SMatthew G. Knepley         PetscReal extJ[18];
17782df84da0SMatthew G. Knepley 
17792df84da0SMatthew G. Knepley         extJ[0]  = 0.  ; extJ[1]  = 0.  ; extJ[2]  = 0. ;
17802df84da0SMatthew G. Knepley         extJ[3]  = 0.  ; extJ[4]  = 1.  ; extJ[5]  = 0. ;
17812df84da0SMatthew G. Knepley         extJ[6]  = 1.  ; extJ[7]  = 0.  ; extJ[8]  = 0. ;
17822df84da0SMatthew G. Knepley         extJ[9]  = 0.  ; extJ[10] = 0.  ; extJ[11] = 1. ;
17832df84da0SMatthew G. Knepley         extJ[12] = zeta; extJ[13] = 0.  ; extJ[14] = xi ;
17842df84da0SMatthew G. Knepley         extJ[15] = 0.  ; extJ[16] = zeta; extJ[17] = eta;
17852df84da0SMatthew G. Knepley 
17862df84da0SMatthew G. Knepley         for (j = 0; j < dim; j++) {
17872df84da0SMatthew G. Knepley           for (k = 0; k < dimR; k++) {
17882df84da0SMatthew G. Knepley             PetscReal val = 0.;
17892df84da0SMatthew G. Knepley 
17902df84da0SMatthew G. Knepley             for (l = 0; l < Nv; l++) {
17912df84da0SMatthew G. Knepley               val += coeff[dim * l + j] * extJ[dimR * l + k];
17922df84da0SMatthew G. Knepley             }
17932df84da0SMatthew G. Knepley             J[i * dim * dim + dim * j + k] = val;
17942df84da0SMatthew G. Knepley           }
17952df84da0SMatthew G. Knepley         }
17962df84da0SMatthew G. Knepley         DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]);
17972df84da0SMatthew G. Knepley         if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);}
17982df84da0SMatthew G. Knepley       }
17992df84da0SMatthew G. Knepley     }
18002df84da0SMatthew G. Knepley   }
18016858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, e, &isDG, &numCoords, &array, &coords));
18022df84da0SMatthew G. Knepley   PetscFunctionReturn(0);
18032df84da0SMatthew G. Knepley }
18042df84da0SMatthew G. Knepley 
1805dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeCellGeometryFEM_Implicit(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
1806dfccc68fSToby Isaac {
1807ba2698f1SMatthew G. Knepley   DMPolytopeType  ct;
1808dfccc68fSToby Isaac   PetscInt        depth, dim, coordDim, coneSize, i;
1809dfccc68fSToby Isaac   PetscInt        Nq = 0;
1810dfccc68fSToby Isaac   const PetscReal *points = NULL;
1811dfccc68fSToby Isaac   DMLabel         depthLabel;
1812c330f8ffSToby Isaac   PetscReal       xi0[3] = {-1.,-1.,-1.}, v0[3], J0[9], detJ0;
1813dfccc68fSToby Isaac   PetscBool       isAffine = PETSC_TRUE;
1814dfccc68fSToby Isaac 
1815dfccc68fSToby Isaac   PetscFunctionBegin;
18169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
18179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
18189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
18199566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValue(depthLabel, cell, &dim));
1820dfccc68fSToby Isaac   if (depth == 1 && dim == 1) {
18219566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
1822dfccc68fSToby Isaac   }
18239566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
182463a3b9bcSJacob Faibussowitsch   PetscCheck(coordDim <= 3,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported coordinate dimension %" PetscInt_FMT " > 3", coordDim);
18259566063dSJacob Faibussowitsch   if (quad) PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, &points, NULL));
18269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1827ba2698f1SMatthew G. Knepley   switch (ct) {
1828ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_POINT:
18299566063dSJacob Faibussowitsch     PetscCall(DMPlexComputePointGeometry_Internal(dm, cell, v, J, invJ, detJ));
1830dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1831dfccc68fSToby Isaac     break;
1832ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_SEGMENT:
1833412e9a14SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
18349566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18359566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeLineGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1836dfccc68fSToby Isaac     break;
1837ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
18389566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18399566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeTriangleGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1840dfccc68fSToby Isaac     break;
1841ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
18429566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_FALSE, Nq, points, v, J, invJ, detJ));
1843412e9a14SMatthew G. Knepley     isAffine = PETSC_FALSE;
1844412e9a14SMatthew G. Knepley     break;
1845412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
18469566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_TRUE, Nq, points, v, J, invJ, detJ));
1847dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1848dfccc68fSToby Isaac     break;
1849ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TETRAHEDRON:
18509566063dSJacob Faibussowitsch     if (Nq) PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0));
18519566063dSJacob Faibussowitsch     else    PetscCall(DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v,  J,  invJ,  detJ));
1852dfccc68fSToby Isaac     break;
1853ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_HEXAHEDRON:
18549566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeHexahedronGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
1855dfccc68fSToby Isaac     isAffine = PETSC_FALSE;
1856dfccc68fSToby Isaac     break;
18572df84da0SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM:
18589566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeTriangularPrismGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ));
18592df84da0SMatthew G. Knepley     isAffine = PETSC_FALSE;
18602df84da0SMatthew G. Knepley     break;
18612df84da0SMatthew 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))]);
1862dfccc68fSToby Isaac   }
18637318780aSToby Isaac   if (isAffine && Nq) {
1864dfccc68fSToby Isaac     if (v) {
1865dfccc68fSToby Isaac       for (i = 0; i < Nq; i++) {
1866c330f8ffSToby Isaac         CoordinatesRefToReal(coordDim, dim, xi0, v0, J0, &points[dim * i], &v[coordDim * i]);
1867dfccc68fSToby Isaac       }
1868dfccc68fSToby Isaac     }
18697318780aSToby Isaac     if (detJ) {
18707318780aSToby Isaac       for (i = 0; i < Nq; i++) {
18717318780aSToby Isaac         detJ[i] = detJ0;
1872dfccc68fSToby Isaac       }
18737318780aSToby Isaac     }
18747318780aSToby Isaac     if (J) {
18757318780aSToby Isaac       PetscInt k;
18767318780aSToby Isaac 
18777318780aSToby Isaac       for (i = 0, k = 0; i < Nq; i++) {
1878dfccc68fSToby Isaac         PetscInt j;
1879dfccc68fSToby Isaac 
18807318780aSToby Isaac         for (j = 0; j < coordDim * coordDim; j++, k++) {
18817318780aSToby Isaac           J[k] = J0[j];
18827318780aSToby Isaac         }
18837318780aSToby Isaac       }
18847318780aSToby Isaac     }
18857318780aSToby Isaac     if (invJ) {
18867318780aSToby Isaac       PetscInt k;
18877318780aSToby Isaac       switch (coordDim) {
18887318780aSToby Isaac       case 0:
18897318780aSToby Isaac         break;
18907318780aSToby Isaac       case 1:
18917318780aSToby Isaac         invJ[0] = 1./J0[0];
18927318780aSToby Isaac         break;
18937318780aSToby Isaac       case 2:
18947318780aSToby Isaac         DMPlex_Invert2D_Internal(invJ, J0, detJ0);
18957318780aSToby Isaac         break;
18967318780aSToby Isaac       case 3:
18977318780aSToby Isaac         DMPlex_Invert3D_Internal(invJ, J0, detJ0);
18987318780aSToby Isaac         break;
18997318780aSToby Isaac       }
19007318780aSToby Isaac       for (i = 1, k = coordDim * coordDim; i < Nq; i++) {
19017318780aSToby Isaac         PetscInt j;
19027318780aSToby Isaac 
19037318780aSToby Isaac         for (j = 0; j < coordDim * coordDim; j++, k++) {
19047318780aSToby Isaac           invJ[k] = invJ[j];
19057318780aSToby Isaac         }
1906dfccc68fSToby Isaac       }
1907dfccc68fSToby Isaac     }
1908dfccc68fSToby Isaac   }
1909dfccc68fSToby Isaac   PetscFunctionReturn(0);
1910dfccc68fSToby Isaac }
1911dfccc68fSToby Isaac 
1912ccd2543fSMatthew G Knepley /*@C
19138e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryAffineFEM - Assuming an affine map, compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
1914ccd2543fSMatthew G Knepley 
1915d083f849SBarry Smith   Collective on dm
1916ccd2543fSMatthew G Knepley 
19174165533cSJose E. Roman   Input Parameters:
1918ccd2543fSMatthew G Knepley + dm   - the DM
1919ccd2543fSMatthew G Knepley - cell - the cell
1920ccd2543fSMatthew G Knepley 
19214165533cSJose E. Roman   Output Parameters:
19229b172b3aSMatthew Knepley + v0   - the translation part of this affine transform, meaning the translation to the origin (not the first vertex of the reference cell)
1923ccd2543fSMatthew G Knepley . J    - the Jacobian of the transform from the reference element
1924ccd2543fSMatthew G Knepley . invJ - the inverse of the Jacobian
1925ccd2543fSMatthew G Knepley - detJ - the Jacobian determinant
1926ccd2543fSMatthew G Knepley 
1927ccd2543fSMatthew G Knepley   Level: advanced
1928ccd2543fSMatthew G Knepley 
1929ccd2543fSMatthew G Knepley   Fortran Notes:
1930ccd2543fSMatthew G Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
1931ccd2543fSMatthew G Knepley   include petsc.h90 in your code.
1932ccd2543fSMatthew G Knepley 
1933db781477SPatrick Sanan .seealso: `DMPlexComputeCellGeometryFEM()`, `DMGetCoordinateSection()`, `DMGetCoordinates()`
1934ccd2543fSMatthew G Knepley @*/
19358e0841e0SMatthew G. Knepley PetscErrorCode DMPlexComputeCellGeometryAffineFEM(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
1936ccd2543fSMatthew G Knepley {
1937ccd2543fSMatthew G Knepley   PetscFunctionBegin;
19389566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, NULL, v0, J, invJ, detJ));
19398e0841e0SMatthew G. Knepley   PetscFunctionReturn(0);
19408e0841e0SMatthew G. Knepley }
19418e0841e0SMatthew G. Knepley 
1942dfccc68fSToby Isaac static PetscErrorCode DMPlexComputeCellGeometryFEM_FE(DM dm, PetscFE fe, PetscInt point, PetscQuadrature quad, PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
19438e0841e0SMatthew G. Knepley {
19446858538eSMatthew G. Knepley   const PetscScalar *array;
19458e0841e0SMatthew G. Knepley   PetscScalar       *coords = NULL;
19466858538eSMatthew G. Knepley   PetscInt           numCoords;
19476858538eSMatthew G. Knepley   PetscBool          isDG;
19486858538eSMatthew G. Knepley   PetscQuadrature    feQuad;
19498e0841e0SMatthew G. Knepley   const PetscReal   *quadPoints;
1950ef0bb6c7SMatthew G. Knepley   PetscTabulation    T;
19516858538eSMatthew G. Knepley   PetscInt           dim, cdim, pdim, qdim, Nq, q;
19528e0841e0SMatthew G. Knepley 
19538e0841e0SMatthew G. Knepley   PetscFunctionBegin;
19549566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
19559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
19566858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
1957dfccc68fSToby Isaac   if (!quad) { /* use the first point of the first functional of the dual space */
1958dfccc68fSToby Isaac     PetscDualSpace dsp;
1959dfccc68fSToby Isaac 
19609566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDualSpace(fe, &dsp));
19619566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(dsp, 0, &quad));
19629566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
1963dfccc68fSToby Isaac     Nq = 1;
1964dfccc68fSToby Isaac   } else {
19659566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL));
1966dfccc68fSToby Isaac   }
19679566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
19689566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &feQuad));
1969dfccc68fSToby Isaac   if (feQuad == quad) {
19709566063dSJacob Faibussowitsch     PetscCall(PetscFEGetCellTabulation(fe, J ? 1 : 0, &T));
197163a3b9bcSJacob 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);
1972dfccc68fSToby Isaac   } else {
19739566063dSJacob Faibussowitsch     PetscCall(PetscFECreateTabulation(fe, 1, Nq, quadPoints, J ? 1 : 0, &T));
1974dfccc68fSToby Isaac   }
197563a3b9bcSJacob Faibussowitsch   PetscCheck(qdim == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Point dimension %" PetscInt_FMT " != quadrature dimension %" PetscInt_FMT, dim, qdim);
1976ef0bb6c7SMatthew G. Knepley   {
1977ef0bb6c7SMatthew G. Knepley     const PetscReal *basis    = T->T[0];
1978ef0bb6c7SMatthew G. Knepley     const PetscReal *basisDer = T->T[1];
1979ef0bb6c7SMatthew G. Knepley     PetscReal        detJt;
1980ef0bb6c7SMatthew G. Knepley 
1981a2a9e04cSMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
198263a3b9bcSJacob Faibussowitsch     PetscCheck(Nq == T->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Np %" PetscInt_FMT " != %" PetscInt_FMT, Nq, T->Np);
198363a3b9bcSJacob Faibussowitsch     PetscCheck(pdim == T->Nb,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nb %" PetscInt_FMT " != %" PetscInt_FMT, pdim, T->Nb);
198463a3b9bcSJacob Faibussowitsch     PetscCheck(dim == T->Nc,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nc %" PetscInt_FMT " != %" PetscInt_FMT, dim, T->Nc);
198563a3b9bcSJacob Faibussowitsch     PetscCheck(cdim == T->cdim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "cdim %" PetscInt_FMT " != %" PetscInt_FMT, cdim, T->cdim);
1986a2a9e04cSMatthew G. Knepley #endif
1987dfccc68fSToby Isaac     if (v) {
19889566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(v, Nq*cdim));
1989f960e424SToby Isaac       for (q = 0; q < Nq; ++q) {
1990f960e424SToby Isaac         PetscInt i, k;
1991f960e424SToby Isaac 
1992301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
1993301b184aSMatthew G. Knepley           const PetscInt vertex = k/cdim;
1994301b184aSMatthew G. Knepley           for (i = 0; i < cdim; ++i) {
1995301b184aSMatthew G. Knepley             v[q*cdim + i] += basis[(q*pdim + k)*cdim + i] * PetscRealPart(coords[vertex*cdim + i]);
1996301b184aSMatthew G. Knepley           }
1997301b184aSMatthew G. Knepley         }
19989566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0*pdim*cdim));
1999f960e424SToby Isaac       }
2000f960e424SToby Isaac     }
20018e0841e0SMatthew G. Knepley     if (J) {
20029566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(J, Nq*cdim*cdim));
20038e0841e0SMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
20048e0841e0SMatthew G. Knepley         PetscInt i, j, k, c, r;
20058e0841e0SMatthew G. Knepley 
20068e0841e0SMatthew G. Knepley         /* J = dx_i/d\xi_j = sum[k=0,n-1] dN_k/d\xi_j * x_i(k) */
2007301b184aSMatthew G. Knepley         for (k = 0; k < pdim; ++k) {
2008301b184aSMatthew G. Knepley           const PetscInt vertex = k/cdim;
2009301b184aSMatthew G. Knepley           for (j = 0; j < dim; ++j) {
2010301b184aSMatthew G. Knepley             for (i = 0; i < cdim; ++i) {
2011301b184aSMatthew G. Knepley               J[(q*cdim + i)*cdim + j] += basisDer[((q*pdim + k)*cdim + i)*dim + j] * PetscRealPart(coords[vertex*cdim + i]);
2012301b184aSMatthew G. Knepley             }
2013301b184aSMatthew G. Knepley           }
2014301b184aSMatthew G. Knepley         }
20159566063dSJacob Faibussowitsch         PetscCall(PetscLogFlops(2.0*pdim*dim*cdim));
20168e0841e0SMatthew G. Knepley         if (cdim > dim) {
20178e0841e0SMatthew G. Knepley           for (c = dim; c < cdim; ++c)
20188e0841e0SMatthew G. Knepley             for (r = 0; r < cdim; ++r)
20198e0841e0SMatthew G. Knepley               J[r*cdim+c] = r == c ? 1.0 : 0.0;
20208e0841e0SMatthew G. Knepley         }
2021f960e424SToby Isaac         if (!detJ && !invJ) continue;
2022a63b72c6SToby Isaac         detJt = 0.;
20238e0841e0SMatthew G. Knepley         switch (cdim) {
20248e0841e0SMatthew G. Knepley         case 3:
2025037dc194SToby Isaac           DMPlex_Det3D_Internal(&detJt, &J[q*cdim*dim]);
2026037dc194SToby Isaac           if (invJ) {DMPlex_Invert3D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);}
202717fe8556SMatthew G. Knepley           break;
202849dc4407SMatthew G. Knepley         case 2:
20299f328543SToby Isaac           DMPlex_Det2D_Internal(&detJt, &J[q*cdim*dim]);
2030037dc194SToby Isaac           if (invJ) {DMPlex_Invert2D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);}
203149dc4407SMatthew G. Knepley           break;
20328e0841e0SMatthew G. Knepley         case 1:
2033037dc194SToby Isaac           detJt = J[q*cdim*dim];
2034037dc194SToby Isaac           if (invJ) invJ[q*cdim*dim] = 1.0/detJt;
203549dc4407SMatthew G. Knepley         }
2036f960e424SToby Isaac         if (detJ) detJ[q] = detJt;
203749dc4407SMatthew G. Knepley       }
203808401ef6SPierre Jolivet     } else PetscCheck(!detJ && !invJ,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Need J to compute invJ or detJ");
203949dc4407SMatthew G. Knepley   }
20409566063dSJacob Faibussowitsch   if (feQuad != quad) PetscCall(PetscTabulationDestroy(&T));
20416858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, point, &isDG, &numCoords, &array, &coords));
20428e0841e0SMatthew G. Knepley   PetscFunctionReturn(0);
20438e0841e0SMatthew G. Knepley }
20448e0841e0SMatthew G. Knepley 
20458e0841e0SMatthew G. Knepley /*@C
20468e0841e0SMatthew G. Knepley   DMPlexComputeCellGeometryFEM - Compute the Jacobian, inverse Jacobian, and Jacobian determinant at each quadrature point in the given cell
20478e0841e0SMatthew G. Knepley 
2048d083f849SBarry Smith   Collective on dm
20498e0841e0SMatthew G. Knepley 
20504165533cSJose E. Roman   Input Parameters:
20518e0841e0SMatthew G. Knepley + dm   - the DM
20528e0841e0SMatthew G. Knepley . cell - the cell
2053dfccc68fSToby Isaac - quad - the quadrature containing the points in the reference element where the geometry will be evaluated.  If quad == NULL, geometry will be
2054dfccc68fSToby Isaac          evaluated at the first vertex of the reference element
20558e0841e0SMatthew G. Knepley 
20564165533cSJose E. Roman   Output Parameters:
2057dfccc68fSToby Isaac + v    - the image of the transformed quadrature points, otherwise the image of the first vertex in the closure of the reference element
20588e0841e0SMatthew G. Knepley . J    - the Jacobian of the transform from the reference element at each quadrature point
20598e0841e0SMatthew G. Knepley . invJ - the inverse of the Jacobian at each quadrature point
20608e0841e0SMatthew G. Knepley - detJ - the Jacobian determinant at each quadrature point
20618e0841e0SMatthew G. Knepley 
20628e0841e0SMatthew G. Knepley   Level: advanced
20638e0841e0SMatthew G. Knepley 
20648e0841e0SMatthew G. Knepley   Fortran Notes:
20658e0841e0SMatthew G. Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
20668e0841e0SMatthew G. Knepley   include petsc.h90 in your code.
20678e0841e0SMatthew G. Knepley 
2068db781477SPatrick Sanan .seealso: `DMGetCoordinateSection()`, `DMGetCoordinates()`
20698e0841e0SMatthew G. Knepley @*/
2070dfccc68fSToby Isaac PetscErrorCode DMPlexComputeCellGeometryFEM(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
20718e0841e0SMatthew G. Knepley {
2072bb4a5db5SMatthew G. Knepley   DM             cdm;
2073dfccc68fSToby Isaac   PetscFE        fe = NULL;
20748e0841e0SMatthew G. Knepley 
20758e0841e0SMatthew G. Knepley   PetscFunctionBegin;
2076dadcf809SJacob Faibussowitsch   PetscValidRealPointer(detJ, 7);
20779566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
2078bb4a5db5SMatthew G. Knepley   if (cdm) {
2079dfccc68fSToby Isaac     PetscClassId id;
2080dfccc68fSToby Isaac     PetscInt     numFields;
2081e5e52638SMatthew G. Knepley     PetscDS      prob;
2082dfccc68fSToby Isaac     PetscObject  disc;
2083dfccc68fSToby Isaac 
20849566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(cdm, &numFields));
2085dfccc68fSToby Isaac     if (numFields) {
20869566063dSJacob Faibussowitsch       PetscCall(DMGetDS(cdm, &prob));
20879566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob,0,&disc));
20889566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
2089dfccc68fSToby Isaac       if (id == PETSCFE_CLASSID) {
2090dfccc68fSToby Isaac         fe = (PetscFE) disc;
2091dfccc68fSToby Isaac       }
2092dfccc68fSToby Isaac     }
2093dfccc68fSToby Isaac   }
20949566063dSJacob Faibussowitsch   if (!fe) PetscCall(DMPlexComputeCellGeometryFEM_Implicit(dm, cell, quad, v, J, invJ, detJ));
20959566063dSJacob Faibussowitsch   else     PetscCall(DMPlexComputeCellGeometryFEM_FE(dm, fe, cell, quad, v, J, invJ, detJ));
2096ccd2543fSMatthew G Knepley   PetscFunctionReturn(0);
2097ccd2543fSMatthew G Knepley }
2098834e62ceSMatthew G. Knepley 
20999bf2564aSMatt McGurn static PetscErrorCode DMPlexComputeGeometryFVM_0D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
21009bf2564aSMatt McGurn {
21019bf2564aSMatt McGurn   PetscSection        coordSection;
21029bf2564aSMatt McGurn   Vec                 coordinates;
21039bf2564aSMatt McGurn   const PetscScalar  *coords = NULL;
21049bf2564aSMatt McGurn   PetscInt            d, dof, off;
21059bf2564aSMatt McGurn 
21069bf2564aSMatt McGurn   PetscFunctionBegin;
21079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
21089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
21099566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
21109bf2564aSMatt McGurn 
21119bf2564aSMatt McGurn   /* for a point the centroid is just the coord */
21129bf2564aSMatt McGurn   if (centroid) {
21139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
21149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
21159bf2564aSMatt McGurn     for (d = 0; d < dof; d++){
21169bf2564aSMatt McGurn       centroid[d] = PetscRealPart(coords[off + d]);
21179bf2564aSMatt McGurn     }
21189bf2564aSMatt McGurn   }
21199bf2564aSMatt McGurn   if (normal) {
21209bf2564aSMatt McGurn     const PetscInt *support, *cones;
21219bf2564aSMatt McGurn     PetscInt        supportSize;
21229bf2564aSMatt McGurn     PetscReal       norm, sign;
21239bf2564aSMatt McGurn 
21249bf2564aSMatt McGurn     /* compute the norm based upon the support centroids */
21259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, cell, &supportSize));
21269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, cell, &support));
21279566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, support[0], NULL, normal, NULL));
21289bf2564aSMatt McGurn 
21299bf2564aSMatt McGurn     /* Take the normal from the centroid of the support to the vertex*/
21309566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(coordSection, cell, &dof));
21319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(coordSection, cell, &off));
21329bf2564aSMatt McGurn     for (d = 0; d < dof; d++){
21339bf2564aSMatt McGurn       normal[d] -= PetscRealPart(coords[off + d]);
21349bf2564aSMatt McGurn     }
21359bf2564aSMatt McGurn 
21369bf2564aSMatt McGurn     /* Determine the sign of the normal based upon its location in the support */
21379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, support[0], &cones));
21389bf2564aSMatt McGurn     sign = cones[0] == cell ? 1.0 : -1.0;
21399bf2564aSMatt McGurn 
21409bf2564aSMatt McGurn     norm = DMPlex_NormD_Internal(dim, normal);
21419bf2564aSMatt McGurn     for (d = 0; d < dim; ++d) normal[d] /= (norm*sign);
21429bf2564aSMatt McGurn   }
21439bf2564aSMatt McGurn   if (vol) {
21449bf2564aSMatt McGurn     *vol = 1.0;
21459bf2564aSMatt McGurn   }
21469566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
21479bf2564aSMatt McGurn   PetscFunctionReturn(0);
21489bf2564aSMatt McGurn }
21499bf2564aSMatt McGurn 
2150011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_1D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2151cc08537eSMatthew G. Knepley {
21526858538eSMatthew G. Knepley   const PetscScalar *array;
2153a1e44745SMatthew G. Knepley   PetscScalar       *coords = NULL;
2154714b99b6SMatthew G. Knepley   PetscInt           coordSize, d;
21556858538eSMatthew G. Knepley   PetscBool          isDG;
2156cc08537eSMatthew G. Knepley 
2157cc08537eSMatthew G. Knepley   PetscFunctionBegin;
21586858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2159cc08537eSMatthew G. Knepley   if (centroid) {
21606858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) centroid[d] = 0.5*PetscRealPart(coords[d] + coords[dim+d]);
2161cc08537eSMatthew G. Knepley   }
2162cc08537eSMatthew G. Knepley   if (normal) {
2163a60a936bSMatthew G. Knepley     PetscReal norm;
2164a60a936bSMatthew G. Knepley 
216508401ef6SPierre Jolivet     PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "We only support 2D edges right now");
21666858538eSMatthew G. Knepley     normal[0] = -PetscRealPart(coords[1] - coords[dim+1]);
21676858538eSMatthew G. Knepley     normal[1] =  PetscRealPart(coords[0] - coords[dim+0]);
2168714b99b6SMatthew G. Knepley     norm      = DMPlex_NormD_Internal(dim, normal);
2169714b99b6SMatthew G. Knepley     for (d = 0; d < dim; ++d) normal[d] /= norm;
2170cc08537eSMatthew G. Knepley   }
2171cc08537eSMatthew G. Knepley   if (vol) {
2172714b99b6SMatthew G. Knepley     *vol = 0.0;
21736858538eSMatthew G. Knepley     for (d = 0; d < dim; ++d) *vol += PetscSqr(PetscRealPart(coords[d] - coords[dim+d]));
2174714b99b6SMatthew G. Knepley     *vol = PetscSqrtReal(*vol);
2175cc08537eSMatthew G. Knepley   }
21766858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2177cc08537eSMatthew G. Knepley   PetscFunctionReturn(0);
2178cc08537eSMatthew G. Knepley }
2179cc08537eSMatthew G. Knepley 
2180cc08537eSMatthew G. Knepley /* Centroid_i = (\sum_n A_n Cn_i) / A */
2181011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_2D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2182cc08537eSMatthew G. Knepley {
2183412e9a14SMatthew G. Knepley   DMPolytopeType     ct;
21846858538eSMatthew G. Knepley   const PetscScalar *array;
2185cc08537eSMatthew G. Knepley   PetscScalar       *coords = NULL;
21866858538eSMatthew G. Knepley   PetscInt           coordSize;
21876858538eSMatthew G. Knepley   PetscBool          isDG;
2188793a2a13SMatthew G. Knepley   PetscInt           fv[4] = {0, 1, 2, 3};
21896858538eSMatthew G. Knepley   PetscInt           cdim, numCorners, p, d;
2190cc08537eSMatthew G. Knepley 
2191cc08537eSMatthew G. Knepley   PetscFunctionBegin;
2192793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
21939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2194412e9a14SMatthew G. Knepley   switch (ct) {
21954f99dae5SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR: fv[2] = 3; fv[3] = 2;break;
2196412e9a14SMatthew G. Knepley     default: break;
2197412e9a14SMatthew G. Knepley   }
21989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
21996858538eSMatthew G. Knepley   PetscCall(DMPlexGetConeSize(dm, cell, &numCorners));
22006858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
22013f27a4e6SJed Brown   {
22023f27a4e6SJed Brown     PetscReal c[3] = {0., 0., 0.}, n[3] = {0., 0., 0.}, origin[3] = {0., 0., 0.}, norm;
2203793a2a13SMatthew G. Knepley 
22043f27a4e6SJed Brown     for (d = 0; d < cdim; d++) origin[d] = PetscRealPart(coords[d]);
22054f99dae5SMatthew G. Knepley     for (p = 0; p < numCorners-2; ++p) {
22063f27a4e6SJed Brown       PetscReal e0[3] = {0., 0., 0.}, e1[3] = {0., 0., 0.};
22073f27a4e6SJed Brown       for (d = 0; d < cdim; d++) {
22083f27a4e6SJed Brown         e0[d] = PetscRealPart(coords[cdim*fv[p+1]+d]) - origin[d];
22093f27a4e6SJed Brown         e1[d] = PetscRealPart(coords[cdim*fv[p+2]+d]) - origin[d];
22103f27a4e6SJed Brown       }
22113f27a4e6SJed Brown       const PetscReal dx = e0[1] * e1[2] - e0[2] * e1[1];
22123f27a4e6SJed Brown       const PetscReal dy = e0[2] * e1[0] - e0[0] * e1[2];
22133f27a4e6SJed Brown       const PetscReal dz = e0[0] * e1[1] - e0[1] * e1[0];
22143f27a4e6SJed Brown       const PetscReal a  = PetscSqrtReal(dx*dx + dy*dy + dz*dz);
22154f99dae5SMatthew G. Knepley 
22164f99dae5SMatthew G. Knepley       n[0] += dx;
22174f99dae5SMatthew G. Knepley       n[1] += dy;
22184f99dae5SMatthew G. Knepley       n[2] += dz;
22193f27a4e6SJed Brown       for (d = 0; d < cdim; d++) {
22203f27a4e6SJed Brown         c[d] += a * PetscRealPart(origin[d] + coords[cdim*fv[p+1]+d] + coords[cdim*fv[p+2]+d]) / 3.;
22213f27a4e6SJed Brown       }
2222ceee4971SMatthew G. Knepley     }
22234f99dae5SMatthew G. Knepley     norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
22244f99dae5SMatthew G. Knepley     n[0] /= norm;
22254f99dae5SMatthew G. Knepley     n[1] /= norm;
22264f99dae5SMatthew G. Knepley     n[2] /= norm;
22274f99dae5SMatthew G. Knepley     c[0] /= norm;
22284f99dae5SMatthew G. Knepley     c[1] /= norm;
22294f99dae5SMatthew G. Knepley     c[2] /= norm;
22304f99dae5SMatthew G. Knepley     if (vol) *vol = 0.5*norm;
22314f99dae5SMatthew G. Knepley     if (centroid) for (d = 0; d < cdim; ++d) centroid[d] = c[d];
22324f99dae5SMatthew G. Knepley     if (normal) for (d = 0; d < cdim; ++d) normal[d] = n[d];
22330a1d6728SMatthew G. Knepley   }
22346858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
2235cc08537eSMatthew G. Knepley   PetscFunctionReturn(0);
2236cc08537eSMatthew G. Knepley }
2237cc08537eSMatthew G. Knepley 
22380ec8681fSMatthew G. Knepley /* Centroid_i = (\sum_n V_n Cn_i) / V */
2239011ea5d8SMatthew G. Knepley static PetscErrorCode DMPlexComputeGeometryFVM_3D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
22400ec8681fSMatthew G. Knepley {
2241412e9a14SMatthew G. Knepley   DMPolytopeType        ct;
22426858538eSMatthew G. Knepley   const PetscScalar    *array;
22430ec8681fSMatthew G. Knepley   PetscScalar          *coords = NULL;
22446858538eSMatthew G. Knepley   PetscInt              coordSize;
22456858538eSMatthew G. Knepley   PetscBool             isDG;
22463f27a4e6SJed Brown   PetscReal             vsum = 0.0, vtmp, coordsTmp[3*3], origin[3];
22476858538eSMatthew G. Knepley   const PetscInt        order[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
22486858538eSMatthew G. Knepley   const PetscInt       *cone, *faceSizes, *faces;
22496858538eSMatthew G. Knepley   const DMPolytopeType *faceTypes;
2250793a2a13SMatthew G. Knepley   PetscBool             isHybrid = PETSC_FALSE;
22516858538eSMatthew G. Knepley   PetscInt              numFaces, f, fOff = 0, p, d;
22520ec8681fSMatthew G. Knepley 
22530ec8681fSMatthew G. Knepley   PetscFunctionBegin;
225463a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No support for dim %" PetscInt_FMT " > 3", dim);
2255793a2a13SMatthew G. Knepley   /* Must check for hybrid cells because prisms have a different orientation scheme */
22569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellType(dm, cell, &ct));
2257412e9a14SMatthew G. Knepley   switch (ct) {
2258412e9a14SMatthew G. Knepley     case DM_POLYTOPE_POINT_PRISM_TENSOR:
2259412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
2260412e9a14SMatthew G. Knepley     case DM_POLYTOPE_TRI_PRISM_TENSOR:
2261412e9a14SMatthew G. Knepley     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
2262412e9a14SMatthew G. Knepley       isHybrid = PETSC_TRUE;
2263412e9a14SMatthew G. Knepley     default: break;
2264412e9a14SMatthew G. Knepley   }
2265793a2a13SMatthew G. Knepley 
2266d9a81ebdSMatthew G. Knepley   if (centroid) for (d = 0; d < dim; ++d) centroid[d] = 0.0;
22676858538eSMatthew G. Knepley   PetscCall(DMPlexGetCone(dm, cell, &cone));
22686858538eSMatthew G. Knepley 
22696858538eSMatthew G. Knepley   // Using the closure of faces for coordinates does not work in periodic geometries, so we index into the cell coordinates
22706858538eSMatthew G. Knepley   PetscCall(DMPlexGetRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
22716858538eSMatthew G. Knepley   PetscCall(DMPlexGetCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
22720ec8681fSMatthew G. Knepley   for (f = 0; f < numFaces; ++f) {
2273793a2a13SMatthew G. Knepley     PetscBool flip = isHybrid && f == 0 ? PETSC_TRUE : PETSC_FALSE; /* The first hybrid face is reversed */
2274793a2a13SMatthew G. Knepley 
22753f27a4e6SJed Brown     // If using zero as the origin vertex for each tetrahedron, an element far from the origin will have positive and
22763f27a4e6SJed Brown     // negative volumes that nearly cancel, thus incurring rounding error. Here we define origin[] as the first vertex
22773f27a4e6SJed Brown     // so that all tetrahedra have positive volume.
22783f27a4e6SJed Brown     if (f == 0) for (d = 0; d < dim; d++) origin[d] = PetscRealPart(coords[d]);
22796858538eSMatthew G. Knepley     switch (faceTypes[f]) {
2280ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_TRIANGLE:
22810ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
22826858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+0]*dim+d]) - origin[d];
22836858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+1]*dim+d]) - origin[d];
22846858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+2]*dim+d]) - origin[d];
22850ec8681fSMatthew G. Knepley       }
22860ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
22876858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
22880ec8681fSMatthew G. Knepley       vsum += vtmp;
22894f25033aSJed Brown       if (centroid) {           /* Centroid of OABC = (a+b+c)/4 */
22900ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
22911ee9d5ecSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
22920ec8681fSMatthew G. Knepley         }
22930ec8681fSMatthew G. Knepley       }
22940ec8681fSMatthew G. Knepley       break;
2295ba2698f1SMatthew G. Knepley     case DM_POLYTOPE_QUADRILATERAL:
2296412e9a14SMatthew G. Knepley     case DM_POLYTOPE_SEG_PRISM_TENSOR:
2297793a2a13SMatthew G. Knepley     {
2298793a2a13SMatthew G. Knepley       PetscInt fv[4] = {0, 1, 2, 3};
2299793a2a13SMatthew G. Knepley 
2300793a2a13SMatthew G. Knepley       /* Side faces for hybrid cells are are stored as tensor products */
2301793a2a13SMatthew G. Knepley       if (isHybrid && f > 1) {fv[2] = 3; fv[3] = 2;}
23020ec8681fSMatthew G. Knepley       /* DO FOR PYRAMID */
23030ec8681fSMatthew G. Knepley       /* First tet */
23040ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
23056858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+fv[0]]*dim+d]) - origin[d];
23066858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+fv[1]]*dim+d]) - origin[d];
23076858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+fv[3]]*dim+d]) - origin[d];
23080ec8681fSMatthew G. Knepley       }
23090ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
23106858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
23110ec8681fSMatthew G. Knepley       vsum += vtmp;
23120ec8681fSMatthew G. Knepley       if (centroid) {
23130ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23140ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
23150ec8681fSMatthew G. Knepley         }
23160ec8681fSMatthew G. Knepley       }
23170ec8681fSMatthew G. Knepley       /* Second tet */
23180ec8681fSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
23196858538eSMatthew G. Knepley         coordsTmp[0*dim+d] = PetscRealPart(coords[faces[fOff+fv[1]]*dim+d]) - origin[d];
23206858538eSMatthew G. Knepley         coordsTmp[1*dim+d] = PetscRealPart(coords[faces[fOff+fv[2]]*dim+d]) - origin[d];
23216858538eSMatthew G. Knepley         coordsTmp[2*dim+d] = PetscRealPart(coords[faces[fOff+fv[3]]*dim+d]) - origin[d];
23220ec8681fSMatthew G. Knepley       }
23230ec8681fSMatthew G. Knepley       Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
23246858538eSMatthew G. Knepley       if (flip) vtmp = -vtmp;
23250ec8681fSMatthew G. Knepley       vsum += vtmp;
23260ec8681fSMatthew G. Knepley       if (centroid) {
23270ec8681fSMatthew G. Knepley         for (d = 0; d < dim; ++d) {
23280ec8681fSMatthew G. Knepley           for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
23290ec8681fSMatthew G. Knepley         }
23300ec8681fSMatthew G. Knepley       }
23310ec8681fSMatthew G. Knepley       break;
2332793a2a13SMatthew G. Knepley     }
23330ec8681fSMatthew G. Knepley     default:
23346858538eSMatthew G. Knepley       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle face %" PetscInt_FMT " of type %s", cone[f], DMPolytopeTypes[ct]);
23350ec8681fSMatthew G. Knepley     }
23366858538eSMatthew G. Knepley     fOff += faceSizes[f];
23370ec8681fSMatthew G. Knepley   }
23386858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, order, &numFaces, &faceTypes, &faceSizes, &faces));
23396858538eSMatthew G. Knepley   PetscCall(DMPlexRestoreCellCoordinates(dm, cell, &isDG, &coordSize, &array, &coords));
23408763be8eSMatthew G. Knepley   if (vol)     *vol = PetscAbsReal(vsum);
23410ec8681fSMatthew G. Knepley   if (normal)   for (d = 0; d < dim; ++d) normal[d]    = 0.0;
23423f27a4e6SJed Brown   if (centroid) for (d = 0; d < dim; ++d) centroid[d] = centroid[d] / (vsum*4) + origin[d];
23430ec8681fSMatthew G. Knepley   PetscFunctionReturn(0);
23440ec8681fSMatthew G. Knepley }
23450ec8681fSMatthew G. Knepley 
2346834e62ceSMatthew G. Knepley /*@C
2347834e62ceSMatthew G. Knepley   DMPlexComputeCellGeometryFVM - Compute the volume for a given cell
2348834e62ceSMatthew G. Knepley 
2349d083f849SBarry Smith   Collective on dm
2350834e62ceSMatthew G. Knepley 
23514165533cSJose E. Roman   Input Parameters:
2352834e62ceSMatthew G. Knepley + dm   - the DM
2353834e62ceSMatthew G. Knepley - cell - the cell
2354834e62ceSMatthew G. Knepley 
23554165533cSJose E. Roman   Output Parameters:
2356834e62ceSMatthew G. Knepley + volume   - the cell volume
2357cc08537eSMatthew G. Knepley . centroid - the cell centroid
2358cc08537eSMatthew G. Knepley - normal - the cell normal, if appropriate
2359834e62ceSMatthew G. Knepley 
2360834e62ceSMatthew G. Knepley   Level: advanced
2361834e62ceSMatthew G. Knepley 
2362834e62ceSMatthew G. Knepley   Fortran Notes:
2363834e62ceSMatthew G. Knepley   Since it returns arrays, this routine is only available in Fortran 90, and you must
2364834e62ceSMatthew G. Knepley   include petsc.h90 in your code.
2365834e62ceSMatthew G. Knepley 
2366db781477SPatrick Sanan .seealso: `DMGetCoordinateSection()`, `DMGetCoordinates()`
2367834e62ceSMatthew G. Knepley @*/
2368cc08537eSMatthew G. Knepley PetscErrorCode DMPlexComputeCellGeometryFVM(DM dm, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
2369834e62ceSMatthew G. Knepley {
23700ec8681fSMatthew G. Knepley   PetscInt       depth, dim;
2371834e62ceSMatthew G. Knepley 
2372834e62ceSMatthew G. Knepley   PetscFunctionBegin;
23739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
23749566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
237508401ef6SPierre Jolivet   PetscCheck(depth == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh must be interpolated");
23769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPointDepth(dm, cell, &depth));
2377011ea5d8SMatthew G. Knepley   switch (depth) {
23789bf2564aSMatt McGurn   case 0:
23799566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_0D_Internal(dm, dim, cell, vol, centroid, normal));
23809bf2564aSMatt McGurn     break;
2381cc08537eSMatthew G. Knepley   case 1:
23829566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_1D_Internal(dm, dim, cell, vol, centroid, normal));
2383cc08537eSMatthew G. Knepley     break;
2384834e62ceSMatthew G. Knepley   case 2:
23859566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_2D_Internal(dm, dim, cell, vol, centroid, normal));
2386834e62ceSMatthew G. Knepley     break;
2387834e62ceSMatthew G. Knepley   case 3:
23889566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM_3D_Internal(dm, dim, cell, vol, centroid, normal));
2389834e62ceSMatthew G. Knepley     break;
2390834e62ceSMatthew G. Knepley   default:
239163a3b9bcSJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %" PetscInt_FMT " (depth %" PetscInt_FMT ") for element geometry computation", dim, depth);
2392834e62ceSMatthew G. Knepley   }
2393834e62ceSMatthew G. Knepley   PetscFunctionReturn(0);
2394834e62ceSMatthew G. Knepley }
2395113c68e6SMatthew G. Knepley 
2396c501906fSMatthew G. Knepley /*@
2397c501906fSMatthew G. Knepley   DMPlexComputeGeometryFEM - Precompute cell geometry for the entire mesh
2398c501906fSMatthew G. Knepley 
2399c501906fSMatthew G. Knepley   Collective on dm
2400c501906fSMatthew G. Knepley 
2401c501906fSMatthew G. Knepley   Input Parameter:
2402c501906fSMatthew G. Knepley . dm - The DMPlex
2403c501906fSMatthew G. Knepley 
2404c501906fSMatthew G. Knepley   Output Parameter:
2405c501906fSMatthew G. Knepley . cellgeom - A vector with the cell geometry data for each cell
2406c501906fSMatthew G. Knepley 
2407c501906fSMatthew G. Knepley   Level: beginner
2408c501906fSMatthew G. Knepley 
2409c501906fSMatthew G. Knepley @*/
2410c0d900a5SMatthew G. Knepley PetscErrorCode DMPlexComputeGeometryFEM(DM dm, Vec *cellgeom)
2411c0d900a5SMatthew G. Knepley {
2412c0d900a5SMatthew G. Knepley   DM             dmCell;
2413c0d900a5SMatthew G. Knepley   Vec            coordinates;
2414c0d900a5SMatthew G. Knepley   PetscSection   coordSection, sectionCell;
2415c0d900a5SMatthew G. Knepley   PetscScalar   *cgeom;
2416412e9a14SMatthew G. Knepley   PetscInt       cStart, cEnd, c;
2417c0d900a5SMatthew G. Knepley 
2418c0d900a5SMatthew G. Knepley   PetscFunctionBegin;
24199566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmCell));
24209566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
24219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
24229566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection));
24239566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmCell, coordinates));
24249566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionCell));
24259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
24269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd));
2427c0d900a5SMatthew G. Knepley   /* TODO This needs to be multiplied by Nq for non-affine */
24289566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFEGeom))/sizeof(PetscScalar))));
24299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionCell));
24309566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmCell, sectionCell));
24319566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionCell));
24329566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmCell, cellgeom));
24339566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*cellgeom, &cgeom));
2434c0d900a5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
2435cf0b7c11SKarl Rupp     PetscFEGeom *cg;
2436c0d900a5SMatthew G. Knepley 
24379566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmCell, c, cgeom, &cg));
24389566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(cg, 1));
24399566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dmCell, c, NULL, cg->v, cg->J, cg->invJ, cg->detJ));
244063a3b9bcSJacob Faibussowitsch     PetscCheck(*cg->detJ > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) *cg->detJ, c);
2441c0d900a5SMatthew G. Knepley   }
2442c0d900a5SMatthew G. Knepley   PetscFunctionReturn(0);
2443c0d900a5SMatthew G. Knepley }
2444c0d900a5SMatthew G. Knepley 
2445891a9168SMatthew G. Knepley /*@
2446891a9168SMatthew G. Knepley   DMPlexComputeGeometryFVM - Computes the cell and face geometry for a finite volume method
2447891a9168SMatthew G. Knepley 
2448891a9168SMatthew G. Knepley   Input Parameter:
2449891a9168SMatthew G. Knepley . dm - The DM
2450891a9168SMatthew G. Knepley 
2451891a9168SMatthew G. Knepley   Output Parameters:
2452891a9168SMatthew G. Knepley + cellgeom - A Vec of PetscFVCellGeom data
2453a2b725a8SWilliam Gropp - facegeom - A Vec of PetscFVFaceGeom data
2454891a9168SMatthew G. Knepley 
2455891a9168SMatthew G. Knepley   Level: developer
2456891a9168SMatthew G. Knepley 
2457db781477SPatrick Sanan .seealso: `PetscFVFaceGeom`, `PetscFVCellGeom`, `DMPlexComputeGeometryFEM()`
2458891a9168SMatthew G. Knepley @*/
2459113c68e6SMatthew G. Knepley PetscErrorCode DMPlexComputeGeometryFVM(DM dm, Vec *cellgeom, Vec *facegeom)
2460113c68e6SMatthew G. Knepley {
2461113c68e6SMatthew G. Knepley   DM             dmFace, dmCell;
2462113c68e6SMatthew G. Knepley   DMLabel        ghostLabel;
2463113c68e6SMatthew G. Knepley   PetscSection   sectionFace, sectionCell;
2464113c68e6SMatthew G. Knepley   PetscSection   coordSection;
2465113c68e6SMatthew G. Knepley   Vec            coordinates;
2466113c68e6SMatthew G. Knepley   PetscScalar   *fgeom, *cgeom;
2467113c68e6SMatthew G. Knepley   PetscReal      minradius, gminradius;
2468113c68e6SMatthew G. Knepley   PetscInt       dim, cStart, cEnd, cEndInterior, c, fStart, fEnd, f;
2469113c68e6SMatthew G. Knepley 
2470113c68e6SMatthew G. Knepley   PetscFunctionBegin;
24719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
24729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
24739566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
2474113c68e6SMatthew G. Knepley   /* Make cell centroids and volumes */
24759566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmCell));
24769566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection));
24779566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmCell, coordinates));
24789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionCell));
24799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
24809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
24819566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd));
24829566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVCellGeom))/sizeof(PetscScalar))));
24839566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionCell));
24849566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmCell, sectionCell));
24859566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionCell));
24869566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmCell, cellgeom));
2487485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
24889566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*cellgeom, &cgeom));
2489113c68e6SMatthew G. Knepley   for (c = cStart; c < cEndInterior; ++c) {
2490113c68e6SMatthew G. Knepley     PetscFVCellGeom *cg;
2491113c68e6SMatthew G. Knepley 
24929566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmCell, c, cgeom, &cg));
24939566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(cg, 1));
24949566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dmCell, c, &cg->volume, cg->centroid, NULL));
2495113c68e6SMatthew G. Knepley   }
2496113c68e6SMatthew G. Knepley   /* Compute face normals and minimum cell radius */
24979566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, &dmFace));
24989566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionFace));
24999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
25009566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionFace, fStart, fEnd));
25019566063dSJacob Faibussowitsch   for (f = fStart; f < fEnd; ++f) PetscCall(PetscSectionSetDof(sectionFace, f, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVFaceGeom))/sizeof(PetscScalar))));
25029566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionFace));
25039566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dmFace, sectionFace));
25049566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionFace));
25059566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(dmFace, facegeom));
25069566063dSJacob Faibussowitsch   PetscCall(VecGetArray(*facegeom, &fgeom));
25079566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2508113c68e6SMatthew G. Knepley   minradius = PETSC_MAX_REAL;
2509113c68e6SMatthew G. Knepley   for (f = fStart; f < fEnd; ++f) {
2510113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2511113c68e6SMatthew G. Knepley     PetscReal        area;
2512412e9a14SMatthew G. Knepley     const PetscInt  *cells;
2513412e9a14SMatthew G. Knepley     PetscInt         ncells, ghost = -1, d, numChildren;
2514113c68e6SMatthew G. Knepley 
25159566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
25169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
25179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &cells));
25189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &ncells));
2519412e9a14SMatthew G. Knepley     /* It is possible to get a face with no support when using partition overlap */
2520412e9a14SMatthew G. Knepley     if (!ncells || ghost >= 0 || numChildren) continue;
25219566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, f, fgeom, &fg));
25229566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFVM(dm, f, &area, fg->centroid, fg->normal));
2523113c68e6SMatthew G. Knepley     for (d = 0; d < dim; ++d) fg->normal[d] *= area;
2524113c68e6SMatthew G. Knepley     /* Flip face orientation if necessary to match ordering in support, and Update minimum radius */
2525113c68e6SMatthew G. Knepley     {
2526113c68e6SMatthew G. Knepley       PetscFVCellGeom *cL, *cR;
2527113c68e6SMatthew G. Knepley       PetscReal       *lcentroid, *rcentroid;
25280453c0cdSMatthew G. Knepley       PetscReal        l[3], r[3], v[3];
2529113c68e6SMatthew G. Knepley 
25309566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cgeom, &cL));
2531113c68e6SMatthew G. Knepley       lcentroid = cells[0] >= cEndInterior ? fg->centroid : cL->centroid;
253206348e87SToby Isaac       if (ncells > 1) {
25339566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cgeom, &cR));
2534113c68e6SMatthew G. Knepley         rcentroid = cells[1] >= cEndInterior ? fg->centroid : cR->centroid;
253506348e87SToby Isaac       }
253606348e87SToby Isaac       else {
253706348e87SToby Isaac         rcentroid = fg->centroid;
253806348e87SToby Isaac       }
25399566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, lcentroid, l));
25409566063dSJacob Faibussowitsch       PetscCall(DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, rcentroid, r));
25410453c0cdSMatthew G. Knepley       DMPlex_WaxpyD_Internal(dim, -1, l, r, v);
2542113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) < 0) {
2543113c68e6SMatthew G. Knepley         for (d = 0; d < dim; ++d) fg->normal[d] = -fg->normal[d];
2544113c68e6SMatthew G. Knepley       }
2545113c68e6SMatthew G. Knepley       if (DMPlex_DotRealD_Internal(dim, fg->normal, v) <= 0) {
254663a3b9bcSJacob 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]);
254763a3b9bcSJacob 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]);
254863a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Direction for face %" PetscInt_FMT " could not be fixed", f);
2549113c68e6SMatthew G. Knepley       }
2550113c68e6SMatthew G. Knepley       if (cells[0] < cEndInterior) {
2551113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cL->centroid, v);
2552113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2553113c68e6SMatthew G. Knepley       }
255406348e87SToby Isaac       if (ncells > 1 && cells[1] < cEndInterior) {
2555113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cR->centroid, v);
2556113c68e6SMatthew G. Knepley         minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v));
2557113c68e6SMatthew G. Knepley       }
2558113c68e6SMatthew G. Knepley     }
2559113c68e6SMatthew G. Knepley   }
25601c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&minradius, &gminradius, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm)));
25619566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMinRadius(dm, gminradius));
2562113c68e6SMatthew G. Knepley   /* Compute centroids of ghost cells */
2563113c68e6SMatthew G. Knepley   for (c = cEndInterior; c < cEnd; ++c) {
2564113c68e6SMatthew G. Knepley     PetscFVFaceGeom *fg;
2565113c68e6SMatthew G. Knepley     const PetscInt  *cone,    *support;
2566113c68e6SMatthew G. Knepley     PetscInt         coneSize, supportSize, s;
2567113c68e6SMatthew G. Knepley 
25689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dmCell, c, &coneSize));
256963a3b9bcSJacob Faibussowitsch     PetscCheck(coneSize == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %" PetscInt_FMT " has cone size %" PetscInt_FMT " != 1", c, coneSize);
25709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dmCell, c, &cone));
25719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dmCell, cone[0], &supportSize));
257263a3b9bcSJacob Faibussowitsch     PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[0], supportSize);
25739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dmCell, cone[0], &support));
25749566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRef(dmFace, cone[0], fgeom, &fg));
2575113c68e6SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
2576113c68e6SMatthew G. Knepley       /* Reflect ghost centroid across plane of face */
2577113c68e6SMatthew G. Knepley       if (support[s] == c) {
2578640bce14SSatish Balay         PetscFVCellGeom       *ci;
2579113c68e6SMatthew G. Knepley         PetscFVCellGeom       *cg;
2580113c68e6SMatthew G. Knepley         PetscReal              c2f[3], a;
2581113c68e6SMatthew G. Knepley 
25829566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, support[(s+1)%2], cgeom, &ci));
2583113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, ci->centroid, fg->centroid, c2f); /* cell to face centroid */
2584113c68e6SMatthew G. Knepley         a    = DMPlex_DotRealD_Internal(dim, c2f, fg->normal)/DMPlex_DotRealD_Internal(dim, fg->normal, fg->normal);
25859566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRef(dmCell, support[s], cgeom, &cg));
2586113c68e6SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, 2*a, fg->normal, ci->centroid, cg->centroid);
2587113c68e6SMatthew G. Knepley         cg->volume = ci->volume;
2588113c68e6SMatthew G. Knepley       }
2589113c68e6SMatthew G. Knepley     }
2590113c68e6SMatthew G. Knepley   }
25919566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*facegeom, &fgeom));
25929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(*cellgeom, &cgeom));
25939566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmCell));
25949566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmFace));
2595113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2596113c68e6SMatthew G. Knepley }
2597113c68e6SMatthew G. Knepley 
2598113c68e6SMatthew G. Knepley /*@C
2599113c68e6SMatthew G. Knepley   DMPlexGetMinRadius - Returns the minimum distance from any cell centroid to a face
2600113c68e6SMatthew G. Knepley 
2601113c68e6SMatthew G. Knepley   Not collective
2602113c68e6SMatthew G. Knepley 
26034165533cSJose E. Roman   Input Parameter:
2604113c68e6SMatthew G. Knepley . dm - the DM
2605113c68e6SMatthew G. Knepley 
26064165533cSJose E. Roman   Output Parameter:
2607a5b23f4aSJose E. Roman . minradius - the minimum cell radius
2608113c68e6SMatthew G. Knepley 
2609113c68e6SMatthew G. Knepley   Level: developer
2610113c68e6SMatthew G. Knepley 
2611db781477SPatrick Sanan .seealso: `DMGetCoordinates()`
2612113c68e6SMatthew G. Knepley @*/
2613113c68e6SMatthew G. Knepley PetscErrorCode DMPlexGetMinRadius(DM dm, PetscReal *minradius)
2614113c68e6SMatthew G. Knepley {
2615113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2616113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2617dadcf809SJacob Faibussowitsch   PetscValidRealPointer(minradius,2);
2618113c68e6SMatthew G. Knepley   *minradius = ((DM_Plex*) dm->data)->minradius;
2619113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2620113c68e6SMatthew G. Knepley }
2621113c68e6SMatthew G. Knepley 
2622113c68e6SMatthew G. Knepley /*@C
2623113c68e6SMatthew G. Knepley   DMPlexSetMinRadius - Sets the minimum distance from the cell centroid to a face
2624113c68e6SMatthew G. Knepley 
2625113c68e6SMatthew G. Knepley   Logically collective
2626113c68e6SMatthew G. Knepley 
26274165533cSJose E. Roman   Input Parameters:
2628113c68e6SMatthew G. Knepley + dm - the DM
2629a5b23f4aSJose E. Roman - minradius - the minimum cell radius
2630113c68e6SMatthew G. Knepley 
2631113c68e6SMatthew G. Knepley   Level: developer
2632113c68e6SMatthew G. Knepley 
2633db781477SPatrick Sanan .seealso: `DMSetCoordinates()`
2634113c68e6SMatthew G. Knepley @*/
2635113c68e6SMatthew G. Knepley PetscErrorCode DMPlexSetMinRadius(DM dm, PetscReal minradius)
2636113c68e6SMatthew G. Knepley {
2637113c68e6SMatthew G. Knepley   PetscFunctionBegin;
2638113c68e6SMatthew G. Knepley   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2639113c68e6SMatthew G. Knepley   ((DM_Plex*) dm->data)->minradius = minradius;
2640113c68e6SMatthew G. Knepley   PetscFunctionReturn(0);
2641113c68e6SMatthew G. Knepley }
2642856ac710SMatthew G. Knepley 
2643856ac710SMatthew G. Knepley static PetscErrorCode BuildGradientReconstruction_Internal(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2644856ac710SMatthew G. Knepley {
2645856ac710SMatthew G. Knepley   DMLabel        ghostLabel;
2646856ac710SMatthew G. Knepley   PetscScalar   *dx, *grad, **gref;
2647856ac710SMatthew G. Knepley   PetscInt       dim, cStart, cEnd, c, cEndInterior, maxNumFaces;
2648856ac710SMatthew G. Knepley 
2649856ac710SMatthew G. Knepley   PetscFunctionBegin;
26509566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
26519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
26529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2653089217ebSMatthew G. Knepley   cEndInterior = cEndInterior < 0 ? cEnd : cEndInterior;
26549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, &maxNumFaces, NULL));
26559566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
26569566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
26579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref));
2658856ac710SMatthew G. Knepley   for (c = cStart; c < cEndInterior; c++) {
2659856ac710SMatthew G. Knepley     const PetscInt        *faces;
2660856ac710SMatthew G. Knepley     PetscInt               numFaces, usedFaces, f, d;
2661640bce14SSatish Balay     PetscFVCellGeom        *cg;
2662856ac710SMatthew G. Knepley     PetscBool              boundary;
2663856ac710SMatthew G. Knepley     PetscInt               ghost;
2664856ac710SMatthew G. Knepley 
2665a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
2666a79418b7SMatt McGurn     PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2667a79418b7SMatt McGurn     if (ghost >= 0) continue;
2668a79418b7SMatt McGurn 
26699566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
26709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &numFaces));
26719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &faces));
267263a3b9bcSJacob 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);
2673856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
2674640bce14SSatish Balay       PetscFVCellGeom       *cg1;
2675856ac710SMatthew G. Knepley       PetscFVFaceGeom       *fg;
2676856ac710SMatthew G. Knepley       const PetscInt        *fcells;
2677856ac710SMatthew G. Knepley       PetscInt               ncell, side;
2678856ac710SMatthew G. Knepley 
26799566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
26809566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2681856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
26829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, faces[f], &fcells));
2683856ac710SMatthew G. Knepley       side  = (c != fcells[0]); /* c is on left=0 or right=1 of face */
2684856ac710SMatthew G. Knepley       ncell = fcells[!side];    /* the neighbor */
26859566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, faces[f], fgeom, &fg));
26869566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2687856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) dx[usedFaces*dim+d] = cg1->centroid[d] - cg->centroid[d];
2688856ac710SMatthew G. Knepley       gref[usedFaces++] = fg->grad[side];  /* Gradient reconstruction term will go here */
2689856ac710SMatthew G. Knepley     }
269028b400f6SJacob Faibussowitsch     PetscCheck(usedFaces,PETSC_COMM_SELF, PETSC_ERR_USER, "Mesh contains isolated cell (no neighbors). Is it intentional?");
26919566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, usedFaces, dx, grad));
2692856ac710SMatthew G. Knepley     for (f = 0, usedFaces = 0; f < numFaces; ++f) {
26939566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(ghostLabel, faces[f], &ghost));
26949566063dSJacob Faibussowitsch       PetscCall(DMIsBoundaryPoint(dm, faces[f], &boundary));
2695856ac710SMatthew G. Knepley       if ((ghost >= 0) || boundary) continue;
2696856ac710SMatthew G. Knepley       for (d = 0; d < dim; ++d) gref[usedFaces][d] = grad[usedFaces*dim+d];
2697856ac710SMatthew G. Knepley       ++usedFaces;
2698856ac710SMatthew G. Knepley     }
2699856ac710SMatthew G. Knepley   }
27009566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
2701856ac710SMatthew G. Knepley   PetscFunctionReturn(0);
2702856ac710SMatthew G. Knepley }
2703856ac710SMatthew G. Knepley 
2704b81db932SToby Isaac static PetscErrorCode BuildGradientReconstruction_Internal_Tree(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2705b81db932SToby Isaac {
2706b81db932SToby Isaac   DMLabel        ghostLabel;
2707b81db932SToby Isaac   PetscScalar   *dx, *grad, **gref;
2708b81db932SToby Isaac   PetscInt       dim, cStart, cEnd, c, cEndInterior, fStart, fEnd, f, nStart, nEnd, maxNumFaces = 0;
2709b81db932SToby Isaac   PetscSection   neighSec;
2710b81db932SToby Isaac   PetscInt     (*neighbors)[2];
2711b81db932SToby Isaac   PetscInt      *counter;
2712b81db932SToby Isaac 
2713b81db932SToby Isaac   PetscFunctionBegin;
27149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
27159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
27169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2717485ad865SMatthew G. Knepley   if (cEndInterior < 0) cEndInterior = cEnd;
27189566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm),&neighSec));
27199566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(neighSec,cStart,cEndInterior));
27209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
27219566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
2722b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2723b81db932SToby Isaac     const PetscInt        *fcells;
2724b81db932SToby Isaac     PetscBool              boundary;
27255bc680faSToby Isaac     PetscInt               ghost = -1;
2726b81db932SToby Isaac     PetscInt               numChildren, numCells, c;
2727b81db932SToby Isaac 
27289566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
27299566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
27309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2731b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
27329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
273306348e87SToby Isaac     if (numCells == 2) {
27349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2735b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2736b81db932SToby Isaac         PetscInt cell = fcells[c];
2737b81db932SToby Isaac 
2738e6885bbbSToby Isaac         if (cell >= cStart && cell < cEndInterior) {
27399566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(neighSec,cell,1));
2740b81db932SToby Isaac         }
2741b81db932SToby Isaac       }
2742b81db932SToby Isaac     }
274306348e87SToby Isaac   }
27449566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(neighSec));
27459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(neighSec,&maxNumFaces));
27469566063dSJacob Faibussowitsch   PetscCall(PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces));
2747b81db932SToby Isaac   nStart = 0;
27489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(neighSec,&nEnd));
27499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((nEnd-nStart),&neighbors));
27509566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEndInterior-cStart),&counter));
2751b81db932SToby Isaac   for (f = fStart; f < fEnd; f++) {
2752b81db932SToby Isaac     const PetscInt        *fcells;
2753b81db932SToby Isaac     PetscBool              boundary;
27545bc680faSToby Isaac     PetscInt               ghost = -1;
2755b81db932SToby Isaac     PetscInt               numChildren, numCells, c;
2756b81db932SToby Isaac 
27579566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, f, &ghost));
27589566063dSJacob Faibussowitsch     PetscCall(DMIsBoundaryPoint(dm, f, &boundary));
27599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
2760b81db932SToby Isaac     if ((ghost >= 0) || boundary || numChildren) continue;
27619566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numCells));
276206348e87SToby Isaac     if (numCells == 2) {
27639566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &fcells));
2764b81db932SToby Isaac       for (c = 0; c < 2; c++) {
2765b81db932SToby Isaac         PetscInt cell = fcells[c], off;
2766b81db932SToby Isaac 
2767e6885bbbSToby Isaac         if (cell >= cStart && cell < cEndInterior) {
27689566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(neighSec,cell,&off));
2769b81db932SToby Isaac           off += counter[cell - cStart]++;
2770b81db932SToby Isaac           neighbors[off][0] = f;
2771b81db932SToby Isaac           neighbors[off][1] = fcells[1 - c];
2772b81db932SToby Isaac         }
2773b81db932SToby Isaac       }
2774b81db932SToby Isaac     }
277506348e87SToby Isaac   }
27769566063dSJacob Faibussowitsch   PetscCall(PetscFree(counter));
27779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref));
2778b81db932SToby Isaac   for (c = cStart; c < cEndInterior; c++) {
2779317218b9SToby Isaac     PetscInt               numFaces, f, d, off, ghost = -1;
2780640bce14SSatish Balay     PetscFVCellGeom        *cg;
2781b81db932SToby Isaac 
27829566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg));
27839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(neighSec, c, &numFaces));
27849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(neighSec, c, &off));
2785a79418b7SMatt McGurn 
2786a79418b7SMatt McGurn     // do not attempt to compute a gradient reconstruction stencil in a ghost cell.  It will never be used
27879566063dSJacob Faibussowitsch     if (ghostLabel) PetscCall(DMLabelGetValue(ghostLabel, c, &ghost));
2788a79418b7SMatt McGurn     if (ghost >= 0) continue;
2789a79418b7SMatt McGurn 
279063a3b9bcSJacob 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);
2791b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2792640bce14SSatish Balay       PetscFVCellGeom       *cg1;
2793b81db932SToby Isaac       PetscFVFaceGeom       *fg;
2794b81db932SToby Isaac       const PetscInt        *fcells;
2795b81db932SToby Isaac       PetscInt               ncell, side, nface;
2796b81db932SToby Isaac 
2797b81db932SToby Isaac       nface = neighbors[off + f][0];
2798b81db932SToby Isaac       ncell = neighbors[off + f][1];
27999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm,nface,&fcells));
2800b81db932SToby Isaac       side  = (c != fcells[0]);
28019566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRef(dmFace, nface, fgeom, &fg));
28029566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1));
2803b81db932SToby Isaac       for (d = 0; d < dim; ++d) dx[f*dim+d] = cg1->centroid[d] - cg->centroid[d];
2804b81db932SToby Isaac       gref[f] = fg->grad[side];  /* Gradient reconstruction term will go here */
2805b81db932SToby Isaac     }
28069566063dSJacob Faibussowitsch     PetscCall(PetscFVComputeGradient(fvm, numFaces, dx, grad));
2807b81db932SToby Isaac     for (f = 0; f < numFaces; ++f) {
2808b81db932SToby Isaac       for (d = 0; d < dim; ++d) gref[f][d] = grad[f*dim+d];
2809b81db932SToby Isaac     }
2810b81db932SToby Isaac   }
28119566063dSJacob Faibussowitsch   PetscCall(PetscFree3(dx, grad, gref));
28129566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&neighSec));
28139566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighbors));
2814b81db932SToby Isaac   PetscFunctionReturn(0);
2815b81db932SToby Isaac }
2816b81db932SToby Isaac 
2817856ac710SMatthew G. Knepley /*@
2818856ac710SMatthew G. Knepley   DMPlexComputeGradientFVM - Compute geometric factors for gradient reconstruction, which are stored in the geometry data, and compute layout for gradient data
2819856ac710SMatthew G. Knepley 
2820d083f849SBarry Smith   Collective on dm
2821856ac710SMatthew G. Knepley 
28224165533cSJose E. Roman   Input Parameters:
2823856ac710SMatthew G. Knepley + dm  - The DM
2824856ac710SMatthew G. Knepley . fvm - The PetscFV
28258f9f38e3SMatthew G. Knepley - cellGeometry - The face geometry from DMPlexComputeCellGeometryFVM()
2826856ac710SMatthew G. Knepley 
28276b867d5aSJose E. Roman   Input/Output Parameter:
28286b867d5aSJose E. Roman . faceGeometry - The face geometry from DMPlexComputeFaceGeometryFVM(); on output
28296b867d5aSJose E. Roman                  the geometric factors for gradient calculation are inserted
28306b867d5aSJose E. Roman 
28316b867d5aSJose E. Roman   Output Parameter:
28326b867d5aSJose E. Roman . dmGrad - The DM describing the layout of gradient data
2833856ac710SMatthew G. Knepley 
2834856ac710SMatthew G. Knepley   Level: developer
2835856ac710SMatthew G. Knepley 
2836db781477SPatrick Sanan .seealso: `DMPlexGetFaceGeometryFVM()`, `DMPlexGetCellGeometryFVM()`
2837856ac710SMatthew G. Knepley @*/
2838856ac710SMatthew G. Knepley PetscErrorCode DMPlexComputeGradientFVM(DM dm, PetscFV fvm, Vec faceGeometry, Vec cellGeometry, DM *dmGrad)
2839856ac710SMatthew G. Knepley {
2840856ac710SMatthew G. Knepley   DM             dmFace, dmCell;
2841856ac710SMatthew G. Knepley   PetscScalar   *fgeom, *cgeom;
2842b81db932SToby Isaac   PetscSection   sectionGrad, parentSection;
2843856ac710SMatthew G. Knepley   PetscInt       dim, pdim, cStart, cEnd, cEndInterior, c;
2844856ac710SMatthew G. Knepley 
2845856ac710SMatthew G. Knepley   PetscFunctionBegin;
28469566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
28479566063dSJacob Faibussowitsch   PetscCall(PetscFVGetNumComponents(fvm, &pdim));
28489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
28499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL));
2850856ac710SMatthew G. Knepley   /* Construct the interpolant corresponding to each face from the least-square solution over the cell neighborhood */
28519566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
28529566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
28539566063dSJacob Faibussowitsch   PetscCall(VecGetArray(faceGeometry, &fgeom));
28549566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cellGeometry, &cgeom));
28559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTree(dm,&parentSection,NULL,NULL,NULL,NULL));
2856b81db932SToby Isaac   if (!parentSection) {
28579566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2858b5a3613cSMatthew G. Knepley   } else {
28599566063dSJacob Faibussowitsch     PetscCall(BuildGradientReconstruction_Internal_Tree(dm, fvm, dmFace, fgeom, dmCell, cgeom));
2860b81db932SToby Isaac   }
28619566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(faceGeometry, &fgeom));
28629566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cellGeometry, &cgeom));
2863856ac710SMatthew G. Knepley   /* Create storage for gradients */
28649566063dSJacob Faibussowitsch   PetscCall(DMClone(dm, dmGrad));
28659566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &sectionGrad));
28669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(sectionGrad, cStart, cEnd));
28679566063dSJacob Faibussowitsch   for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionGrad, c, pdim*dim));
28689566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(sectionGrad));
28699566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*dmGrad, sectionGrad));
28709566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&sectionGrad));
2871856ac710SMatthew G. Knepley   PetscFunctionReturn(0);
2872856ac710SMatthew G. Knepley }
2873b27d5b9eSToby Isaac 
2874c501906fSMatthew G. Knepley /*@
2875c501906fSMatthew G. Knepley   DMPlexGetDataFVM - Retrieve precomputed cell geometry
2876c501906fSMatthew G. Knepley 
2877d083f849SBarry Smith   Collective on dm
2878c501906fSMatthew G. Knepley 
28794165533cSJose E. Roman   Input Parameters:
2880c501906fSMatthew G. Knepley + dm  - The DM
28816b867d5aSJose E. Roman - fv  - The PetscFV
2882c501906fSMatthew G. Knepley 
2883c501906fSMatthew G. Knepley   Output Parameters:
2884c501906fSMatthew G. Knepley + cellGeometry - The cell geometry
2885c501906fSMatthew G. Knepley . faceGeometry - The face geometry
28866b867d5aSJose E. Roman - gradDM       - The gradient matrices
2887c501906fSMatthew G. Knepley 
2888c501906fSMatthew G. Knepley   Level: developer
2889c501906fSMatthew G. Knepley 
2890db781477SPatrick Sanan .seealso: `DMPlexComputeGeometryFVM()`
2891c501906fSMatthew G. Knepley @*/
2892b27d5b9eSToby Isaac PetscErrorCode DMPlexGetDataFVM(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM)
2893b27d5b9eSToby Isaac {
2894b27d5b9eSToby Isaac   PetscObject    cellgeomobj, facegeomobj;
2895b27d5b9eSToby Isaac 
2896b27d5b9eSToby Isaac   PetscFunctionBegin;
28979566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2898b27d5b9eSToby Isaac   if (!cellgeomobj) {
2899b27d5b9eSToby Isaac     Vec cellgeomInt, facegeomInt;
2900b27d5b9eSToby Isaac 
29019566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellgeomInt, &facegeomInt));
29029566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_cellgeom_fvm",(PetscObject)cellgeomInt));
29039566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_facegeom_fvm",(PetscObject)facegeomInt));
29049566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellgeomInt));
29059566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&facegeomInt));
29069566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj));
2907b27d5b9eSToby Isaac   }
29089566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_facegeom_fvm", &facegeomobj));
2909b27d5b9eSToby Isaac   if (cellgeom) *cellgeom = (Vec) cellgeomobj;
2910b27d5b9eSToby Isaac   if (facegeom) *facegeom = (Vec) facegeomobj;
2911b27d5b9eSToby Isaac   if (gradDM) {
2912b27d5b9eSToby Isaac     PetscObject gradobj;
2913b27d5b9eSToby Isaac     PetscBool   computeGradients;
2914b27d5b9eSToby Isaac 
29159566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv,&computeGradients));
2916b27d5b9eSToby Isaac     if (!computeGradients) {
2917b27d5b9eSToby Isaac       *gradDM = NULL;
2918b27d5b9eSToby Isaac       PetscFunctionReturn(0);
2919b27d5b9eSToby Isaac     }
29209566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj));
2921b27d5b9eSToby Isaac     if (!gradobj) {
2922b27d5b9eSToby Isaac       DM dmGradInt;
2923b27d5b9eSToby Isaac 
29249566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeGradientFVM(dm,fv,(Vec) facegeomobj,(Vec) cellgeomobj,&dmGradInt));
29259566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject) dm, "DMPlex_dmgrad_fvm", (PetscObject)dmGradInt));
29269566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmGradInt));
29279566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj));
2928b27d5b9eSToby Isaac     }
2929b27d5b9eSToby Isaac     *gradDM = (DM) gradobj;
2930b27d5b9eSToby Isaac   }
2931b27d5b9eSToby Isaac   PetscFunctionReturn(0);
2932b27d5b9eSToby Isaac }
2933d6143a4eSToby Isaac 
29349d150b73SToby Isaac static PetscErrorCode DMPlexCoordinatesToReference_NewtonUpdate(PetscInt dimC, PetscInt dimR, PetscScalar *J, PetscScalar *invJ, PetscScalar *work,  PetscReal *resNeg, PetscReal *guess)
29359d150b73SToby Isaac {
29369d150b73SToby Isaac   PetscInt l, m;
29379d150b73SToby Isaac 
2938cd345991SToby Isaac   PetscFunctionBeginHot;
29399d150b73SToby Isaac   if (dimC == dimR && dimR <= 3) {
29409d150b73SToby Isaac     /* invert Jacobian, multiply */
29419d150b73SToby Isaac     PetscScalar det, idet;
29429d150b73SToby Isaac 
29439d150b73SToby Isaac     switch (dimR) {
29449d150b73SToby Isaac     case 1:
29459d150b73SToby Isaac       invJ[0] = 1./ J[0];
29469d150b73SToby Isaac       break;
29479d150b73SToby Isaac     case 2:
29489d150b73SToby Isaac       det = J[0] * J[3] - J[1] * J[2];
29499d150b73SToby Isaac       idet = 1./det;
29509d150b73SToby Isaac       invJ[0] =  J[3] * idet;
29519d150b73SToby Isaac       invJ[1] = -J[1] * idet;
29529d150b73SToby Isaac       invJ[2] = -J[2] * idet;
29539d150b73SToby Isaac       invJ[3] =  J[0] * idet;
29549d150b73SToby Isaac       break;
29559d150b73SToby Isaac     case 3:
29569d150b73SToby Isaac       {
29579d150b73SToby Isaac         invJ[0] = J[4] * J[8] - J[5] * J[7];
29589d150b73SToby Isaac         invJ[1] = J[2] * J[7] - J[1] * J[8];
29599d150b73SToby Isaac         invJ[2] = J[1] * J[5] - J[2] * J[4];
29609d150b73SToby Isaac         det = invJ[0] * J[0] + invJ[1] * J[3] + invJ[2] * J[6];
29619d150b73SToby Isaac         idet = 1./det;
29629d150b73SToby Isaac         invJ[0] *= idet;
29639d150b73SToby Isaac         invJ[1] *= idet;
29649d150b73SToby Isaac         invJ[2] *= idet;
29659d150b73SToby Isaac         invJ[3]  = idet * (J[5] * J[6] - J[3] * J[8]);
29669d150b73SToby Isaac         invJ[4]  = idet * (J[0] * J[8] - J[2] * J[6]);
29679d150b73SToby Isaac         invJ[5]  = idet * (J[2] * J[3] - J[0] * J[5]);
29689d150b73SToby Isaac         invJ[6]  = idet * (J[3] * J[7] - J[4] * J[6]);
29699d150b73SToby Isaac         invJ[7]  = idet * (J[1] * J[6] - J[0] * J[7]);
29709d150b73SToby Isaac         invJ[8]  = idet * (J[0] * J[4] - J[1] * J[3]);
29719d150b73SToby Isaac       }
29729d150b73SToby Isaac       break;
29739d150b73SToby Isaac     }
29749d150b73SToby Isaac     for (l = 0; l < dimR; l++) {
29759d150b73SToby Isaac       for (m = 0; m < dimC; m++) {
2976c6e120d1SToby Isaac         guess[l] += PetscRealPart(invJ[l * dimC + m]) * resNeg[m];
29779d150b73SToby Isaac       }
29789d150b73SToby Isaac     }
29799d150b73SToby Isaac   } else {
29809d150b73SToby Isaac #if defined(PETSC_USE_COMPLEX)
29819d150b73SToby Isaac     char transpose = 'C';
29829d150b73SToby Isaac #else
29839d150b73SToby Isaac     char transpose = 'T';
29849d150b73SToby Isaac #endif
29859d150b73SToby Isaac     PetscBLASInt m = dimR;
29869d150b73SToby Isaac     PetscBLASInt n = dimC;
29879d150b73SToby Isaac     PetscBLASInt one = 1;
29889d150b73SToby Isaac     PetscBLASInt worksize = dimR * dimC, info;
29899d150b73SToby Isaac 
29909d150b73SToby Isaac     for (l = 0; l < dimC; l++) {invJ[l] = resNeg[l];}
29919d150b73SToby Isaac 
2992*792fecdfSBarry Smith     PetscCallBLAS("LAPACKgels",LAPACKgels_(&transpose,&m,&n,&one,J,&m,invJ,&n,work,&worksize, &info));
299308401ef6SPierre Jolivet     PetscCheck(info == 0,PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELS");
29949d150b73SToby Isaac 
2995c6e120d1SToby Isaac     for (l = 0; l < dimR; l++) {guess[l] += PetscRealPart(invJ[l]);}
29969d150b73SToby Isaac   }
29979d150b73SToby Isaac   PetscFunctionReturn(0);
29989d150b73SToby Isaac }
29999d150b73SToby Isaac 
30009d150b73SToby Isaac static PetscErrorCode DMPlexCoordinatesToReference_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
30019d150b73SToby Isaac {
3002c0cbe899SToby Isaac   PetscInt       coordSize, i, j, k, l, m, maxIts = 7, numV = (1 << dimR);
30039d150b73SToby Isaac   PetscScalar    *coordsScalar = NULL;
30049d150b73SToby Isaac   PetscReal      *cellData, *cellCoords, *cellCoeffs, *extJ, *resNeg;
30059d150b73SToby Isaac   PetscScalar    *J, *invJ, *work;
30069d150b73SToby Isaac 
30079d150b73SToby Isaac   PetscFunctionBegin;
30089d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
30099566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
30101dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT,dimC * (1 << dimR), coordSize);
30119566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
30129566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
30139d150b73SToby Isaac   cellCoords = &cellData[0];
30149d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
30159d150b73SToby Isaac   extJ       = &cellData[2 * coordSize];
30169d150b73SToby Isaac   resNeg     = &cellData[2 * coordSize + dimR];
30179d150b73SToby Isaac   invJ       = &J[dimR * dimC];
30189d150b73SToby Isaac   work       = &J[2 * dimR * dimC];
30199d150b73SToby Isaac   if (dimR == 2) {
30209d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
30219d150b73SToby Isaac 
30229d150b73SToby Isaac     for (i = 0; i < 4; i++) {
30239d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
30249d150b73SToby Isaac 
30259d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
30269d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
30279d150b73SToby Isaac       }
30289d150b73SToby Isaac     }
30299d150b73SToby Isaac   } else if (dimR == 3) {
30309d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
30319d150b73SToby Isaac 
30329d150b73SToby Isaac     for (i = 0; i < 8; 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 {
30409d150b73SToby Isaac     for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);}
30419d150b73SToby Isaac   }
30429d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
30439d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
30449d150b73SToby Isaac     PetscReal *swap;
30459d150b73SToby Isaac 
30469d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
30479d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
30489d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
30499d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
30509d150b73SToby Isaac       }
30519d150b73SToby Isaac     }
30529d150b73SToby Isaac 
30539d150b73SToby Isaac     if (i < dimR - 1) {
30549d150b73SToby Isaac       swap = cellCoeffs;
30559d150b73SToby Isaac       cellCoeffs = cellCoords;
30569d150b73SToby Isaac       cellCoords = swap;
30579d150b73SToby Isaac     }
30589d150b73SToby Isaac   }
30599566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(refCoords,numPoints * dimR));
30609d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
30619d150b73SToby Isaac     for (i = 0; i < maxIts; i++) {
30629d150b73SToby Isaac       PetscReal *guess = &refCoords[dimR * j];
30639d150b73SToby Isaac 
30649d150b73SToby Isaac       /* compute -residual and Jacobian */
30659d150b73SToby Isaac       for (k = 0; k < dimC; k++) {resNeg[k] = realCoords[dimC * j + k];}
30669d150b73SToby Isaac       for (k = 0; k < dimC * dimR; k++) {J[k] = 0.;}
30679d150b73SToby Isaac       for (k = 0; k < numV; k++) {
30689d150b73SToby Isaac         PetscReal extCoord = 1.;
30699d150b73SToby Isaac         for (l = 0; l < dimR; l++) {
30709d150b73SToby Isaac           PetscReal coord = guess[l];
30719d150b73SToby Isaac           PetscInt  dep   = (k & (1 << l)) >> l;
30729d150b73SToby Isaac 
30739d150b73SToby Isaac           extCoord *= dep * coord + !dep;
30749d150b73SToby Isaac           extJ[l] = dep;
30759d150b73SToby Isaac 
30769d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
30779d150b73SToby Isaac             PetscReal coord = guess[m];
30789d150b73SToby Isaac             PetscInt  dep   = ((k & (1 << m)) >> m) && (m != l);
30799d150b73SToby Isaac             PetscReal mult  = dep * coord + !dep;
30809d150b73SToby Isaac 
30819d150b73SToby Isaac             extJ[l] *= mult;
30829d150b73SToby Isaac           }
30839d150b73SToby Isaac         }
30849d150b73SToby Isaac         for (l = 0; l < dimC; l++) {
30859d150b73SToby Isaac           PetscReal coeff = cellCoeffs[dimC * k + l];
30869d150b73SToby Isaac 
30879d150b73SToby Isaac           resNeg[l] -= coeff * extCoord;
30889d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
30899d150b73SToby Isaac             J[dimR * l + m] += coeff * extJ[m];
30909d150b73SToby Isaac           }
30919d150b73SToby Isaac         }
30929d150b73SToby Isaac       }
309376bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
30940611203eSToby Isaac         PetscReal maxAbs = 0.;
30950611203eSToby Isaac 
30960611203eSToby Isaac         for (l = 0; l < dimC; l++) {
30970611203eSToby Isaac           maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l]));
30980611203eSToby Isaac         }
309963a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm,"cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n",cell,j,i,(double) maxAbs));
31000611203eSToby Isaac       }
31019d150b73SToby Isaac 
31029566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(dimC,dimR,J,invJ,work,resNeg,guess));
31039d150b73SToby Isaac     }
31049d150b73SToby Isaac   }
31059566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J));
31069566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData));
31079566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31089d150b73SToby Isaac   PetscFunctionReturn(0);
31099d150b73SToby Isaac }
31109d150b73SToby Isaac 
31119d150b73SToby Isaac static PetscErrorCode DMPlexReferenceToCoordinates_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt dimC, PetscInt dimR)
31129d150b73SToby Isaac {
31139d150b73SToby Isaac   PetscInt       coordSize, i, j, k, l, numV = (1 << dimR);
31149d150b73SToby Isaac   PetscScalar    *coordsScalar = NULL;
31159d150b73SToby Isaac   PetscReal      *cellData, *cellCoords, *cellCoeffs;
31169d150b73SToby Isaac 
31179d150b73SToby Isaac   PetscFunctionBegin;
31189d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
31199566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31201dca8a05SBarry Smith   PetscCheck(coordSize >= dimC * numV,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %" PetscInt_FMT " coordinates, got %" PetscInt_FMT,dimC * (1 << dimR), coordSize);
31219566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
31229d150b73SToby Isaac   cellCoords = &cellData[0];
31239d150b73SToby Isaac   cellCoeffs = &cellData[coordSize];
31249d150b73SToby Isaac   if (dimR == 2) {
31259d150b73SToby Isaac     const PetscInt zToPlex[4] = {0, 1, 3, 2};
31269d150b73SToby Isaac 
31279d150b73SToby Isaac     for (i = 0; i < 4; i++) {
31289d150b73SToby Isaac       PetscInt plexI = zToPlex[i];
31299d150b73SToby Isaac 
31309d150b73SToby Isaac       for (j = 0; j < dimC; j++) {
31319d150b73SToby Isaac         cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]);
31329d150b73SToby Isaac       }
31339d150b73SToby Isaac     }
31349d150b73SToby Isaac   } else if (dimR == 3) {
31359d150b73SToby Isaac     const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6};
31369d150b73SToby Isaac 
31379d150b73SToby Isaac     for (i = 0; i < 8; 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 {
31459d150b73SToby Isaac     for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);}
31469d150b73SToby Isaac   }
31479d150b73SToby Isaac   /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */
31489d150b73SToby Isaac   for (i = 0; i < dimR; i++) {
31499d150b73SToby Isaac     PetscReal *swap;
31509d150b73SToby Isaac 
31519d150b73SToby Isaac     for (j = 0; j < (numV / 2); j++) {
31529d150b73SToby Isaac       for (k = 0; k < dimC; k++) {
31539d150b73SToby Isaac         cellCoeffs[dimC * j + k]                = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]);
31549d150b73SToby Isaac         cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]);
31559d150b73SToby Isaac       }
31569d150b73SToby Isaac     }
31579d150b73SToby Isaac 
31589d150b73SToby Isaac     if (i < dimR - 1) {
31599d150b73SToby Isaac       swap = cellCoeffs;
31609d150b73SToby Isaac       cellCoeffs = cellCoords;
31619d150b73SToby Isaac       cellCoords = swap;
31629d150b73SToby Isaac     }
31639d150b73SToby Isaac   }
31649566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(realCoords,numPoints * dimC));
31659d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
31669d150b73SToby Isaac     const PetscReal *guess  = &refCoords[dimR * j];
31679d150b73SToby Isaac     PetscReal       *mapped = &realCoords[dimC * j];
31689d150b73SToby Isaac 
31699d150b73SToby Isaac     for (k = 0; k < numV; k++) {
31709d150b73SToby Isaac       PetscReal extCoord = 1.;
31719d150b73SToby Isaac       for (l = 0; l < dimR; l++) {
31729d150b73SToby Isaac         PetscReal coord = guess[l];
31739d150b73SToby Isaac         PetscInt  dep   = (k & (1 << l)) >> l;
31749d150b73SToby Isaac 
31759d150b73SToby Isaac         extCoord *= dep * coord + !dep;
31769d150b73SToby Isaac       }
31779d150b73SToby Isaac       for (l = 0; l < dimC; l++) {
31789d150b73SToby Isaac         PetscReal coeff = cellCoeffs[dimC * k + l];
31799d150b73SToby Isaac 
31809d150b73SToby Isaac         mapped[l] += coeff * extCoord;
31819d150b73SToby Isaac       }
31829d150b73SToby Isaac     }
31839d150b73SToby Isaac   }
31849566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData));
31859566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar));
31869d150b73SToby Isaac   PetscFunctionReturn(0);
31879d150b73SToby Isaac }
31889d150b73SToby Isaac 
31899c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
31909c3cf19fSMatthew 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)
31919d150b73SToby Isaac {
31929c3cf19fSMatthew G. Knepley   PetscInt       numComp, pdim, i, j, k, l, m, maxIter = 7, coordSize;
3193c6e120d1SToby Isaac   PetscScalar    *nodes = NULL;
3194c6e120d1SToby Isaac   PetscReal      *invV, *modes;
3195c6e120d1SToby Isaac   PetscReal      *B, *D, *resNeg;
3196c6e120d1SToby Isaac   PetscScalar    *J, *invJ, *work;
31979d150b73SToby Isaac 
31989d150b73SToby Isaac   PetscFunctionBegin;
31999566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32009566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
320163a3b9bcSJacob 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);
32029566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32039d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32049566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim,MPIU_REAL,&modes));
32059d150b73SToby Isaac   invV = fe->invV;
3206012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3207012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3208012b7cc6SMatthew G. Knepley     for (j = 0; j < pdim; ++j) {
3209012b7cc6SMatthew G. Knepley       modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
32109d150b73SToby Isaac     }
32119d150b73SToby Isaac   }
32129566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B));
32139c3cf19fSMatthew G. Knepley   D      = &B[pdim*Nc];
32149c3cf19fSMatthew G. Knepley   resNeg = &D[pdim*Nc * dimR];
32159566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J));
32169c3cf19fSMatthew G. Knepley   invJ = &J[Nc * dimR];
32179c3cf19fSMatthew G. Knepley   work = &invJ[Nc * dimR];
32189d150b73SToby Isaac   for (i = 0; i < numPoints * dimR; i++) {refCoords[i] = 0.;}
32199d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32209b1f03cbSToby 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 */
32219d150b73SToby Isaac       PetscReal *guess = &refCoords[j * dimR];
32229566063dSJacob Faibussowitsch       PetscCall(PetscSpaceEvaluate(fe->basisSpace, 1, guess, B, D, NULL));
32239c3cf19fSMatthew G. Knepley       for (k = 0; k < Nc; k++) {resNeg[k] = realCoords[j * Nc + k];}
32249c3cf19fSMatthew G. Knepley       for (k = 0; k < Nc * dimR; k++) {J[k] = 0.;}
32259c3cf19fSMatthew G. Knepley       for (k = 0; k < pdim; k++) {
32269c3cf19fSMatthew G. Knepley         for (l = 0; l < Nc; l++) {
3227012b7cc6SMatthew G. Knepley           resNeg[l] -= modes[k] * B[k * Nc + l];
32289d150b73SToby Isaac           for (m = 0; m < dimR; m++) {
3229012b7cc6SMatthew G. Knepley             J[l * dimR + m] += modes[k] * D[(k * Nc + l) * dimR + m];
32309d150b73SToby Isaac           }
32319d150b73SToby Isaac         }
32329d150b73SToby Isaac       }
323376bd3646SJed Brown       if (0 && PetscDefined(USE_DEBUG)) {
32340611203eSToby Isaac         PetscReal maxAbs = 0.;
32350611203eSToby Isaac 
32369c3cf19fSMatthew G. Knepley         for (l = 0; l < Nc; l++) {
32370611203eSToby Isaac           maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l]));
32380611203eSToby Isaac         }
323963a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(dm,"cell %" PetscInt_FMT ", point %" PetscInt_FMT ", iter %" PetscInt_FMT ": res %g\n",cell,j,i,(double) maxAbs));
32400611203eSToby Isaac       }
32419566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_NewtonUpdate(Nc,dimR,J,invJ,work,resNeg,guess));
32429d150b73SToby Isaac     }
32439d150b73SToby Isaac   }
32449566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J));
32459566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B));
32469566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes));
32479566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32489d150b73SToby Isaac   PetscFunctionReturn(0);
32499d150b73SToby Isaac }
32509d150b73SToby Isaac 
32519c3cf19fSMatthew G. Knepley /* TODO: TOBY please fix this for Nc > 1 */
32529c3cf19fSMatthew 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)
32539d150b73SToby Isaac {
32549c3cf19fSMatthew G. Knepley   PetscInt       numComp, pdim, i, j, k, l, coordSize;
3255c6e120d1SToby Isaac   PetscScalar    *nodes = NULL;
3256c6e120d1SToby Isaac   PetscReal      *invV, *modes;
32579d150b73SToby Isaac   PetscReal      *B;
32589d150b73SToby Isaac 
32599d150b73SToby Isaac   PetscFunctionBegin;
32609566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDimension(fe, &pdim));
32619566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &numComp));
326263a3b9bcSJacob 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);
32639566063dSJacob Faibussowitsch   PetscCall(DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32649d150b73SToby Isaac   /* convert nodes to values in the stable evaluation basis */
32659566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,pdim,MPIU_REAL,&modes));
32669d150b73SToby Isaac   invV = fe->invV;
3267012b7cc6SMatthew G. Knepley   for (i = 0; i < pdim; ++i) {
3268012b7cc6SMatthew G. Knepley     modes[i] = 0.;
3269012b7cc6SMatthew G. Knepley     for (j = 0; j < pdim; ++j) {
3270012b7cc6SMatthew G. Knepley       modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]);
32719d150b73SToby Isaac     }
32729d150b73SToby Isaac   }
32739566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B));
32749566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(fe->basisSpace, numPoints, refCoords, B, NULL, NULL));
32759c3cf19fSMatthew G. Knepley   for (i = 0; i < numPoints * Nc; i++) {realCoords[i] = 0.;}
32769d150b73SToby Isaac   for (j = 0; j < numPoints; j++) {
32779c3cf19fSMatthew G. Knepley     PetscReal *mapped = &realCoords[j * Nc];
32789d150b73SToby Isaac 
32799c3cf19fSMatthew G. Knepley     for (k = 0; k < pdim; k++) {
32809c3cf19fSMatthew G. Knepley       for (l = 0; l < Nc; l++) {
328140cf36b3SToby Isaac         mapped[l] += modes[k] * B[(j * pdim + k) * Nc + l];
32829d150b73SToby Isaac       }
32839d150b73SToby Isaac     }
32849d150b73SToby Isaac   }
32859566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B));
32869566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes));
32879566063dSJacob Faibussowitsch   PetscCall(DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes));
32889d150b73SToby Isaac   PetscFunctionReturn(0);
32899d150b73SToby Isaac }
32909d150b73SToby Isaac 
3291d6143a4eSToby Isaac /*@
3292d6143a4eSToby Isaac   DMPlexCoordinatesToReference - Pull coordinates back from the mesh to the reference element using a single element
3293d6143a4eSToby Isaac   map.  This inversion will be accurate inside the reference element, but may be inaccurate for mappings that do not
3294d6143a4eSToby Isaac   extend uniquely outside the reference cell (e.g, most non-affine maps)
3295d6143a4eSToby Isaac 
3296d6143a4eSToby Isaac   Not collective
3297d6143a4eSToby Isaac 
3298d6143a4eSToby Isaac   Input Parameters:
3299d6143a4eSToby Isaac + dm         - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or
3300d6143a4eSToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
3301d6143a4eSToby Isaac                as a multilinear map for tensor-product elements
3302d6143a4eSToby Isaac . cell       - the cell whose map is used.
3303d6143a4eSToby Isaac . numPoints  - the number of points to locate
33041b266c99SBarry Smith - realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim())
3305d6143a4eSToby Isaac 
3306d6143a4eSToby Isaac   Output Parameters:
3307d6143a4eSToby Isaac . refCoords  - (numPoints x dimension) array of reference coordinates (see DMGetDimension())
33081b266c99SBarry Smith 
33091b266c99SBarry Smith   Level: intermediate
331073c9229bSMatthew Knepley 
3311db781477SPatrick Sanan .seealso: `DMPlexReferenceToCoordinates()`
3312d6143a4eSToby Isaac @*/
3313d6143a4eSToby Isaac PetscErrorCode DMPlexCoordinatesToReference(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[])
3314d6143a4eSToby Isaac {
3315485ad865SMatthew G. Knepley   PetscInt       dimC, dimR, depth, cStart, cEnd, i;
33169d150b73SToby Isaac   DM             coordDM = NULL;
33179d150b73SToby Isaac   Vec            coords;
33189d150b73SToby Isaac   PetscFE        fe = NULL;
33199d150b73SToby Isaac 
3320d6143a4eSToby Isaac   PetscFunctionBegin;
33219d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
33229566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dimR));
33239566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&dimC));
33249d150b73SToby Isaac   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0);
33259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
33269566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm,&coords));
33279566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&coordDM));
33289d150b73SToby Isaac   if (coordDM) {
33299d150b73SToby Isaac     PetscInt coordFields;
33309d150b73SToby Isaac 
33319566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM,&coordFields));
33329d150b73SToby Isaac     if (coordFields) {
33339d150b73SToby Isaac       PetscClassId id;
33349d150b73SToby Isaac       PetscObject  disc;
33359d150b73SToby Isaac 
33369566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM,0,NULL,&disc));
33379566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
33389d150b73SToby Isaac       if (id == PETSCFE_CLASSID) {
33399d150b73SToby Isaac         fe = (PetscFE) disc;
33409d150b73SToby Isaac       }
33419d150b73SToby Isaac     }
33429d150b73SToby Isaac   }
33439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
33441dca8a05SBarry 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);
33459d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
33469d150b73SToby Isaac     PetscInt  coneSize;
33479d150b73SToby Isaac     PetscBool isSimplex, isTensor;
33489d150b73SToby Isaac 
33499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,cell,&coneSize));
33509d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
33519d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
33529d150b73SToby Isaac     if (isSimplex) {
33539d150b73SToby Isaac       PetscReal detJ, *v0, *J, *invJ;
33549d150b73SToby Isaac 
33559566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33569d150b73SToby Isaac       J    = &v0[dimC];
33579d150b73SToby Isaac       invJ = &J[dimC * dimC];
33589566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, invJ, &detJ));
33599d150b73SToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the inverse affine transformation for each point */
3360c330f8ffSToby Isaac         const PetscReal x0[3] = {-1.,-1.,-1.};
3361c330f8ffSToby Isaac 
3362c330f8ffSToby Isaac         CoordinatesRealToRef(dimC, dimR, x0, v0, invJ, &realCoords[dimC * i], &refCoords[dimR * i]);
33639d150b73SToby Isaac       }
33649566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
33659d150b73SToby Isaac     } else if (isTensor) {
33669566063dSJacob Faibussowitsch       PetscCall(DMPlexCoordinatesToReference_Tensor(coordDM, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
336763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %" PetscInt_FMT,coneSize);
33689d150b73SToby Isaac   } else {
33699566063dSJacob Faibussowitsch     PetscCall(DMPlexCoordinatesToReference_FE(coordDM, fe, cell, numPoints, realCoords, refCoords, coords, dimC, dimR));
33709d150b73SToby Isaac   }
33719d150b73SToby Isaac   PetscFunctionReturn(0);
33729d150b73SToby Isaac }
33739d150b73SToby Isaac 
33749d150b73SToby Isaac /*@
33759d150b73SToby Isaac   DMPlexReferenceToCoordinates - Map references coordinates to coordinates in the the mesh for a single element map.
33769d150b73SToby Isaac 
33779d150b73SToby Isaac   Not collective
33789d150b73SToby Isaac 
33799d150b73SToby Isaac   Input Parameters:
33809d150b73SToby Isaac + dm         - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or
33819d150b73SToby Isaac                implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or
33829d150b73SToby Isaac                as a multilinear map for tensor-product elements
33839d150b73SToby Isaac . cell       - the cell whose map is used.
33849d150b73SToby Isaac . numPoints  - the number of points to locate
3385a2b725a8SWilliam Gropp - refCoords  - (numPoints x dimension) array of reference coordinates (see DMGetDimension())
33869d150b73SToby Isaac 
33879d150b73SToby Isaac   Output Parameters:
33889d150b73SToby Isaac . realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim())
33891b266c99SBarry Smith 
33901b266c99SBarry Smith    Level: intermediate
339173c9229bSMatthew Knepley 
3392db781477SPatrick Sanan .seealso: `DMPlexCoordinatesToReference()`
33939d150b73SToby Isaac @*/
33949d150b73SToby Isaac PetscErrorCode DMPlexReferenceToCoordinates(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[])
33959d150b73SToby Isaac {
3396485ad865SMatthew G. Knepley   PetscInt       dimC, dimR, depth, cStart, cEnd, i;
33979d150b73SToby Isaac   DM             coordDM = NULL;
33989d150b73SToby Isaac   Vec            coords;
33999d150b73SToby Isaac   PetscFE        fe = NULL;
34009d150b73SToby Isaac 
34019d150b73SToby Isaac   PetscFunctionBegin;
34029d150b73SToby Isaac   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
34039566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dimR));
34049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm,&dimC));
34059d150b73SToby Isaac   if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0);
34069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
34079566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm,&coords));
34089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm,&coordDM));
34099d150b73SToby Isaac   if (coordDM) {
34109d150b73SToby Isaac     PetscInt coordFields;
34119d150b73SToby Isaac 
34129566063dSJacob Faibussowitsch     PetscCall(DMGetNumFields(coordDM,&coordFields));
34139d150b73SToby Isaac     if (coordFields) {
34149d150b73SToby Isaac       PetscClassId id;
34159d150b73SToby Isaac       PetscObject  disc;
34169d150b73SToby Isaac 
34179566063dSJacob Faibussowitsch       PetscCall(DMGetField(coordDM,0,NULL,&disc));
34189566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&id));
34199d150b73SToby Isaac       if (id == PETSCFE_CLASSID) {
34209d150b73SToby Isaac         fe = (PetscFE) disc;
34219d150b73SToby Isaac       }
34229d150b73SToby Isaac     }
34239d150b73SToby Isaac   }
34249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
34251dca8a05SBarry 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);
34269d150b73SToby Isaac   if (!fe) { /* implicit discretization: affine or multilinear */
34279d150b73SToby Isaac     PetscInt  coneSize;
34289d150b73SToby Isaac     PetscBool isSimplex, isTensor;
34299d150b73SToby Isaac 
34309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,cell,&coneSize));
34319d150b73SToby Isaac     isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE;
34329d150b73SToby Isaac     isTensor  = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE;
34339d150b73SToby Isaac     if (isSimplex) {
34349d150b73SToby Isaac       PetscReal detJ, *v0, *J;
34359d150b73SToby Isaac 
34369566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34379d150b73SToby Isaac       J    = &v0[dimC];
34389566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, NULL, &detJ));
3439c330f8ffSToby Isaac       for (i = 0; i < numPoints; i++) { /* Apply the affine transformation for each point */
3440c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
3441c330f8ffSToby Isaac 
3442c330f8ffSToby Isaac         CoordinatesRefToReal(dimC, dimR, xi0, v0, J, &refCoords[dimR * i], &realCoords[dimC * i]);
34439d150b73SToby Isaac       }
34449566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0));
34459d150b73SToby Isaac     } else if (isTensor) {
34469566063dSJacob Faibussowitsch       PetscCall(DMPlexReferenceToCoordinates_Tensor(coordDM, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
344763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %" PetscInt_FMT,coneSize);
34489d150b73SToby Isaac   } else {
34499566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceToCoordinates_FE(coordDM, fe, cell, numPoints, refCoords, realCoords, coords, dimC, dimR));
34509d150b73SToby Isaac   }
3451d6143a4eSToby Isaac   PetscFunctionReturn(0);
3452d6143a4eSToby Isaac }
34530139fca9SMatthew G. Knepley 
34540139fca9SMatthew G. Knepley /*@C
34550139fca9SMatthew G. Knepley   DMPlexRemapGeometry - This function maps the original DM coordinates to new coordinates.
34560139fca9SMatthew G. Knepley 
34570139fca9SMatthew G. Knepley   Not collective
34580139fca9SMatthew G. Knepley 
34590139fca9SMatthew G. Knepley   Input Parameters:
34600139fca9SMatthew G. Knepley + dm      - The DM
34610139fca9SMatthew G. Knepley . time    - The time
34620139fca9SMatthew G. Knepley - func    - The function transforming current coordinates to new coordaintes
34630139fca9SMatthew G. Knepley 
34640139fca9SMatthew G. Knepley    Calling sequence of func:
34650139fca9SMatthew G. Knepley $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
34660139fca9SMatthew G. Knepley $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
34670139fca9SMatthew G. Knepley $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
34680139fca9SMatthew G. Knepley $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
34690139fca9SMatthew G. Knepley 
34700139fca9SMatthew G. Knepley +  dim          - The spatial dimension
34710139fca9SMatthew G. Knepley .  Nf           - The number of input fields (here 1)
34720139fca9SMatthew G. Knepley .  NfAux        - The number of input auxiliary fields
34730139fca9SMatthew G. Knepley .  uOff         - The offset of the coordinates in u[] (here 0)
34740139fca9SMatthew G. Knepley .  uOff_x       - The offset of the coordinates in u_x[] (here 0)
34750139fca9SMatthew G. Knepley .  u            - The coordinate values at this point in space
34760139fca9SMatthew G. Knepley .  u_t          - The coordinate time derivative at this point in space (here NULL)
34770139fca9SMatthew G. Knepley .  u_x          - The coordinate derivatives at this point in space
34780139fca9SMatthew G. Knepley .  aOff         - The offset of each auxiliary field in u[]
34790139fca9SMatthew G. Knepley .  aOff_x       - The offset of each auxiliary field in u_x[]
34800139fca9SMatthew G. Knepley .  a            - The auxiliary field values at this point in space
34810139fca9SMatthew G. Knepley .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
34820139fca9SMatthew G. Knepley .  a_x          - The auxiliary field derivatives at this point in space
34830139fca9SMatthew G. Knepley .  t            - The current time
34840139fca9SMatthew G. Knepley .  x            - The coordinates of this point (here not used)
34850139fca9SMatthew G. Knepley .  numConstants - The number of constants
34860139fca9SMatthew G. Knepley .  constants    - The value of each constant
34870139fca9SMatthew G. Knepley -  f            - The new coordinates at this point in space
34880139fca9SMatthew G. Knepley 
34890139fca9SMatthew G. Knepley   Level: intermediate
34900139fca9SMatthew G. Knepley 
3491db781477SPatrick Sanan .seealso: `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMProjectFieldLocal()`, `DMProjectFieldLabelLocal()`
34920139fca9SMatthew G. Knepley @*/
34930139fca9SMatthew G. Knepley PetscErrorCode DMPlexRemapGeometry(DM dm, PetscReal time,
34940139fca9SMatthew G. Knepley                                    void (*func)(PetscInt, PetscInt, PetscInt,
34950139fca9SMatthew G. Knepley                                                 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
34960139fca9SMatthew G. Knepley                                                 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
34970139fca9SMatthew G. Knepley                                                 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
34980139fca9SMatthew G. Knepley {
34990139fca9SMatthew G. Knepley   DM             cdm;
35008bf1a49fSMatthew G. Knepley   DMField        cf;
35010139fca9SMatthew G. Knepley   Vec            lCoords, tmpCoords;
35020139fca9SMatthew G. Knepley 
35030139fca9SMatthew G. Knepley   PetscFunctionBegin;
35049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(cdm, &tmpCoords));
35079566063dSJacob Faibussowitsch   PetscCall(VecCopy(lCoords, tmpCoords));
35088bf1a49fSMatthew G. Knepley   /* We have to do the coordinate field manually right now since the coordinate DM will not have its own */
35099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &cf));
35106858538eSMatthew G. Knepley   cdm->coordinates[0].field = cf;
35119566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(cdm, time, tmpCoords, &func, INSERT_VALUES, lCoords));
35126858538eSMatthew G. Knepley   cdm->coordinates[0].field = NULL;
35139566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(cdm, &tmpCoords));
35149566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, lCoords));
35150139fca9SMatthew G. Knepley   PetscFunctionReturn(0);
35160139fca9SMatthew G. Knepley }
35170139fca9SMatthew G. Knepley 
35180139fca9SMatthew G. Knepley /* Shear applies the transformation, assuming we fix z,
35190139fca9SMatthew G. Knepley   / 1  0  m_0 \
35200139fca9SMatthew G. Knepley   | 0  1  m_1 |
35210139fca9SMatthew G. Knepley   \ 0  0   1  /
35220139fca9SMatthew G. Knepley */
35230139fca9SMatthew G. Knepley static void f0_shear(PetscInt dim, PetscInt Nf, PetscInt NfAux,
35240139fca9SMatthew G. Knepley                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
35250139fca9SMatthew G. Knepley                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
35260139fca9SMatthew G. Knepley                      PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar coords[])
35270139fca9SMatthew G. Knepley {
35280139fca9SMatthew G. Knepley   const PetscInt Nc = uOff[1]-uOff[0];
3529c1f1bd54SMatthew G. Knepley   const PetscInt ax = (PetscInt) PetscRealPart(constants[0]);
35300139fca9SMatthew G. Knepley   PetscInt       c;
35310139fca9SMatthew G. Knepley 
35320139fca9SMatthew G. Knepley   for (c = 0; c < Nc; ++c) {
35330139fca9SMatthew G. Knepley     coords[c] = u[c] + constants[c+1]*u[ax];
35340139fca9SMatthew G. Knepley   }
35350139fca9SMatthew G. Knepley }
35360139fca9SMatthew G. Knepley 
35370139fca9SMatthew G. Knepley /*@C
35380139fca9SMatthew G. Knepley   DMPlexShearGeometry - This shears the domain, meaning adds a multiple of the shear coordinate to all other coordinates.
35390139fca9SMatthew G. Knepley 
35400139fca9SMatthew G. Knepley   Not collective
35410139fca9SMatthew G. Knepley 
35420139fca9SMatthew G. Knepley   Input Parameters:
35430139fca9SMatthew G. Knepley + dm          - The DM
35443ee9839eSMatthew G. Knepley . direction   - The shear coordinate direction, e.g. 0 is the x-axis
35450139fca9SMatthew G. Knepley - multipliers - The multiplier m for each direction which is not the shear direction
35460139fca9SMatthew G. Knepley 
35470139fca9SMatthew G. Knepley   Level: intermediate
35480139fca9SMatthew G. Knepley 
3549db781477SPatrick Sanan .seealso: `DMPlexRemapGeometry()`
35500139fca9SMatthew G. Knepley @*/
35513ee9839eSMatthew G. Knepley PetscErrorCode DMPlexShearGeometry(DM dm, DMDirection direction, PetscReal multipliers[])
35520139fca9SMatthew G. Knepley {
35530139fca9SMatthew G. Knepley   DM             cdm;
35540139fca9SMatthew G. Knepley   PetscDS        cds;
35550139fca9SMatthew G. Knepley   PetscObject    obj;
35560139fca9SMatthew G. Knepley   PetscClassId   id;
35570139fca9SMatthew G. Knepley   PetscScalar   *moduli;
35583ee9839eSMatthew G. Knepley   const PetscInt dir = (PetscInt) direction;
35590139fca9SMatthew G. Knepley   PetscInt       dE, d, e;
35600139fca9SMatthew G. Knepley 
35610139fca9SMatthew G. Knepley   PetscFunctionBegin;
35629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
35639566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
35649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dE+1, &moduli));
35650139fca9SMatthew G. Knepley   moduli[0] = dir;
3566cdaaecf7SMatthew G. Knepley   for (d = 0, e = 0; d < dE; ++d) moduli[d+1] = d == dir ? 0.0 : (multipliers ? multipliers[e++] : 1.0);
35679566063dSJacob Faibussowitsch   PetscCall(DMGetDS(cdm, &cds));
35689566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
35699566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetClassId(obj, &id));
35700139fca9SMatthew G. Knepley   if (id != PETSCFE_CLASSID) {
35710139fca9SMatthew G. Knepley     Vec           lCoords;
35720139fca9SMatthew G. Knepley     PetscSection  cSection;
35730139fca9SMatthew G. Knepley     PetscScalar  *coords;
35740139fca9SMatthew G. Knepley     PetscInt      vStart, vEnd, v;
35750139fca9SMatthew G. Knepley 
35769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
35779566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &cSection));
35789566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &lCoords));
35799566063dSJacob Faibussowitsch     PetscCall(VecGetArray(lCoords, &coords));
35800139fca9SMatthew G. Knepley     for (v = vStart; v < vEnd; ++v) {
35810139fca9SMatthew G. Knepley       PetscReal ds;
35820139fca9SMatthew G. Knepley       PetscInt  off, c;
35830139fca9SMatthew G. Knepley 
35849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cSection, v, &off));
35850139fca9SMatthew G. Knepley       ds   = PetscRealPart(coords[off+dir]);
35860139fca9SMatthew G. Knepley       for (c = 0; c < dE; ++c) coords[off+c] += moduli[c]*ds;
35870139fca9SMatthew G. Knepley     }
35889566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(lCoords, &coords));
35890139fca9SMatthew G. Knepley   } else {
35909566063dSJacob Faibussowitsch     PetscCall(PetscDSSetConstants(cds, dE+1, moduli));
35919566063dSJacob Faibussowitsch     PetscCall(DMPlexRemapGeometry(dm, 0.0, f0_shear));
35920139fca9SMatthew G. Knepley   }
35939566063dSJacob Faibussowitsch   PetscCall(PetscFree(moduli));
35940139fca9SMatthew G. Knepley   PetscFunctionReturn(0);
35950139fca9SMatthew G. Knepley }
3596