Actual source code: plexgeometry.c
petsc-dev 2014-02-02
1: #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/
5: static PetscErrorCode DMPlexLocatePoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6: {
7: const PetscInt embedDim = 2;
8: PetscReal x = PetscRealPart(point[0]);
9: PetscReal y = PetscRealPart(point[1]);
10: PetscReal v0[2], J[4], invJ[4], detJ;
11: PetscReal xi, eta;
15: DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
16: xi = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
17: eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
19: if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
20: else *cell = -1;
21: return(0);
22: }
26: static PetscErrorCode DMPlexLocatePoint_General_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
27: {
28: PetscSection coordSection;
29: Vec coordsLocal;
30: PetscScalar *coords = NULL;
31: const PetscInt faces[8] = {0, 1, 1, 2, 2, 3, 3, 0};
32: PetscReal x = PetscRealPart(point[0]);
33: PetscReal y = PetscRealPart(point[1]);
34: PetscInt crossings = 0, f;
35: PetscErrorCode ierr;
38: DMGetCoordinatesLocal(dm, &coordsLocal);
39: DMGetCoordinateSection(dm, &coordSection);
40: DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);
41: for (f = 0; f < 4; ++f) {
42: PetscReal x_i = PetscRealPart(coords[faces[2*f+0]*2+0]);
43: PetscReal y_i = PetscRealPart(coords[faces[2*f+0]*2+1]);
44: PetscReal x_j = PetscRealPart(coords[faces[2*f+1]*2+0]);
45: PetscReal y_j = PetscRealPart(coords[faces[2*f+1]*2+1]);
46: PetscReal slope = (y_j - y_i) / (x_j - x_i);
47: PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
48: PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
49: PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
50: if ((cond1 || cond2) && above) ++crossings;
51: }
52: if (crossings % 2) *cell = c;
53: else *cell = -1;
54: DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);
55: return(0);
56: }
60: static PetscErrorCode DMPlexLocatePoint_Simplex_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
61: {
62: const PetscInt embedDim = 3;
63: PetscReal v0[3], J[9], invJ[9], detJ;
64: PetscReal x = PetscRealPart(point[0]);
65: PetscReal y = PetscRealPart(point[1]);
66: PetscReal z = PetscRealPart(point[2]);
67: PetscReal xi, eta, zeta;
71: DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
72: xi = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
73: eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
74: zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
76: if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
77: else *cell = -1;
78: return(0);
79: }
83: static PetscErrorCode DMPlexLocatePoint_General_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
84: {
85: PetscSection coordSection;
86: Vec coordsLocal;
87: PetscScalar *coords;
88: const PetscInt faces[24] = {0, 3, 2, 1, 5, 4, 7, 6, 3, 0, 4, 5,
89: 1, 2, 6, 7, 3, 5, 6, 2, 0, 1, 7, 4};
90: PetscBool found = PETSC_TRUE;
91: PetscInt f;
95: DMGetCoordinatesLocal(dm, &coordsLocal);
96: DMGetCoordinateSection(dm, &coordSection);
97: DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);
98: for (f = 0; f < 6; ++f) {
99: /* Check the point is under plane */
100: /* Get face normal */
101: PetscReal v_i[3];
102: PetscReal v_j[3];
103: PetscReal normal[3];
104: PetscReal pp[3];
105: PetscReal dot;
107: v_i[0] = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
108: v_i[1] = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
109: v_i[2] = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
110: v_j[0] = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
111: v_j[1] = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
112: v_j[2] = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
113: normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
114: normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
115: normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
116: pp[0] = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
117: pp[1] = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
118: pp[2] = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
119: dot = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
121: /* Check that projected point is in face (2D location problem) */
122: if (dot < 0.0) {
123: found = PETSC_FALSE;
124: break;
125: }
126: }
127: if (found) *cell = c;
128: else *cell = -1;
129: DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);
130: return(0);
131: }
135: /*
136: Need to implement using the guess
137: */
138: PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
139: {
140: PetscInt cell = -1 /*, guess = -1*/;
141: PetscInt bs, numPoints, p;
142: PetscInt dim, cStart, cEnd, cMax, c, coneSize;
143: PetscInt *cells;
144: PetscScalar *a;
148: DMPlexGetDimension(dm, &dim);
149: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
150: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
151: if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
152: VecGetLocalSize(v, &numPoints);
153: VecGetBlockSize(v, &bs);
154: VecGetArray(v, &a);
155: if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
156: numPoints /= bs;
157: PetscMalloc1(numPoints, &cells);
158: for (p = 0; p < numPoints; ++p) {
159: const PetscScalar *point = &a[p*bs];
161: switch (dim) {
162: case 2:
163: for (c = cStart; c < cEnd; ++c) {
164: DMPlexGetConeSize(dm, c, &coneSize);
165: switch (coneSize) {
166: case 3:
167: DMPlexLocatePoint_Simplex_2D_Internal(dm, point, c, &cell);
168: break;
169: case 4:
170: DMPlexLocatePoint_General_2D_Internal(dm, point, c, &cell);
171: break;
172: default:
173: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
174: }
175: if (cell >= 0) break;
176: }
177: break;
178: case 3:
179: for (c = cStart; c < cEnd; ++c) {
180: DMPlexGetConeSize(dm, c, &coneSize);
181: switch (coneSize) {
182: case 4:
183: DMPlexLocatePoint_Simplex_3D_Internal(dm, point, c, &cell);
184: break;
185: case 6:
186: DMPlexLocatePoint_General_3D_Internal(dm, point, c, &cell);
187: break;
188: default:
189: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
190: }
191: if (cell >= 0) break;
192: }
193: break;
194: default:
195: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
196: }
197: cells[p] = cell;
198: }
199: VecRestoreArray(v, &a);
200: ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);
201: return(0);
202: }
206: /*
207: DMPlexComputeProjection2Dto1D_Internal - Rewrite coordinates to be the 1D projection of the 2D
208: */
209: static PetscErrorCode DMPlexComputeProjection2Dto1D_Internal(PetscScalar coords[], PetscReal R[])
210: {
211: const PetscReal x = PetscRealPart(coords[2] - coords[0]);
212: const PetscReal y = PetscRealPart(coords[3] - coords[1]);
213: const PetscReal r = PetscSqrtReal(x*x + y*y), c = x/r, s = y/r;
216: R[0] = c; R[1] = -s;
217: R[2] = s; R[3] = c;
218: coords[0] = 0.0;
219: coords[1] = r;
220: return(0);
221: }
225: /*
226: DMPlexComputeProjection3Dto2D_Internal - Rewrite coordinates to be the 2D projection of the 3D
227: */
228: static PetscErrorCode DMPlexComputeProjection3Dto2D_Internal(PetscInt coordSize, PetscScalar coords[], PetscReal R[])
229: {
230: PetscReal x1[3], x2[3], n[3], norm;
231: PetscReal x1p[3], x2p[3], xnp[3];
232: PetscReal sqrtz, alpha;
233: const PetscInt dim = 3;
234: PetscInt d, e, p;
237: /* 0) Calculate normal vector */
238: for (d = 0; d < dim; ++d) {
239: x1[d] = PetscRealPart(coords[1*dim+d] - coords[0*dim+d]);
240: x2[d] = PetscRealPart(coords[2*dim+d] - coords[0*dim+d]);
241: }
242: n[0] = x1[1]*x2[2] - x1[2]*x2[1];
243: n[1] = x1[2]*x2[0] - x1[0]*x2[2];
244: n[2] = x1[0]*x2[1] - x1[1]*x2[0];
245: norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
246: n[0] /= norm;
247: n[1] /= norm;
248: n[2] /= norm;
249: /* 1) Take the normal vector and rotate until it is \hat z
251: Let the normal vector be <nx, ny, nz> and alpha = 1/sqrt(1 - nz^2), then
253: R = / alpha nx nz alpha ny nz -1/alpha \
254: | -alpha ny alpha nx 0 |
255: \ nx ny nz /
257: will rotate the normal vector to \hat z
258: */
259: sqrtz = PetscSqrtReal(1.0 - n[2]*n[2]);
260: /* Check for n = z */
261: if (sqrtz < 1.0e-10) {
262: if (n[2] < 0.0) {
263: if (coordSize > 9) {
264: coords[2] = PetscRealPart(coords[3*dim+0] - coords[0*dim+0]);
265: coords[3] = PetscRealPart(coords[3*dim+0] - coords[0*dim+0]);
266: coords[4] = x2[0];
267: coords[5] = x2[1];
268: coords[6] = x1[0];
269: coords[7] = x1[1];
270: } else {
271: coords[2] = x2[0];
272: coords[3] = x2[1];
273: coords[4] = x1[0];
274: coords[5] = x1[1];
275: }
276: R[0] = 1.0; R[1] = 0.0; R[2] = 0.0;
277: R[3] = 0.0; R[4] = 1.0; R[5] = 0.0;
278: R[6] = 0.0; R[7] = 0.0; R[8] = -1.0;
279: } else {
280: for (p = 3; p < coordSize/3; ++p) {
281: coords[p*2+0] = PetscRealPart(coords[p*dim+0] - coords[0*dim+0]);
282: coords[p*2+1] = PetscRealPart(coords[p*dim+1] - coords[0*dim+1]);
283: }
284: coords[2] = x1[0];
285: coords[3] = x1[1];
286: coords[4] = x2[0];
287: coords[5] = x2[1];
288: R[0] = 1.0; R[1] = 0.0; R[2] = 0.0;
289: R[3] = 0.0; R[4] = 1.0; R[5] = 0.0;
290: R[6] = 0.0; R[7] = 0.0; R[8] = 1.0;
291: }
292: coords[0] = 0.0;
293: coords[1] = 0.0;
294: return(0);
295: }
296: alpha = 1.0/sqrtz;
297: R[0] = alpha*n[0]*n[2]; R[1] = alpha*n[1]*n[2]; R[2] = -sqrtz;
298: R[3] = -alpha*n[1]; R[4] = alpha*n[0]; R[5] = 0.0;
299: R[6] = n[0]; R[7] = n[1]; R[8] = n[2];
300: for (d = 0; d < dim; ++d) {
301: x1p[d] = 0.0;
302: x2p[d] = 0.0;
303: for (e = 0; e < dim; ++e) {
304: x1p[d] += R[d*dim+e]*x1[e];
305: x2p[d] += R[d*dim+e]*x2[e];
306: }
307: }
308: if (PetscAbsReal(x1p[2]) > 1.0e-9) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid rotation calculated");
309: if (PetscAbsReal(x2p[2]) > 1.0e-9) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid rotation calculated");
310: /* 2) Project to (x, y) */
311: for (p = 3; p < coordSize/3; ++p) {
312: for (d = 0; d < dim; ++d) {
313: xnp[d] = 0.0;
314: for (e = 0; e < dim; ++e) {
315: xnp[d] += R[d*dim+e]*PetscRealPart(coords[p*dim+e] - coords[0*dim+e]);
316: }
317: if (d < dim-1) coords[p*2+d] = xnp[d];
318: }
319: }
320: coords[0] = 0.0;
321: coords[1] = 0.0;
322: coords[2] = x1p[0];
323: coords[3] = x1p[1];
324: coords[4] = x2p[0];
325: coords[5] = x2p[1];
326: /* Output R^T which rotates \hat z to the input normal */
327: for (d = 0; d < dim; ++d) {
328: for (e = d+1; e < dim; ++e) {
329: PetscReal tmp;
331: tmp = R[d*dim+e];
332: R[d*dim+e] = R[e*dim+d];
333: R[e*dim+d] = tmp;
334: }
335: }
336: return(0);
337: }
341: PETSC_STATIC_INLINE void Invert2D_Internal(PetscReal invJ[], PetscReal J[], PetscReal detJ)
342: {
343: const PetscReal invDet = 1.0/detJ;
345: invJ[0] = invDet*J[3];
346: invJ[1] = -invDet*J[1];
347: invJ[2] = -invDet*J[2];
348: invJ[3] = invDet*J[0];
349: PetscLogFlops(5.0);
350: }
354: PETSC_STATIC_INLINE void Invert3D_Internal(PetscReal invJ[], PetscReal J[], PetscReal detJ)
355: {
356: const PetscReal invDet = 1.0/detJ;
358: invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
359: invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
360: invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
361: invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
362: invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
363: invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
364: invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
365: invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
366: invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
367: PetscLogFlops(37.0);
368: }
372: PETSC_STATIC_INLINE void Det2D_Internal(PetscReal *detJ, PetscReal J[])
373: {
374: *detJ = J[0]*J[3] - J[1]*J[2];
375: PetscLogFlops(3.0);
376: }
380: PETSC_STATIC_INLINE void Det3D_Internal(PetscReal *detJ, PetscReal J[])
381: {
382: *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
383: J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
384: J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
385: PetscLogFlops(12.0);
386: }
390: PETSC_UNUSED
391: PETSC_STATIC_INLINE void Volume_Triangle_Internal(PetscReal *vol, PetscReal coords[])
392: {
393: /* Signed volume is 1/2 the determinant
395: | 1 1 1 |
396: | x0 x1 x2 |
397: | y0 y1 y2 |
399: but if x0,y0 is the origin, we have
401: | x1 x2 |
402: | y1 y2 |
403: */
404: const PetscReal x1 = coords[2] - coords[0], y1 = coords[3] - coords[1];
405: const PetscReal x2 = coords[4] - coords[0], y2 = coords[5] - coords[1];
406: PetscReal M[4], detM;
407: M[0] = x1; M[1] = x2;
408: M[2] = y1; M[3] = y2;
409: Det2D_Internal(&detM, M);
410: *vol = 0.5*detM;
411: PetscLogFlops(5.0);
412: }
416: PETSC_STATIC_INLINE void Volume_Triangle_Origin_Internal(PetscReal *vol, PetscReal coords[])
417: {
418: Det2D_Internal(vol, coords);
419: *vol *= 0.5;
420: }
424: PETSC_UNUSED
425: PETSC_STATIC_INLINE void Volume_Tetrahedron_Internal(PetscReal *vol, PetscReal coords[])
426: {
427: /* Signed volume is 1/6th of the determinant
429: | 1 1 1 1 |
430: | x0 x1 x2 x3 |
431: | y0 y1 y2 y3 |
432: | z0 z1 z2 z3 |
434: but if x0,y0,z0 is the origin, we have
436: | x1 x2 x3 |
437: | y1 y2 y3 |
438: | z1 z2 z3 |
439: */
440: const PetscReal x1 = coords[3] - coords[0], y1 = coords[4] - coords[1], z1 = coords[5] - coords[2];
441: const PetscReal x2 = coords[6] - coords[0], y2 = coords[7] - coords[1], z2 = coords[8] - coords[2];
442: const PetscReal x3 = coords[9] - coords[0], y3 = coords[10] - coords[1], z3 = coords[11] - coords[2];
443: PetscReal M[9], detM;
444: M[0] = x1; M[1] = x2; M[2] = x3;
445: M[3] = y1; M[4] = y2; M[5] = y3;
446: M[6] = z1; M[7] = z2; M[8] = z3;
447: Det3D_Internal(&detM, M);
448: *vol = -0.16666666666666666666666*detM;
449: PetscLogFlops(10.0);
450: }
454: PETSC_STATIC_INLINE void Volume_Tetrahedron_Origin_Internal(PetscReal *vol, PetscReal coords[])
455: {
456: Det3D_Internal(vol, coords);
457: *vol *= -0.16666666666666666666666;
458: }
462: static PetscErrorCode DMPlexComputeLineGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
463: {
464: PetscSection coordSection;
465: Vec coordinates;
466: PetscScalar *coords = NULL;
467: PetscInt numCoords, d;
471: DMGetCoordinatesLocal(dm, &coordinates);
472: DMGetCoordinateSection(dm, &coordSection);
473: DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
474: *detJ = 0.0;
475: if (numCoords == 4) {
476: const PetscInt dim = 2;
477: PetscReal R[4], J0;
479: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
480: DMPlexComputeProjection2Dto1D_Internal(coords, R);
481: if (J) {
482: J0 = 0.5*PetscRealPart(coords[1]);
483: J[0] = R[0]*J0; J[1] = R[1];
484: J[2] = R[2]*J0; J[3] = R[3];
485: Det2D_Internal(detJ, J);
486: }
487: if (invJ) {Invert2D_Internal(invJ, J, *detJ);}
488: } else if (numCoords == 2) {
489: const PetscInt dim = 1;
491: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
492: if (J) {
493: J[0] = 0.5*(PetscRealPart(coords[1]) - PetscRealPart(coords[0]));
494: *detJ = J[0];
495: PetscLogFlops(2.0);
496: }
497: if (invJ) {invJ[0] = 1.0/J[0]; PetscLogFlops(1.0);}
498: } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this segment is %d != 2", numCoords);
499: DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
500: return(0);
501: }
505: static PetscErrorCode DMPlexComputeTriangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
506: {
507: PetscSection coordSection;
508: Vec coordinates;
509: PetscScalar *coords = NULL;
510: PetscInt numCoords, d, f, g;
514: DMGetCoordinatesLocal(dm, &coordinates);
515: DMGetCoordinateSection(dm, &coordSection);
516: DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
517: *detJ = 0.0;
518: if (numCoords == 9) {
519: const PetscInt dim = 3;
520: PetscReal R[9], J0[9] = {1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0};
522: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
523: DMPlexComputeProjection3Dto2D_Internal(numCoords, coords, R);
524: if (J) {
525: const PetscInt pdim = 2;
527: for (d = 0; d < pdim; d++) {
528: for (f = 0; f < pdim; f++) {
529: J0[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*pdim+d]) - PetscRealPart(coords[0*pdim+d]));
530: }
531: }
532: PetscLogFlops(8.0);
533: Det3D_Internal(detJ, J0);
534: for (d = 0; d < dim; d++) {
535: for (f = 0; f < dim; f++) {
536: J[d*dim+f] = 0.0;
537: for (g = 0; g < dim; g++) {
538: J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
539: }
540: }
541: }
542: PetscLogFlops(18.0);
543: }
544: if (invJ) {Invert3D_Internal(invJ, J, *detJ);}
545: } else if (numCoords == 6) {
546: const PetscInt dim = 2;
548: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
549: if (J) {
550: for (d = 0; d < dim; d++) {
551: for (f = 0; f < dim; f++) {
552: J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
553: }
554: }
555: PetscLogFlops(8.0);
556: Det2D_Internal(detJ, J);
557: }
558: if (invJ) {Invert2D_Internal(invJ, J, *detJ);}
559: } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this triangle is %d != 6", numCoords);
560: DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
561: return(0);
562: }
566: static PetscErrorCode DMPlexComputeRectangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
567: {
568: PetscSection coordSection;
569: Vec coordinates;
570: PetscScalar *coords = NULL;
571: PetscInt numCoords, d, f, g;
575: DMGetCoordinatesLocal(dm, &coordinates);
576: DMGetCoordinateSection(dm, &coordSection);
577: DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
578: *detJ = 0.0;
579: if (numCoords == 12) {
580: const PetscInt dim = 3;
581: PetscReal R[9], J0[9] = {1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0};
583: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
584: DMPlexComputeProjection3Dto2D_Internal(numCoords, coords, R);
585: if (J) {
586: const PetscInt pdim = 2;
588: for (d = 0; d < pdim; d++) {
589: J0[d*dim+0] = 0.5*(PetscRealPart(coords[1*pdim+d]) - PetscRealPart(coords[0*pdim+d]));
590: J0[d*dim+1] = 0.5*(PetscRealPart(coords[3*pdim+d]) - PetscRealPart(coords[0*pdim+d]));
591: }
592: PetscLogFlops(8.0);
593: Det3D_Internal(detJ, J0);
594: for (d = 0; d < dim; d++) {
595: for (f = 0; f < dim; f++) {
596: J[d*dim+f] = 0.0;
597: for (g = 0; g < dim; g++) {
598: J[d*dim+f] += R[d*dim+g]*J0[g*dim+f];
599: }
600: }
601: }
602: PetscLogFlops(18.0);
603: }
604: if (invJ) {Invert3D_Internal(invJ, J, *detJ);}
605: } else if (numCoords == 8) {
606: const PetscInt dim = 2;
608: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
609: if (J) {
610: for (d = 0; d < dim; d++) {
611: J[d*dim+0] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
612: J[d*dim+1] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
613: }
614: PetscLogFlops(8.0);
615: Det2D_Internal(detJ, J);
616: }
617: if (invJ) {Invert2D_Internal(invJ, J, *detJ);}
618: } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %d != 6", numCoords);
619: DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);
620: return(0);
621: }
625: static PetscErrorCode DMPlexComputeTetrahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
626: {
627: PetscSection coordSection;
628: Vec coordinates;
629: PetscScalar *coords = NULL;
630: const PetscInt dim = 3;
631: PetscInt d;
635: DMGetCoordinatesLocal(dm, &coordinates);
636: DMGetCoordinateSection(dm, &coordSection);
637: DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);
638: *detJ = 0.0;
639: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
640: if (J) {
641: for (d = 0; d < dim; d++) {
642: /* I orient with outward face normals */
643: J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d]));
644: J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
645: J[d*dim+2] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
646: }
647: PetscLogFlops(18.0);
648: Det3D_Internal(detJ, J);
649: }
650: if (invJ) {Invert3D_Internal(invJ, J, *detJ);}
651: DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);
652: return(0);
653: }
657: static PetscErrorCode DMPlexComputeHexahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
658: {
659: PetscSection coordSection;
660: Vec coordinates;
661: PetscScalar *coords = NULL;
662: const PetscInt dim = 3;
663: PetscInt d;
667: DMGetCoordinatesLocal(dm, &coordinates);
668: DMGetCoordinateSection(dm, &coordSection);
669: DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);
670: *detJ = 0.0;
671: if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);}
672: if (J) {
673: for (d = 0; d < dim; d++) {
674: J[d*dim+0] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d]));
675: J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d]));
676: J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d]));
677: }
678: PetscLogFlops(18.0);
679: Det3D_Internal(detJ, J);
680: }
681: if (invJ) {Invert3D_Internal(invJ, J, *detJ);}
682: DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);
683: return(0);
684: }
688: /*@C
689: DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
691: Collective on DM
693: Input Arguments:
694: + dm - the DM
695: - cell - the cell
697: Output Arguments:
698: + v0 - the translation part of this affine transform
699: . J - the Jacobian of the transform from the reference element
700: . invJ - the inverse of the Jacobian
701: - detJ - the Jacobian determinant
703: Level: advanced
705: Fortran Notes:
706: Since it returns arrays, this routine is only available in Fortran 90, and you must
707: include petsc.h90 in your code.
709: .seealso: DMGetCoordinateSection(), DMGetCoordinateVec()
710: @*/
711: PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
712: {
713: PetscInt depth, dim, coneSize;
717: DMPlexGetDepth(dm, &depth);
718: DMPlexGetConeSize(dm, cell, &coneSize);
719: if (depth == 1) {
720: DMPlexGetDimension(dm, &dim);
721: switch (dim) {
722: case 1:
723: DMPlexComputeLineGeometry_Internal(dm, cell, v0, J, invJ, detJ);
724: break;
725: case 2:
726: switch (coneSize) {
727: case 3:
728: DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J, invJ, detJ);
729: break;
730: case 4:
731: DMPlexComputeRectangleGeometry_Internal(dm, cell, v0, J, invJ, detJ);
732: break;
733: default:
734: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
735: }
736: break;
737: case 3:
738: switch (coneSize) {
739: case 4:
740: DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J, invJ, detJ);
741: break;
742: case 8:
743: DMPlexComputeHexahedronGeometry_Internal(dm, cell, v0, J, invJ, detJ);
744: break;
745: default:
746: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
747: }
748: break;
749: default:
750: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
751: }
752: } else {
753: /* We need to keep a pointer to the depth label */
754: DMPlexGetLabelValue(dm, "depth", cell, &dim);
755: /* Cone size is now the number of faces */
756: switch (dim) {
757: case 1:
758: DMPlexComputeLineGeometry_Internal(dm, cell, v0, J, invJ, detJ);
759: break;
760: case 2:
761: switch (coneSize) {
762: case 3:
763: DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J, invJ, detJ);
764: break;
765: case 4:
766: DMPlexComputeRectangleGeometry_Internal(dm, cell, v0, J, invJ, detJ);
767: break;
768: default:
769: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
770: }
771: break;
772: case 3:
773: switch (coneSize) {
774: case 4:
775: DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J, invJ, detJ);
776: break;
777: case 6:
778: DMPlexComputeHexahedronGeometry_Internal(dm, cell, v0, J, invJ, detJ);
779: break;
780: default:
781: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
782: }
783: break;
784: default:
785: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
786: }
787: }
788: return(0);
789: }
793: static PetscErrorCode DMPlexComputeGeometryFVM_1D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
794: {
795: PetscSection coordSection;
796: Vec coordinates;
797: PetscScalar *coords = NULL;
798: PetscInt coordSize;
802: DMGetCoordinatesLocal(dm, &coordinates);
803: DMGetCoordinateSection(dm, &coordSection);
804: DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);
805: if (dim != 2) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "We only support 2D edges right now");
806: if (centroid) {
807: centroid[0] = 0.5*PetscRealPart(coords[0] + coords[dim+0]);
808: centroid[1] = 0.5*PetscRealPart(coords[1] + coords[dim+1]);
809: }
810: if (normal) {
811: PetscReal norm;
813: normal[0] = -PetscRealPart(coords[1] - coords[dim+1]);
814: normal[1] = PetscRealPart(coords[0] - coords[dim+0]);
815: norm = PetscSqrtReal(normal[0]*normal[0] + normal[1]*normal[1]);
816: normal[0] /= norm;
817: normal[1] /= norm;
818: }
819: if (vol) {
820: *vol = PetscSqrtReal(PetscSqr(PetscRealPart(coords[0] - coords[dim+0])) + PetscSqr(PetscRealPart(coords[1] - coords[dim+1])));
821: }
822: DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);
823: return(0);
824: }
828: /* Centroid_i = (\sum_n A_n Cn_i ) / A */
829: static PetscErrorCode DMPlexComputeGeometryFVM_2D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
830: {
831: PetscSection coordSection;
832: Vec coordinates;
833: PetscScalar *coords = NULL;
834: PetscReal vsum = 0.0, csum[3] = {0.0, 0.0, 0.0}, vtmp, ctmp[4], v0[3], R[9];
835: PetscInt tdim = 2, coordSize, numCorners, p, d, e;
839: DMGetCoordinatesLocal(dm, &coordinates);
840: DMPlexGetConeSize(dm, cell, &numCorners);
841: DMGetCoordinateSection(dm, &coordSection);
842: DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);
843: dim = coordSize/numCorners;
844: if (normal) {
845: if (dim > 2) {
846: const PetscReal x0 = PetscRealPart(coords[dim+0] - coords[0]), x1 = PetscRealPart(coords[dim*2+0] - coords[0]);
847: const PetscReal y0 = PetscRealPart(coords[dim+1] - coords[1]), y1 = PetscRealPart(coords[dim*2+1] - coords[1]);
848: const PetscReal z0 = PetscRealPart(coords[dim+2] - coords[2]), z1 = PetscRealPart(coords[dim*2+2] - coords[2]);
849: PetscReal norm;
851: v0[0] = PetscRealPart(coords[0]);
852: v0[1] = PetscRealPart(coords[1]);
853: v0[2] = PetscRealPart(coords[2]);
854: normal[0] = y0*z1 - z0*y1;
855: normal[1] = z0*x1 - x0*z1;
856: normal[2] = x0*y1 - y0*x1;
857: norm = PetscSqrtReal(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
858: normal[0] /= norm;
859: normal[1] /= norm;
860: normal[2] /= norm;
861: } else {
862: for (d = 0; d < dim; ++d) normal[d] = 0.0;
863: }
864: }
865: if (dim == 3) {DMPlexComputeProjection3Dto2D_Internal(coordSize, coords, R);}
866: for (p = 0; p < numCorners; ++p) {
867: /* Need to do this copy to get types right */
868: for (d = 0; d < tdim; ++d) {
869: ctmp[d] = PetscRealPart(coords[p*tdim+d]);
870: ctmp[tdim+d] = PetscRealPart(coords[((p+1)%numCorners)*tdim+d]);
871: }
872: Volume_Triangle_Origin_Internal(&vtmp, ctmp);
873: vsum += vtmp;
874: for (d = 0; d < tdim; ++d) {
875: csum[d] += (ctmp[d] + ctmp[tdim+d])*vtmp;
876: }
877: }
878: for (d = 0; d < tdim; ++d) {
879: csum[d] /= (tdim+1)*vsum;
880: }
881: DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);
882: if (vol) *vol = PetscAbsReal(vsum);
883: if (centroid) {
884: if (dim > 2) {
885: for (d = 0; d < dim; ++d) {
886: centroid[d] = v0[d];
887: for (e = 0; e < dim; ++e) {
888: centroid[d] += R[d*dim+e]*csum[e];
889: }
890: }
891: } else for (d = 0; d < dim; ++d) centroid[d] = csum[d];
892: }
893: return(0);
894: }
898: /* Centroid_i = (\sum_n V_n Cn_i ) / V */
899: static PetscErrorCode DMPlexComputeGeometryFVM_3D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
900: {
901: PetscSection coordSection;
902: Vec coordinates;
903: PetscScalar *coords = NULL;
904: PetscReal vsum = 0.0, vtmp, coordsTmp[3*3];
905: const PetscInt *faces, *facesO;
906: PetscInt numFaces, f, coordSize, numCorners, p, d;
907: PetscErrorCode ierr;
910: DMGetCoordinatesLocal(dm, &coordinates);
911: DMGetCoordinateSection(dm, &coordSection);
913: if (centroid) for (d = 0; d < dim; ++d) centroid[d] = 0.0;
914: DMPlexGetConeSize(dm, cell, &numFaces);
915: DMPlexGetCone(dm, cell, &faces);
916: DMPlexGetConeOrientation(dm, cell, &facesO);
917: for (f = 0; f < numFaces; ++f) {
918: DMPlexVecGetClosure(dm, coordSection, coordinates, faces[f], &coordSize, &coords);
919: numCorners = coordSize/dim;
920: switch (numCorners) {
921: case 3:
922: for (d = 0; d < dim; ++d) {
923: coordsTmp[0*dim+d] = PetscRealPart(coords[0*dim+d]);
924: coordsTmp[1*dim+d] = PetscRealPart(coords[1*dim+d]);
925: coordsTmp[2*dim+d] = PetscRealPart(coords[2*dim+d]);
926: }
927: Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
928: if (facesO[f] < 0) vtmp = -vtmp;
929: vsum += vtmp;
930: if (centroid) { /* Centroid of OABC = (a+b+c)/4 */
931: for (d = 0; d < dim; ++d) {
932: for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
933: }
934: }
935: break;
936: case 4:
937: /* DO FOR PYRAMID */
938: /* First tet */
939: for (d = 0; d < dim; ++d) {
940: coordsTmp[0*dim+d] = PetscRealPart(coords[0*dim+d]);
941: coordsTmp[1*dim+d] = PetscRealPart(coords[1*dim+d]);
942: coordsTmp[2*dim+d] = PetscRealPart(coords[3*dim+d]);
943: }
944: Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
945: if (facesO[f] < 0) vtmp = -vtmp;
946: vsum += vtmp;
947: if (centroid) {
948: for (d = 0; d < dim; ++d) {
949: for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
950: }
951: }
952: /* Second tet */
953: for (d = 0; d < dim; ++d) {
954: coordsTmp[0*dim+d] = PetscRealPart(coords[1*dim+d]);
955: coordsTmp[1*dim+d] = PetscRealPart(coords[2*dim+d]);
956: coordsTmp[2*dim+d] = PetscRealPart(coords[3*dim+d]);
957: }
958: Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp);
959: if (facesO[f] < 0) vtmp = -vtmp;
960: vsum += vtmp;
961: if (centroid) {
962: for (d = 0; d < dim; ++d) {
963: for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp;
964: }
965: }
966: break;
967: default:
968: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle faces with %d vertices", numCorners);
969: }
970: DMPlexVecRestoreClosure(dm, coordSection, coordinates, faces[f], &coordSize, &coords);
971: }
972: if (vol) *vol = PetscAbsReal(vsum);
973: if (normal) for (d = 0; d < dim; ++d) normal[d] = 0.0;
974: if (centroid) for (d = 0; d < dim; ++d) centroid[d] /= (vsum*4);
975: return(0);
976: }
980: /*@C
981: DMPlexComputeCellGeometryFVM - Compute the volume for a given cell
983: Collective on DM
985: Input Arguments:
986: + dm - the DM
987: - cell - the cell
989: Output Arguments:
990: + volume - the cell volume
991: . centroid - the cell centroid
992: - normal - the cell normal, if appropriate
994: Level: advanced
996: Fortran Notes:
997: Since it returns arrays, this routine is only available in Fortran 90, and you must
998: include petsc.h90 in your code.
1000: .seealso: DMGetCoordinateSection(), DMGetCoordinateVec()
1001: @*/
1002: PetscErrorCode DMPlexComputeCellGeometryFVM(DM dm, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[])
1003: {
1004: PetscInt depth, dim;
1008: DMPlexGetDepth(dm, &depth);
1009: DMPlexGetDimension(dm, &dim);
1010: if (depth != dim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh must be interpolated");
1011: /* We need to keep a pointer to the depth label */
1012: DMPlexGetLabelValue(dm, "depth", cell, &depth);
1013: /* Cone size is now the number of faces */
1014: switch (depth) {
1015: case 1:
1016: DMPlexComputeGeometryFVM_1D_Internal(dm, dim, cell, vol, centroid, normal);
1017: break;
1018: case 2:
1019: DMPlexComputeGeometryFVM_2D_Internal(dm, dim, cell, vol, centroid, normal);
1020: break;
1021: case 3:
1022: DMPlexComputeGeometryFVM_3D_Internal(dm, dim, cell, vol, centroid, normal);
1023: break;
1024: default:
1025: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
1026: }
1027: return(0);
1028: }