1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 3 #include <petscblaslapack.h> 4 #include <petsctime.h> 5 6 /*@ 7 DMPlexFindVertices - Try to find DAG points based on their coordinates. 8 9 Not Collective (provided DMGetCoordinatesLocalSetUp() has been called already) 10 11 Input Parameters: 12 + dm - The DMPlex object 13 . npoints - The number of sought points 14 . coords - The array of coordinates of the sought points 15 - eps - The tolerance or PETSC_DEFAULT 16 17 Output Parameters: 18 . dagPoints - The array of found DAG points, or -1 if not found 19 20 Level: intermediate 21 22 Notes: 23 The length of the array coords must be npoints * dim where dim is the spatial dimension returned by DMGetDimension(). 24 25 The output array dagPoints is NOT newly allocated; the user must pass an array of length npoints. 26 27 Each rank does the search independently; a nonnegative value is returned only if this rank's local DMPlex portion contains the point. 28 29 The tolerance is interpreted as the maximum Euclidean (L2) distance of the sought point from the specified coordinates. 30 31 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. 32 33 .seealso: DMPlexCreate(), DMGetCoordinates() 34 @*/ 35 PetscErrorCode DMPlexFindVertices(DM dm, PetscInt npoints, const PetscReal coord[], PetscReal eps, PetscInt dagPoints[]) 36 { 37 PetscInt c, dim, i, j, o, p, vStart, vEnd; 38 Vec allCoordsVec; 39 const PetscScalar *allCoords; 40 PetscReal norm; 41 PetscErrorCode ierr; 42 43 PetscFunctionBegin; 44 if (eps < 0) eps = PETSC_SQRT_MACHINE_EPSILON; 45 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 46 ierr = DMGetCoordinatesLocal(dm, &allCoordsVec);CHKERRQ(ierr); 47 ierr = VecGetArrayRead(allCoordsVec, &allCoords);CHKERRQ(ierr); 48 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 49 if (PetscDefined(USE_DEBUG)) { 50 /* check coordinate section is consistent with DM dimension */ 51 PetscSection cs; 52 PetscInt ndof; 53 54 ierr = DMGetCoordinateSection(dm, &cs);CHKERRQ(ierr); 55 for (p = vStart; p < vEnd; p++) { 56 ierr = PetscSectionGetDof(cs, p, &ndof);CHKERRQ(ierr); 57 if (PetscUnlikely(ndof != dim)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point %D: ndof = %D != %D = dim", p, ndof, dim); 58 } 59 } 60 if (eps == 0.0) { 61 for (i=0,j=0; i < npoints; i++,j+=dim) { 62 dagPoints[i] = -1; 63 for (p = vStart,o=0; p < vEnd; p++,o+=dim) { 64 for (c = 0; c < dim; c++) { 65 if (coord[j+c] != PetscRealPart(allCoords[o+c])) break; 66 } 67 if (c == dim) { 68 dagPoints[i] = p; 69 break; 70 } 71 } 72 } 73 ierr = VecRestoreArrayRead(allCoordsVec, &allCoords);CHKERRQ(ierr); 74 PetscFunctionReturn(0); 75 } 76 for (i=0,j=0; i < npoints; i++,j+=dim) { 77 dagPoints[i] = -1; 78 for (p = vStart,o=0; p < vEnd; p++,o+=dim) { 79 norm = 0.0; 80 for (c = 0; c < dim; c++) { 81 norm += PetscSqr(coord[j+c] - PetscRealPart(allCoords[o+c])); 82 } 83 norm = PetscSqrtReal(norm); 84 if (norm <= eps) { 85 dagPoints[i] = p; 86 break; 87 } 88 } 89 } 90 ierr = VecRestoreArrayRead(allCoordsVec, &allCoords);CHKERRQ(ierr); 91 PetscFunctionReturn(0); 92 } 93 94 static PetscErrorCode DMPlexGetLineIntersection_2D_Internal(const PetscReal segmentA[], const PetscReal segmentB[], PetscReal intersection[], PetscBool *hasIntersection) 95 { 96 const PetscReal p0_x = segmentA[0*2+0]; 97 const PetscReal p0_y = segmentA[0*2+1]; 98 const PetscReal p1_x = segmentA[1*2+0]; 99 const PetscReal p1_y = segmentA[1*2+1]; 100 const PetscReal p2_x = segmentB[0*2+0]; 101 const PetscReal p2_y = segmentB[0*2+1]; 102 const PetscReal p3_x = segmentB[1*2+0]; 103 const PetscReal p3_y = segmentB[1*2+1]; 104 const PetscReal s1_x = p1_x - p0_x; 105 const PetscReal s1_y = p1_y - p0_y; 106 const PetscReal s2_x = p3_x - p2_x; 107 const PetscReal s2_y = p3_y - p2_y; 108 const PetscReal denom = (-s2_x * s1_y + s1_x * s2_y); 109 110 PetscFunctionBegin; 111 *hasIntersection = PETSC_FALSE; 112 /* Non-parallel lines */ 113 if (denom != 0.0) { 114 const PetscReal s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / denom; 115 const PetscReal t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / denom; 116 117 if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { 118 *hasIntersection = PETSC_TRUE; 119 if (intersection) { 120 intersection[0] = p0_x + (t * s1_x); 121 intersection[1] = p0_y + (t * s1_y); 122 } 123 } 124 } 125 PetscFunctionReturn(0); 126 } 127 128 static PetscErrorCode DMPlexLocatePoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell) 129 { 130 const PetscInt embedDim = 2; 131 const PetscReal eps = PETSC_SQRT_MACHINE_EPSILON; 132 PetscReal x = PetscRealPart(point[0]); 133 PetscReal y = PetscRealPart(point[1]); 134 PetscReal v0[2], J[4], invJ[4], detJ; 135 PetscReal xi, eta; 136 PetscErrorCode ierr; 137 138 PetscFunctionBegin; 139 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 140 xi = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]); 141 eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]); 142 143 if ((xi >= -eps) && (eta >= -eps) && (xi + eta <= 2.0+eps)) *cell = c; 144 else *cell = DMLOCATEPOINT_POINT_NOT_FOUND; 145 PetscFunctionReturn(0); 146 } 147 148 static PetscErrorCode DMPlexClosestPoint_Simplex_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscReal cpoint[]) 149 { 150 const PetscInt embedDim = 2; 151 PetscReal x = PetscRealPart(point[0]); 152 PetscReal y = PetscRealPart(point[1]); 153 PetscReal v0[2], J[4], invJ[4], detJ; 154 PetscReal xi, eta, r; 155 PetscErrorCode ierr; 156 157 PetscFunctionBegin; 158 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 159 xi = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]); 160 eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]); 161 162 xi = PetscMax(xi, 0.0); 163 eta = PetscMax(eta, 0.0); 164 if (xi + eta > 2.0) { 165 r = (xi + eta)/2.0; 166 xi /= r; 167 eta /= r; 168 } 169 cpoint[0] = J[0*embedDim+0]*xi + J[0*embedDim+1]*eta + v0[0]; 170 cpoint[1] = J[1*embedDim+0]*xi + J[1*embedDim+1]*eta + v0[1]; 171 PetscFunctionReturn(0); 172 } 173 174 static PetscErrorCode DMPlexLocatePoint_Quad_2D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell) 175 { 176 PetscSection coordSection; 177 Vec coordsLocal; 178 PetscScalar *coords = NULL; 179 const PetscInt faces[8] = {0, 1, 1, 2, 2, 3, 3, 0}; 180 PetscReal x = PetscRealPart(point[0]); 181 PetscReal y = PetscRealPart(point[1]); 182 PetscInt crossings = 0, f; 183 PetscErrorCode ierr; 184 185 PetscFunctionBegin; 186 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 187 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 188 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr); 189 for (f = 0; f < 4; ++f) { 190 PetscReal x_i = PetscRealPart(coords[faces[2*f+0]*2+0]); 191 PetscReal y_i = PetscRealPart(coords[faces[2*f+0]*2+1]); 192 PetscReal x_j = PetscRealPart(coords[faces[2*f+1]*2+0]); 193 PetscReal y_j = PetscRealPart(coords[faces[2*f+1]*2+1]); 194 PetscReal slope = (y_j - y_i) / (x_j - x_i); 195 PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE; 196 PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE; 197 PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE; 198 if ((cond1 || cond2) && above) ++crossings; 199 } 200 if (crossings % 2) *cell = c; 201 else *cell = DMLOCATEPOINT_POINT_NOT_FOUND; 202 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr); 203 PetscFunctionReturn(0); 204 } 205 206 static PetscErrorCode DMPlexLocatePoint_Simplex_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell) 207 { 208 const PetscInt embedDim = 3; 209 PetscReal v0[3], J[9], invJ[9], detJ; 210 PetscReal x = PetscRealPart(point[0]); 211 PetscReal y = PetscRealPart(point[1]); 212 PetscReal z = PetscRealPart(point[2]); 213 PetscReal xi, eta, zeta; 214 PetscErrorCode ierr; 215 216 PetscFunctionBegin; 217 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 218 xi = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]); 219 eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]); 220 zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]); 221 222 if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c; 223 else *cell = DMLOCATEPOINT_POINT_NOT_FOUND; 224 PetscFunctionReturn(0); 225 } 226 227 static PetscErrorCode DMPlexLocatePoint_General_3D_Internal(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell) 228 { 229 PetscSection coordSection; 230 Vec coordsLocal; 231 PetscScalar *coords = NULL; 232 const PetscInt faces[24] = {0, 3, 2, 1, 5, 4, 7, 6, 3, 0, 4, 5, 233 1, 2, 6, 7, 3, 5, 6, 2, 0, 1, 7, 4}; 234 PetscBool found = PETSC_TRUE; 235 PetscInt f; 236 PetscErrorCode ierr; 237 238 PetscFunctionBegin; 239 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 240 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 241 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr); 242 for (f = 0; f < 6; ++f) { 243 /* Check the point is under plane */ 244 /* Get face normal */ 245 PetscReal v_i[3]; 246 PetscReal v_j[3]; 247 PetscReal normal[3]; 248 PetscReal pp[3]; 249 PetscReal dot; 250 251 v_i[0] = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]); 252 v_i[1] = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]); 253 v_i[2] = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]); 254 v_j[0] = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]); 255 v_j[1] = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]); 256 v_j[2] = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]); 257 normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1]; 258 normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2]; 259 normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0]; 260 pp[0] = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]); 261 pp[1] = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]); 262 pp[2] = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]); 263 dot = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2]; 264 265 /* Check that projected point is in face (2D location problem) */ 266 if (dot < 0.0) { 267 found = PETSC_FALSE; 268 break; 269 } 270 } 271 if (found) *cell = c; 272 else *cell = DMLOCATEPOINT_POINT_NOT_FOUND; 273 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr); 274 PetscFunctionReturn(0); 275 } 276 277 static PetscErrorCode PetscGridHashInitialize_Internal(PetscGridHash box, PetscInt dim, const PetscScalar point[]) 278 { 279 PetscInt d; 280 281 PetscFunctionBegin; 282 box->dim = dim; 283 for (d = 0; d < dim; ++d) box->lower[d] = box->upper[d] = PetscRealPart(point[d]); 284 PetscFunctionReturn(0); 285 } 286 287 PetscErrorCode PetscGridHashCreate(MPI_Comm comm, PetscInt dim, const PetscScalar point[], PetscGridHash *box) 288 { 289 PetscErrorCode ierr; 290 291 PetscFunctionBegin; 292 ierr = PetscMalloc1(1, box);CHKERRQ(ierr); 293 ierr = PetscGridHashInitialize_Internal(*box, dim, point);CHKERRQ(ierr); 294 PetscFunctionReturn(0); 295 } 296 297 PetscErrorCode PetscGridHashEnlarge(PetscGridHash box, const PetscScalar point[]) 298 { 299 PetscInt d; 300 301 PetscFunctionBegin; 302 for (d = 0; d < box->dim; ++d) { 303 box->lower[d] = PetscMin(box->lower[d], PetscRealPart(point[d])); 304 box->upper[d] = PetscMax(box->upper[d], PetscRealPart(point[d])); 305 } 306 PetscFunctionReturn(0); 307 } 308 309 /* 310 PetscGridHashSetGrid - Divide the grid into boxes 311 312 Not collective 313 314 Input Parameters: 315 + box - The grid hash object 316 . n - The number of boxes in each dimension, or PETSC_DETERMINE 317 - h - The box size in each dimension, only used if n[d] == PETSC_DETERMINE 318 319 Level: developer 320 321 .seealso: PetscGridHashCreate() 322 */ 323 PetscErrorCode PetscGridHashSetGrid(PetscGridHash box, const PetscInt n[], const PetscReal h[]) 324 { 325 PetscInt d; 326 327 PetscFunctionBegin; 328 for (d = 0; d < box->dim; ++d) { 329 box->extent[d] = box->upper[d] - box->lower[d]; 330 if (n[d] == PETSC_DETERMINE) { 331 box->h[d] = h[d]; 332 box->n[d] = PetscCeilReal(box->extent[d]/h[d]); 333 } else { 334 box->n[d] = n[d]; 335 box->h[d] = box->extent[d]/n[d]; 336 } 337 } 338 PetscFunctionReturn(0); 339 } 340 341 /* 342 PetscGridHashGetEnclosingBox - Find the grid boxes containing each input point 343 344 Not collective 345 346 Input Parameters: 347 + box - The grid hash object 348 . numPoints - The number of input points 349 - points - The input point coordinates 350 351 Output Parameters: 352 + dboxes - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim) 353 - boxes - An array of numPoints integers expressing the enclosing box as single number, or NULL 354 355 Level: developer 356 357 .seealso: PetscGridHashCreate() 358 */ 359 PetscErrorCode PetscGridHashGetEnclosingBox(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[]) 360 { 361 const PetscReal *lower = box->lower; 362 const PetscReal *upper = box->upper; 363 const PetscReal *h = box->h; 364 const PetscInt *n = box->n; 365 const PetscInt dim = box->dim; 366 PetscInt d, p; 367 368 PetscFunctionBegin; 369 for (p = 0; p < numPoints; ++p) { 370 for (d = 0; d < dim; ++d) { 371 PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]); 372 373 if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1; 374 if (dbox == -1 && PetscAbsReal(PetscRealPart(points[p*dim+d]) - lower[d]) < 1.0e-9) dbox = 0; 375 if (dbox < 0 || dbox >= n[d]) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input point %d (%g, %g, %g) is outside of our bounding box", 376 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); 377 dboxes[p*dim+d] = dbox; 378 } 379 if (boxes) for (d = 1, boxes[p] = dboxes[p*dim]; d < dim; ++d) boxes[p] += dboxes[p*dim+d]*n[d-1]; 380 } 381 PetscFunctionReturn(0); 382 } 383 384 /* 385 PetscGridHashGetEnclosingBoxQuery - Find the grid boxes containing each input point 386 387 Not collective 388 389 Input Parameters: 390 + box - The grid hash object 391 . numPoints - The number of input points 392 - points - The input point coordinates 393 394 Output Parameters: 395 + dboxes - An array of numPoints*dim integers expressing the enclosing box as (i_0, i_1, ..., i_dim) 396 . boxes - An array of numPoints integers expressing the enclosing box as single number, or NULL 397 - found - Flag indicating if point was located within a box 398 399 Level: developer 400 401 .seealso: PetscGridHashGetEnclosingBox() 402 */ 403 PetscErrorCode PetscGridHashGetEnclosingBoxQuery(PetscGridHash box, PetscInt numPoints, const PetscScalar points[], PetscInt dboxes[], PetscInt boxes[],PetscBool *found) 404 { 405 const PetscReal *lower = box->lower; 406 const PetscReal *upper = box->upper; 407 const PetscReal *h = box->h; 408 const PetscInt *n = box->n; 409 const PetscInt dim = box->dim; 410 PetscInt d, p; 411 412 PetscFunctionBegin; 413 *found = PETSC_FALSE; 414 for (p = 0; p < numPoints; ++p) { 415 for (d = 0; d < dim; ++d) { 416 PetscInt dbox = PetscFloorReal((PetscRealPart(points[p*dim+d]) - lower[d])/h[d]); 417 418 if (dbox == n[d] && PetscAbsReal(PetscRealPart(points[p*dim+d]) - upper[d]) < 1.0e-9) dbox = n[d]-1; 419 if (dbox < 0 || dbox >= n[d]) { 420 PetscFunctionReturn(0); 421 } 422 dboxes[p*dim+d] = dbox; 423 } 424 if (boxes) for (d = 1, boxes[p] = dboxes[p*dim]; d < dim; ++d) boxes[p] += dboxes[p*dim+d]*n[d-1]; 425 } 426 *found = PETSC_TRUE; 427 PetscFunctionReturn(0); 428 } 429 430 PetscErrorCode PetscGridHashDestroy(PetscGridHash *box) 431 { 432 PetscErrorCode ierr; 433 434 PetscFunctionBegin; 435 if (*box) { 436 ierr = PetscSectionDestroy(&(*box)->cellSection);CHKERRQ(ierr); 437 ierr = ISDestroy(&(*box)->cells);CHKERRQ(ierr); 438 ierr = DMLabelDestroy(&(*box)->cellsSparse);CHKERRQ(ierr); 439 } 440 ierr = PetscFree(*box);CHKERRQ(ierr); 441 PetscFunctionReturn(0); 442 } 443 444 PetscErrorCode DMPlexLocatePoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cellStart, PetscInt *cell) 445 { 446 DMPolytopeType ct; 447 PetscErrorCode ierr; 448 449 PetscFunctionBegin; 450 ierr = DMPlexGetCellType(dm, cellStart, &ct);CHKERRQ(ierr); 451 switch (ct) { 452 case DM_POLYTOPE_TRIANGLE: 453 ierr = DMPlexLocatePoint_Simplex_2D_Internal(dm, point, cellStart, cell);CHKERRQ(ierr);break; 454 case DM_POLYTOPE_QUADRILATERAL: 455 ierr = DMPlexLocatePoint_Quad_2D_Internal(dm, point, cellStart, cell);CHKERRQ(ierr);break; 456 case DM_POLYTOPE_TETRAHEDRON: 457 ierr = DMPlexLocatePoint_Simplex_3D_Internal(dm, point, cellStart, cell);CHKERRQ(ierr);break; 458 case DM_POLYTOPE_HEXAHEDRON: 459 ierr = DMPlexLocatePoint_General_3D_Internal(dm, point, cellStart, cell);CHKERRQ(ierr);break; 460 default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell %D with type %s", cellStart, DMPolytopeTypes[ct]); 461 } 462 PetscFunctionReturn(0); 463 } 464 465 /* 466 DMPlexClosestPoint_Internal - Returns the closest point in the cell to the given point 467 */ 468 PetscErrorCode DMPlexClosestPoint_Internal(DM dm, PetscInt dim, const PetscScalar point[], PetscInt cell, PetscReal cpoint[]) 469 { 470 DMPolytopeType ct; 471 PetscErrorCode ierr; 472 473 PetscFunctionBegin; 474 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 475 switch (ct) { 476 case DM_POLYTOPE_TRIANGLE: 477 ierr = DMPlexClosestPoint_Simplex_2D_Internal(dm, point, cell, cpoint);CHKERRQ(ierr);break; 478 #if 0 479 case DM_POLYTOPE_QUADRILATERAL: 480 ierr = DMPlexClosestPoint_General_2D_Internal(dm, point, cell, cpoint);CHKERRQ(ierr);break; 481 case DM_POLYTOPE_TETRAHEDRON: 482 ierr = DMPlexClosestPoint_Simplex_3D_Internal(dm, point, cell, cpoint);CHKERRQ(ierr);break; 483 case DM_POLYTOPE_HEXAHEDRON: 484 ierr = DMPlexClosestPoint_General_3D_Internal(dm, point, cell, cpoint);CHKERRQ(ierr);break; 485 #endif 486 default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No closest point location for cell %D with type %s", cell, DMPolytopeTypes[ct]); 487 } 488 PetscFunctionReturn(0); 489 } 490 491 /* 492 DMPlexComputeGridHash_Internal - Create a grid hash structure covering the Plex 493 494 Collective on dm 495 496 Input Parameter: 497 . dm - The Plex 498 499 Output Parameter: 500 . localBox - The grid hash object 501 502 Level: developer 503 504 .seealso: PetscGridHashCreate(), PetscGridHashGetEnclosingBox() 505 */ 506 PetscErrorCode DMPlexComputeGridHash_Internal(DM dm, PetscGridHash *localBox) 507 { 508 MPI_Comm comm; 509 PetscGridHash lbox; 510 Vec coordinates; 511 PetscSection coordSection; 512 Vec coordsLocal; 513 const PetscScalar *coords; 514 PetscInt *dboxes, *boxes; 515 PetscInt n[3] = {10, 10, 10}; 516 PetscInt dim, N, cStart, cEnd, c, i; 517 PetscErrorCode ierr; 518 519 PetscFunctionBegin; 520 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 521 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 522 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 523 if (dim != 2) SETERRQ(comm, PETSC_ERR_SUP, "I have only coded this for 2D"); 524 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 525 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 526 ierr = PetscGridHashCreate(comm, dim, coords, &lbox);CHKERRQ(ierr); 527 for (i = 0; i < N; i += dim) {ierr = PetscGridHashEnlarge(lbox, &coords[i]);CHKERRQ(ierr);} 528 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 529 ierr = PetscOptionsGetInt(NULL,NULL,"-dm_plex_hash_box_nijk",&n[0],NULL);CHKERRQ(ierr); 530 n[1] = n[0]; 531 n[2] = n[0]; 532 ierr = PetscGridHashSetGrid(lbox, n, NULL);CHKERRQ(ierr); 533 #if 0 534 /* Could define a custom reduction to merge these */ 535 ierr = MPIU_Allreduce(lbox->lower, gbox->lower, 3, MPIU_REAL, MPI_MIN, comm);CHKERRQ(ierr); 536 ierr = MPIU_Allreduce(lbox->upper, gbox->upper, 3, MPIU_REAL, MPI_MAX, comm);CHKERRQ(ierr); 537 #endif 538 /* Is there a reason to snap the local bounding box to a division of the global box? */ 539 /* Should we compute all overlaps of local boxes? We could do this with a rendevouz scheme partitioning the global box */ 540 /* Create label */ 541 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 542 ierr = DMLabelCreate(PETSC_COMM_SELF, "cells", &lbox->cellsSparse);CHKERRQ(ierr); 543 ierr = DMLabelCreateIndex(lbox->cellsSparse, cStart, cEnd);CHKERRQ(ierr); 544 /* Compute boxes which overlap each cell: https://stackoverflow.com/questions/13790208/triangle-square-intersection-test-in-2d */ 545 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 546 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 547 ierr = PetscCalloc2(16 * dim, &dboxes, 16, &boxes);CHKERRQ(ierr); 548 for (c = cStart; c < cEnd; ++c) { 549 const PetscReal *h = lbox->h; 550 PetscScalar *ccoords = NULL; 551 PetscInt csize = 0; 552 PetscScalar point[3]; 553 PetscInt dlim[6], d, e, i, j, k; 554 555 /* Find boxes enclosing each vertex */ 556 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &csize, &ccoords);CHKERRQ(ierr); 557 ierr = PetscGridHashGetEnclosingBox(lbox, csize/dim, ccoords, dboxes, boxes);CHKERRQ(ierr); 558 /* Mark cells containing the vertices */ 559 for (e = 0; e < csize/dim; ++e) {ierr = DMLabelSetValue(lbox->cellsSparse, c, boxes[e]);CHKERRQ(ierr);} 560 /* Get grid of boxes containing these */ 561 for (d = 0; d < dim; ++d) {dlim[d*2+0] = dlim[d*2+1] = dboxes[d];} 562 for (d = dim; d < 3; ++d) {dlim[d*2+0] = dlim[d*2+1] = 0;} 563 for (e = 1; e < dim+1; ++e) { 564 for (d = 0; d < dim; ++d) { 565 dlim[d*2+0] = PetscMin(dlim[d*2+0], dboxes[e*dim+d]); 566 dlim[d*2+1] = PetscMax(dlim[d*2+1], dboxes[e*dim+d]); 567 } 568 } 569 /* Check for intersection of box with cell */ 570 for (k = dlim[2*2+0], point[2] = lbox->lower[2] + k*h[2]; k <= dlim[2*2+1]; ++k, point[2] += h[2]) { 571 for (j = dlim[1*2+0], point[1] = lbox->lower[1] + j*h[1]; j <= dlim[1*2+1]; ++j, point[1] += h[1]) { 572 for (i = dlim[0*2+0], point[0] = lbox->lower[0] + i*h[0]; i <= dlim[0*2+1]; ++i, point[0] += h[0]) { 573 const PetscInt box = (k*lbox->n[1] + j)*lbox->n[0] + i; 574 PetscScalar cpoint[3]; 575 PetscInt cell, edge, ii, jj, kk; 576 577 /* Check whether cell contains any vertex of these subboxes TODO vectorize this */ 578 for (kk = 0, cpoint[2] = point[2]; kk < (dim > 2 ? 2 : 1); ++kk, cpoint[2] += h[2]) { 579 for (jj = 0, cpoint[1] = point[1]; jj < (dim > 1 ? 2 : 1); ++jj, cpoint[1] += h[1]) { 580 for (ii = 0, cpoint[0] = point[0]; ii < 2; ++ii, cpoint[0] += h[0]) { 581 582 ierr = DMPlexLocatePoint_Internal(dm, dim, cpoint, c, &cell);CHKERRQ(ierr); 583 if (cell >= 0) { ierr = DMLabelSetValue(lbox->cellsSparse, c, box);CHKERRQ(ierr); ii = jj = kk = 2;} 584 } 585 } 586 } 587 /* Check whether cell edge intersects any edge of these subboxes TODO vectorize this */ 588 for (edge = 0; edge < dim+1; ++edge) { 589 PetscReal segA[6], segB[6]; 590 591 if (PetscUnlikely(dim > 3)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected dim %d > 3",dim); 592 for (d = 0; d < dim; ++d) {segA[d] = PetscRealPart(ccoords[edge*dim+d]); segA[dim+d] = PetscRealPart(ccoords[((edge+1)%(dim+1))*dim+d]);} 593 for (kk = 0; kk < (dim > 2 ? 2 : 1); ++kk) { 594 if (dim > 2) {segB[2] = PetscRealPart(point[2]); 595 segB[dim+2] = PetscRealPart(point[2]) + kk*h[2];} 596 for (jj = 0; jj < (dim > 1 ? 2 : 1); ++jj) { 597 if (dim > 1) {segB[1] = PetscRealPart(point[1]); 598 segB[dim+1] = PetscRealPart(point[1]) + jj*h[1];} 599 for (ii = 0; ii < 2; ++ii) { 600 PetscBool intersects; 601 602 segB[0] = PetscRealPart(point[0]); 603 segB[dim+0] = PetscRealPart(point[0]) + ii*h[0]; 604 ierr = DMPlexGetLineIntersection_2D_Internal(segA, segB, NULL, &intersects);CHKERRQ(ierr); 605 if (intersects) { ierr = DMLabelSetValue(lbox->cellsSparse, c, box);CHKERRQ(ierr); edge = ii = jj = kk = dim+1;} 606 } 607 } 608 } 609 } 610 } 611 } 612 } 613 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &ccoords);CHKERRQ(ierr); 614 } 615 ierr = PetscFree2(dboxes, boxes);CHKERRQ(ierr); 616 ierr = DMLabelConvertToSection(lbox->cellsSparse, &lbox->cellSection, &lbox->cells);CHKERRQ(ierr); 617 ierr = DMLabelDestroy(&lbox->cellsSparse);CHKERRQ(ierr); 618 *localBox = lbox; 619 PetscFunctionReturn(0); 620 } 621 622 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, DMPointLocationType ltype, PetscSF cellSF) 623 { 624 DM_Plex *mesh = (DM_Plex *) dm->data; 625 PetscBool hash = mesh->useHashLocation, reuse = PETSC_FALSE; 626 PetscInt bs, numPoints, p, numFound, *found = NULL; 627 PetscInt dim, cStart, cEnd, numCells, c, d; 628 const PetscInt *boxCells; 629 PetscSFNode *cells; 630 PetscScalar *a; 631 PetscMPIInt result; 632 PetscLogDouble t0,t1; 633 PetscReal gmin[3],gmax[3]; 634 PetscInt terminating_query_type[] = { 0, 0, 0 }; 635 PetscErrorCode ierr; 636 637 PetscFunctionBegin; 638 ierr = PetscTime(&t0);CHKERRQ(ierr); 639 if (ltype == DM_POINTLOCATION_NEAREST && !hash) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Nearest point location only supported with grid hashing. Use -dm_plex_hash_location to enable it."); 640 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 641 ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr); 642 ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)cellSF),PETSC_COMM_SELF,&result);CHKERRQ(ierr); 643 if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PetscObjectComm((PetscObject)cellSF),PETSC_ERR_SUP, "Trying parallel point location: only local point location supported"); 644 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); 645 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 646 ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr); 647 ierr = VecGetArray(v, &a);CHKERRQ(ierr); 648 numPoints /= bs; 649 { 650 const PetscSFNode *sf_cells; 651 652 ierr = PetscSFGetGraph(cellSF,NULL,NULL,NULL,&sf_cells);CHKERRQ(ierr); 653 if (sf_cells) { 654 ierr = PetscInfo(dm,"[DMLocatePoints_Plex] Re-using existing StarForest node list\n");CHKERRQ(ierr); 655 cells = (PetscSFNode*)sf_cells; 656 reuse = PETSC_TRUE; 657 } else { 658 ierr = PetscInfo(dm,"[DMLocatePoints_Plex] Creating and initializing new StarForest node list\n");CHKERRQ(ierr); 659 ierr = PetscMalloc1(numPoints, &cells);CHKERRQ(ierr); 660 /* initialize cells if created */ 661 for (p=0; p<numPoints; p++) { 662 cells[p].rank = 0; 663 cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND; 664 } 665 } 666 } 667 /* define domain bounding box */ 668 { 669 Vec coorglobal; 670 671 ierr = DMGetCoordinates(dm,&coorglobal);CHKERRQ(ierr); 672 ierr = VecStrideMaxAll(coorglobal,NULL,gmax);CHKERRQ(ierr); 673 ierr = VecStrideMinAll(coorglobal,NULL,gmin);CHKERRQ(ierr); 674 } 675 if (hash) { 676 if (!mesh->lbox) {ierr = PetscInfo(dm, "Initializing grid hashing");CHKERRQ(ierr);ierr = DMPlexComputeGridHash_Internal(dm, &mesh->lbox);CHKERRQ(ierr);} 677 /* Designate the local box for each point */ 678 /* Send points to correct process */ 679 /* Search cells that lie in each subbox */ 680 /* Should we bin points before doing search? */ 681 ierr = ISGetIndices(mesh->lbox->cells, &boxCells);CHKERRQ(ierr); 682 } 683 for (p = 0, numFound = 0; p < numPoints; ++p) { 684 const PetscScalar *point = &a[p*bs]; 685 PetscInt dbin[3] = {-1,-1,-1}, bin, cell = -1, cellOffset; 686 PetscBool point_outside_domain = PETSC_FALSE; 687 688 /* check bounding box of domain */ 689 for (d=0; d<dim; d++) { 690 if (PetscRealPart(point[d]) < gmin[d]) { point_outside_domain = PETSC_TRUE; break; } 691 if (PetscRealPart(point[d]) > gmax[d]) { point_outside_domain = PETSC_TRUE; break; } 692 } 693 if (point_outside_domain) { 694 cells[p].rank = 0; 695 cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND; 696 terminating_query_type[0]++; 697 continue; 698 } 699 700 /* check initial values in cells[].index - abort early if found */ 701 if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) { 702 c = cells[p].index; 703 cells[p].index = DMLOCATEPOINT_POINT_NOT_FOUND; 704 ierr = DMPlexLocatePoint_Internal(dm, dim, point, c, &cell);CHKERRQ(ierr); 705 if (cell >= 0) { 706 cells[p].rank = 0; 707 cells[p].index = cell; 708 numFound++; 709 } 710 } 711 if (cells[p].index != DMLOCATEPOINT_POINT_NOT_FOUND) { 712 terminating_query_type[1]++; 713 continue; 714 } 715 716 if (hash) { 717 PetscBool found_box; 718 719 /* allow for case that point is outside box - abort early */ 720 ierr = PetscGridHashGetEnclosingBoxQuery(mesh->lbox, 1, point, dbin, &bin,&found_box);CHKERRQ(ierr); 721 if (found_box) { 722 /* TODO Lay an interface over this so we can switch between Section (dense) and Label (sparse) */ 723 ierr = PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells);CHKERRQ(ierr); 724 ierr = PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset);CHKERRQ(ierr); 725 for (c = cellOffset; c < cellOffset + numCells; ++c) { 726 ierr = DMPlexLocatePoint_Internal(dm, dim, point, boxCells[c], &cell);CHKERRQ(ierr); 727 if (cell >= 0) { 728 cells[p].rank = 0; 729 cells[p].index = cell; 730 numFound++; 731 terminating_query_type[2]++; 732 break; 733 } 734 } 735 } 736 } else { 737 for (c = cStart; c < cEnd; ++c) { 738 ierr = DMPlexLocatePoint_Internal(dm, dim, point, c, &cell);CHKERRQ(ierr); 739 if (cell >= 0) { 740 cells[p].rank = 0; 741 cells[p].index = cell; 742 numFound++; 743 terminating_query_type[2]++; 744 break; 745 } 746 } 747 } 748 } 749 if (hash) {ierr = ISRestoreIndices(mesh->lbox->cells, &boxCells);CHKERRQ(ierr);} 750 if (ltype == DM_POINTLOCATION_NEAREST && hash && numFound < numPoints) { 751 for (p = 0; p < numPoints; p++) { 752 const PetscScalar *point = &a[p*bs]; 753 PetscReal cpoint[3], diff[3], dist, distMax = PETSC_MAX_REAL; 754 PetscInt dbin[3] = {-1,-1,-1}, bin, cellOffset, d; 755 756 if (cells[p].index < 0) { 757 ++numFound; 758 ierr = PetscGridHashGetEnclosingBox(mesh->lbox, 1, point, dbin, &bin);CHKERRQ(ierr); 759 ierr = PetscSectionGetDof(mesh->lbox->cellSection, bin, &numCells);CHKERRQ(ierr); 760 ierr = PetscSectionGetOffset(mesh->lbox->cellSection, bin, &cellOffset);CHKERRQ(ierr); 761 for (c = cellOffset; c < cellOffset + numCells; ++c) { 762 ierr = DMPlexClosestPoint_Internal(dm, dim, point, boxCells[c], cpoint);CHKERRQ(ierr); 763 for (d = 0; d < dim; ++d) diff[d] = cpoint[d] - PetscRealPart(point[d]); 764 dist = DMPlex_NormD_Internal(dim, diff); 765 if (dist < distMax) { 766 for (d = 0; d < dim; ++d) a[p*bs+d] = cpoint[d]; 767 cells[p].rank = 0; 768 cells[p].index = boxCells[c]; 769 distMax = dist; 770 break; 771 } 772 } 773 } 774 } 775 } 776 /* This code is only be relevant when interfaced to parallel point location */ 777 /* Check for highest numbered proc that claims a point (do we care?) */ 778 if (ltype == DM_POINTLOCATION_REMOVE && numFound < numPoints) { 779 ierr = PetscMalloc1(numFound,&found);CHKERRQ(ierr); 780 for (p = 0, numFound = 0; p < numPoints; p++) { 781 if (cells[p].rank >= 0 && cells[p].index >= 0) { 782 if (numFound < p) { 783 cells[numFound] = cells[p]; 784 } 785 found[numFound++] = p; 786 } 787 } 788 } 789 ierr = VecRestoreArray(v, &a);CHKERRQ(ierr); 790 if (!reuse) { 791 ierr = PetscSFSetGraph(cellSF, cEnd - cStart, numFound, found, PETSC_OWN_POINTER, cells, PETSC_OWN_POINTER);CHKERRQ(ierr); 792 } 793 ierr = PetscTime(&t1);CHKERRQ(ierr); 794 if (hash) { 795 ierr = PetscInfo3(dm,"[DMLocatePoints_Plex] terminating_query_type : %D [outside domain] : %D [inside initial cell] : %D [hash]\n",terminating_query_type[0],terminating_query_type[1],terminating_query_type[2]);CHKERRQ(ierr); 796 } else { 797 ierr = PetscInfo3(dm,"[DMLocatePoints_Plex] terminating_query_type : %D [outside domain] : %D [inside initial cell] : %D [brute-force]\n",terminating_query_type[0],terminating_query_type[1],terminating_query_type[2]);CHKERRQ(ierr); 798 } 799 ierr = PetscInfo3(dm,"[DMLocatePoints_Plex] npoints %D : time(rank0) %1.2e (sec): points/sec %1.4e\n",numPoints,t1-t0,(double)((double)numPoints/(t1-t0)));CHKERRQ(ierr); 800 PetscFunctionReturn(0); 801 } 802 803 /*@C 804 DMPlexComputeProjection2Dto1D - Rewrite coordinates to be the 1D projection of the 2D coordinates 805 806 Not collective 807 808 Input Parameter: 809 . coords - The coordinates of a segment 810 811 Output Parameters: 812 + coords - The new y-coordinate, and 0 for x 813 - R - The rotation which accomplishes the projection 814 815 Level: developer 816 817 .seealso: DMPlexComputeProjection3Dto1D(), DMPlexComputeProjection3Dto2D() 818 @*/ 819 PetscErrorCode DMPlexComputeProjection2Dto1D(PetscScalar coords[], PetscReal R[]) 820 { 821 const PetscReal x = PetscRealPart(coords[2] - coords[0]); 822 const PetscReal y = PetscRealPart(coords[3] - coords[1]); 823 const PetscReal r = PetscSqrtReal(x*x + y*y), c = x/r, s = y/r; 824 825 PetscFunctionBegin; 826 R[0] = c; R[1] = -s; 827 R[2] = s; R[3] = c; 828 coords[0] = 0.0; 829 coords[1] = r; 830 PetscFunctionReturn(0); 831 } 832 833 /*@C 834 DMPlexComputeProjection3Dto1D - Rewrite coordinates to be the 1D projection of the 3D coordinates 835 836 Not collective 837 838 Input Parameter: 839 . coords - The coordinates of a segment 840 841 Output Parameters: 842 + coords - The new y-coordinate, and 0 for x and z 843 - R - The rotation which accomplishes the projection 844 845 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 846 847 Level: developer 848 849 .seealso: DMPlexComputeProjection2Dto1D(), DMPlexComputeProjection3Dto2D() 850 @*/ 851 PetscErrorCode DMPlexComputeProjection3Dto1D(PetscScalar coords[], PetscReal R[]) 852 { 853 PetscReal x = PetscRealPart(coords[3] - coords[0]); 854 PetscReal y = PetscRealPart(coords[4] - coords[1]); 855 PetscReal z = PetscRealPart(coords[5] - coords[2]); 856 PetscReal r = PetscSqrtReal(x*x + y*y + z*z); 857 PetscReal rinv = 1. / r; 858 PetscFunctionBegin; 859 860 x *= rinv; y *= rinv; z *= rinv; 861 if (x > 0.) { 862 PetscReal inv1pX = 1./ (1. + x); 863 864 R[0] = x; R[1] = -y; R[2] = -z; 865 R[3] = y; R[4] = 1. - y*y*inv1pX; R[5] = -y*z*inv1pX; 866 R[6] = z; R[7] = -y*z*inv1pX; R[8] = 1. - z*z*inv1pX; 867 } 868 else { 869 PetscReal inv1mX = 1./ (1. - x); 870 871 R[0] = x; R[1] = z; R[2] = y; 872 R[3] = y; R[4] = -y*z*inv1mX; R[5] = 1. - y*y*inv1mX; 873 R[6] = z; R[7] = 1. - z*z*inv1mX; R[8] = -y*z*inv1mX; 874 } 875 coords[0] = 0.0; 876 coords[1] = r; 877 PetscFunctionReturn(0); 878 } 879 880 /*@ 881 DMPlexComputeProjection3Dto2D - Rewrite coordinates of 3 or more coplanar 3D points to a common 2D basis for the 882 plane. The normal is defined by positive orientation of the first 3 points. 883 884 Not collective 885 886 Input Parameter: 887 + coordSize - Length of coordinate array (3x number of points); must be at least 9 (3 points) 888 - coords - The interlaced coordinates of each coplanar 3D point 889 890 Output Parameters: 891 + coords - The first 2*coordSize/3 entries contain interlaced 2D points, with the rest undefined 892 - 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. 893 894 Level: developer 895 896 .seealso: DMPlexComputeProjection2Dto1D(), DMPlexComputeProjection3Dto1D() 897 @*/ 898 PetscErrorCode DMPlexComputeProjection3Dto2D(PetscInt coordSize, PetscScalar coords[], PetscReal R[]) 899 { 900 PetscReal x1[3], x2[3], n[3], c[3], norm; 901 const PetscInt dim = 3; 902 PetscInt d, p; 903 904 PetscFunctionBegin; 905 /* 0) Calculate normal vector */ 906 for (d = 0; d < dim; ++d) { 907 x1[d] = PetscRealPart(coords[1*dim+d] - coords[0*dim+d]); 908 x2[d] = PetscRealPart(coords[2*dim+d] - coords[0*dim+d]); 909 } 910 // n = x1 \otimes x2 911 n[0] = x1[1]*x2[2] - x1[2]*x2[1]; 912 n[1] = x1[2]*x2[0] - x1[0]*x2[2]; 913 n[2] = x1[0]*x2[1] - x1[1]*x2[0]; 914 norm = PetscSqrtReal(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); 915 for (d = 0; d < dim; d++) n[d] /= norm; 916 norm = PetscSqrtReal(x1[0] * x1[0] + x1[1] * x1[1] + x1[2] * x1[2]); 917 for (d = 0; d < dim; d++) x1[d] /= norm; 918 // x2 = n \otimes x1 919 x2[0] = n[1] * x1[2] - n[2] * x1[1]; 920 x2[1] = n[2] * x1[0] - n[0] * x1[2]; 921 x2[2] = n[0] * x1[1] - n[1] * x1[0]; 922 for (d=0; d<dim; d++) { 923 R[d * dim + 0] = x1[d]; 924 R[d * dim + 1] = x2[d]; 925 R[d * dim + 2] = n[d]; 926 c[d] = PetscRealPart(coords[0*dim + d]); 927 } 928 for (p=0; p<coordSize/dim; p++) { 929 PetscReal y[3]; 930 for (d=0; d<dim; d++) y[d] = PetscRealPart(coords[p*dim + d]) - c[d]; 931 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]; 932 } 933 PetscFunctionReturn(0); 934 } 935 936 PETSC_UNUSED 937 PETSC_STATIC_INLINE void Volume_Triangle_Internal(PetscReal *vol, PetscReal coords[]) 938 { 939 /* Signed volume is 1/2 the determinant 940 941 | 1 1 1 | 942 | x0 x1 x2 | 943 | y0 y1 y2 | 944 945 but if x0,y0 is the origin, we have 946 947 | x1 x2 | 948 | y1 y2 | 949 */ 950 const PetscReal x1 = coords[2] - coords[0], y1 = coords[3] - coords[1]; 951 const PetscReal x2 = coords[4] - coords[0], y2 = coords[5] - coords[1]; 952 PetscReal M[4], detM; 953 M[0] = x1; M[1] = x2; 954 M[2] = y1; M[3] = y2; 955 DMPlex_Det2D_Internal(&detM, M); 956 *vol = 0.5*detM; 957 (void)PetscLogFlops(5.0); 958 } 959 960 PETSC_STATIC_INLINE void Volume_Triangle_Origin_Internal(PetscReal *vol, PetscReal coords[]) 961 { 962 DMPlex_Det2D_Internal(vol, coords); 963 *vol *= 0.5; 964 } 965 966 PETSC_UNUSED 967 PETSC_STATIC_INLINE void Volume_Tetrahedron_Internal(PetscReal *vol, PetscReal coords[]) 968 { 969 /* Signed volume is 1/6th of the determinant 970 971 | 1 1 1 1 | 972 | x0 x1 x2 x3 | 973 | y0 y1 y2 y3 | 974 | z0 z1 z2 z3 | 975 976 but if x0,y0,z0 is the origin, we have 977 978 | x1 x2 x3 | 979 | y1 y2 y3 | 980 | z1 z2 z3 | 981 */ 982 const PetscReal x1 = coords[3] - coords[0], y1 = coords[4] - coords[1], z1 = coords[5] - coords[2]; 983 const PetscReal x2 = coords[6] - coords[0], y2 = coords[7] - coords[1], z2 = coords[8] - coords[2]; 984 const PetscReal x3 = coords[9] - coords[0], y3 = coords[10] - coords[1], z3 = coords[11] - coords[2]; 985 const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.); 986 PetscReal M[9], detM; 987 M[0] = x1; M[1] = x2; M[2] = x3; 988 M[3] = y1; M[4] = y2; M[5] = y3; 989 M[6] = z1; M[7] = z2; M[8] = z3; 990 DMPlex_Det3D_Internal(&detM, M); 991 *vol = -onesixth*detM; 992 (void)PetscLogFlops(10.0); 993 } 994 995 PETSC_STATIC_INLINE void Volume_Tetrahedron_Origin_Internal(PetscReal *vol, PetscReal coords[]) 996 { 997 const PetscReal onesixth = ((PetscReal)1./(PetscReal)6.); 998 DMPlex_Det3D_Internal(vol, coords); 999 *vol *= -onesixth; 1000 } 1001 1002 static PetscErrorCode DMPlexComputePointGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1003 { 1004 PetscSection coordSection; 1005 Vec coordinates; 1006 const PetscScalar *coords; 1007 PetscInt dim, d, off; 1008 PetscErrorCode ierr; 1009 1010 PetscFunctionBegin; 1011 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1012 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1013 ierr = PetscSectionGetDof(coordSection,e,&dim);CHKERRQ(ierr); 1014 if (!dim) PetscFunctionReturn(0); 1015 ierr = PetscSectionGetOffset(coordSection,e,&off);CHKERRQ(ierr); 1016 ierr = VecGetArrayRead(coordinates,&coords);CHKERRQ(ierr); 1017 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[off + d]);} 1018 ierr = VecRestoreArrayRead(coordinates,&coords);CHKERRQ(ierr); 1019 *detJ = 1.; 1020 if (J) { 1021 for (d = 0; d < dim * dim; d++) J[d] = 0.; 1022 for (d = 0; d < dim; d++) J[d * dim + d] = 1.; 1023 if (invJ) { 1024 for (d = 0; d < dim * dim; d++) invJ[d] = 0.; 1025 for (d = 0; d < dim; d++) invJ[d * dim + d] = 1.; 1026 } 1027 } 1028 PetscFunctionReturn(0); 1029 } 1030 1031 static PetscErrorCode DMPlexComputeLineGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1032 { 1033 PetscSection coordSection; 1034 Vec coordinates; 1035 PetscScalar *coords = NULL; 1036 PetscInt numCoords, d, pStart, pEnd, numSelfCoords = 0; 1037 PetscErrorCode ierr; 1038 1039 PetscFunctionBegin; 1040 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1041 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1042 ierr = PetscSectionGetChart(coordSection,&pStart,&pEnd);CHKERRQ(ierr); 1043 if (e >= pStart && e < pEnd) {ierr = PetscSectionGetDof(coordSection,e,&numSelfCoords);CHKERRQ(ierr);} 1044 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1045 numCoords = numSelfCoords ? numSelfCoords : numCoords; 1046 if (invJ && !J) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "In order to compute invJ, J must not be NULL"); 1047 *detJ = 0.0; 1048 if (numCoords == 6) { 1049 const PetscInt dim = 3; 1050 PetscReal R[9], J0; 1051 1052 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1053 ierr = DMPlexComputeProjection3Dto1D(coords, R);CHKERRQ(ierr); 1054 if (J) { 1055 J0 = 0.5*PetscRealPart(coords[1]); 1056 J[0] = R[0]*J0; J[1] = R[1]; J[2] = R[2]; 1057 J[3] = R[3]*J0; J[4] = R[4]; J[5] = R[5]; 1058 J[6] = R[6]*J0; J[7] = R[7]; J[8] = R[8]; 1059 DMPlex_Det3D_Internal(detJ, J); 1060 if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);} 1061 } 1062 } else if (numCoords == 4) { 1063 const PetscInt dim = 2; 1064 PetscReal R[4], J0; 1065 1066 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1067 ierr = DMPlexComputeProjection2Dto1D(coords, R);CHKERRQ(ierr); 1068 if (J) { 1069 J0 = 0.5*PetscRealPart(coords[1]); 1070 J[0] = R[0]*J0; J[1] = R[1]; 1071 J[2] = R[2]*J0; J[3] = R[3]; 1072 DMPlex_Det2D_Internal(detJ, J); 1073 if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);} 1074 } 1075 } else if (numCoords == 2) { 1076 const PetscInt dim = 1; 1077 1078 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1079 if (J) { 1080 J[0] = 0.5*(PetscRealPart(coords[1]) - PetscRealPart(coords[0])); 1081 *detJ = J[0]; 1082 ierr = PetscLogFlops(2.0);CHKERRQ(ierr); 1083 if (invJ) {invJ[0] = 1.0/J[0]; ierr = PetscLogFlops(1.0);CHKERRQ(ierr);} 1084 } 1085 } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this segment is %D != 2", numCoords); 1086 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1087 PetscFunctionReturn(0); 1088 } 1089 1090 static PetscErrorCode DMPlexComputeTriangleGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1091 { 1092 PetscSection coordSection; 1093 Vec coordinates; 1094 PetscScalar *coords = NULL; 1095 PetscInt numCoords, numSelfCoords = 0, d, f, g, pStart, pEnd; 1096 PetscErrorCode ierr; 1097 1098 PetscFunctionBegin; 1099 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1100 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1101 ierr = PetscSectionGetChart(coordSection,&pStart,&pEnd);CHKERRQ(ierr); 1102 if (e >= pStart && e < pEnd) {ierr = PetscSectionGetDof(coordSection,e,&numSelfCoords);CHKERRQ(ierr);} 1103 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1104 numCoords = numSelfCoords ? numSelfCoords : numCoords; 1105 *detJ = 0.0; 1106 if (numCoords == 9) { 1107 const PetscInt dim = 3; 1108 PetscReal R[9], J0[9] = {1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0}; 1109 1110 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1111 ierr = DMPlexComputeProjection3Dto2D(numCoords, coords, R);CHKERRQ(ierr); 1112 if (J) { 1113 const PetscInt pdim = 2; 1114 1115 for (d = 0; d < pdim; d++) { 1116 for (f = 0; f < pdim; f++) { 1117 J0[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*pdim+d]) - PetscRealPart(coords[0*pdim+d])); 1118 } 1119 } 1120 ierr = PetscLogFlops(8.0);CHKERRQ(ierr); 1121 DMPlex_Det3D_Internal(detJ, J0); 1122 for (d = 0; d < dim; d++) { 1123 for (f = 0; f < dim; f++) { 1124 J[d*dim+f] = 0.0; 1125 for (g = 0; g < dim; g++) { 1126 J[d*dim+f] += R[d*dim+g]*J0[g*dim+f]; 1127 } 1128 } 1129 } 1130 ierr = PetscLogFlops(18.0);CHKERRQ(ierr); 1131 } 1132 if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);} 1133 } else if (numCoords == 6) { 1134 const PetscInt dim = 2; 1135 1136 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1137 if (J) { 1138 for (d = 0; d < dim; d++) { 1139 for (f = 0; f < dim; f++) { 1140 J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d])); 1141 } 1142 } 1143 ierr = PetscLogFlops(8.0);CHKERRQ(ierr); 1144 DMPlex_Det2D_Internal(detJ, J); 1145 } 1146 if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);} 1147 } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this triangle is %D != 6 or 9", numCoords); 1148 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1149 PetscFunctionReturn(0); 1150 } 1151 1152 static PetscErrorCode DMPlexComputeRectangleGeometry_Internal(DM dm, PetscInt e, PetscBool isTensor, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1153 { 1154 PetscSection coordSection; 1155 Vec coordinates; 1156 PetscScalar *coords = NULL; 1157 PetscInt numCoords, numSelfCoords = 0, d, f, g, pStart, pEnd; 1158 PetscErrorCode ierr; 1159 1160 PetscFunctionBegin; 1161 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1162 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1163 ierr = PetscSectionGetChart(coordSection,&pStart,&pEnd);CHKERRQ(ierr); 1164 if (e >= pStart && e < pEnd) {ierr = PetscSectionGetDof(coordSection,e,&numSelfCoords);CHKERRQ(ierr);} 1165 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1166 numCoords = numSelfCoords ? numSelfCoords : numCoords; 1167 if (!Nq) { 1168 PetscInt vorder[4] = {0, 1, 2, 3}; 1169 1170 if (isTensor) {vorder[2] = 3; vorder[3] = 2;} 1171 *detJ = 0.0; 1172 if (numCoords == 12) { 1173 const PetscInt dim = 3; 1174 PetscReal R[9], J0[9] = {1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0}; 1175 1176 if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);} 1177 ierr = DMPlexComputeProjection3Dto2D(numCoords, coords, R);CHKERRQ(ierr); 1178 if (J) { 1179 const PetscInt pdim = 2; 1180 1181 for (d = 0; d < pdim; d++) { 1182 J0[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*pdim+d]) - PetscRealPart(coords[vorder[0]*pdim+d])); 1183 J0[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[2]*pdim+d]) - PetscRealPart(coords[vorder[1]*pdim+d])); 1184 } 1185 ierr = PetscLogFlops(8.0);CHKERRQ(ierr); 1186 DMPlex_Det3D_Internal(detJ, J0); 1187 for (d = 0; d < dim; d++) { 1188 for (f = 0; f < dim; f++) { 1189 J[d*dim+f] = 0.0; 1190 for (g = 0; g < dim; g++) { 1191 J[d*dim+f] += R[d*dim+g]*J0[g*dim+f]; 1192 } 1193 } 1194 } 1195 ierr = PetscLogFlops(18.0);CHKERRQ(ierr); 1196 } 1197 if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);} 1198 } else if (numCoords == 8) { 1199 const PetscInt dim = 2; 1200 1201 if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);} 1202 if (J) { 1203 for (d = 0; d < dim; d++) { 1204 J[d*dim+0] = 0.5*(PetscRealPart(coords[vorder[1]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d])); 1205 J[d*dim+1] = 0.5*(PetscRealPart(coords[vorder[3]*dim+d]) - PetscRealPart(coords[vorder[0]*dim+d])); 1206 } 1207 ierr = PetscLogFlops(8.0);CHKERRQ(ierr); 1208 DMPlex_Det2D_Internal(detJ, J); 1209 } 1210 if (invJ) {DMPlex_Invert2D_Internal(invJ, J, *detJ);} 1211 } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %D != 8 or 12", numCoords); 1212 } else { 1213 const PetscInt Nv = 4; 1214 const PetscInt dimR = 2; 1215 PetscInt zToPlex[4] = {0, 1, 3, 2}; 1216 PetscReal zOrder[12]; 1217 PetscReal zCoeff[12]; 1218 PetscInt i, j, k, l, dim; 1219 1220 if (isTensor) {zToPlex[2] = 2; zToPlex[3] = 3;} 1221 if (numCoords == 12) { 1222 dim = 3; 1223 } else if (numCoords == 8) { 1224 dim = 2; 1225 } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of coordinates for this quadrilateral is %D != 8 or 12", numCoords); 1226 for (i = 0; i < Nv; i++) { 1227 PetscInt zi = zToPlex[i]; 1228 1229 for (j = 0; j < dim; j++) { 1230 zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]); 1231 } 1232 } 1233 for (j = 0; j < dim; j++) { 1234 zCoeff[dim * 0 + j] = 0.25 * ( zOrder[dim * 0 + j] + zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]); 1235 zCoeff[dim * 1 + j] = 0.25 * (- zOrder[dim * 0 + j] + zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]); 1236 zCoeff[dim * 2 + j] = 0.25 * (- zOrder[dim * 0 + j] - zOrder[dim * 1 + j] + zOrder[dim * 2 + j] + zOrder[dim * 3 + j]); 1237 zCoeff[dim * 3 + j] = 0.25 * ( zOrder[dim * 0 + j] - zOrder[dim * 1 + j] - zOrder[dim * 2 + j] + zOrder[dim * 3 + j]); 1238 } 1239 for (i = 0; i < Nq; i++) { 1240 PetscReal xi = points[dimR * i], eta = points[dimR * i + 1]; 1241 1242 if (v) { 1243 PetscReal extPoint[4]; 1244 1245 extPoint[0] = 1.; 1246 extPoint[1] = xi; 1247 extPoint[2] = eta; 1248 extPoint[3] = xi * eta; 1249 for (j = 0; j < dim; j++) { 1250 PetscReal val = 0.; 1251 1252 for (k = 0; k < Nv; k++) { 1253 val += extPoint[k] * zCoeff[dim * k + j]; 1254 } 1255 v[i * dim + j] = val; 1256 } 1257 } 1258 if (J) { 1259 PetscReal extJ[8]; 1260 1261 extJ[0] = 0.; 1262 extJ[1] = 0.; 1263 extJ[2] = 1.; 1264 extJ[3] = 0.; 1265 extJ[4] = 0.; 1266 extJ[5] = 1.; 1267 extJ[6] = eta; 1268 extJ[7] = xi; 1269 for (j = 0; j < dim; j++) { 1270 for (k = 0; k < dimR; k++) { 1271 PetscReal val = 0.; 1272 1273 for (l = 0; l < Nv; l++) { 1274 val += zCoeff[dim * l + j] * extJ[dimR * l + k]; 1275 } 1276 J[i * dim * dim + dim * j + k] = val; 1277 } 1278 } 1279 if (dim == 3) { /* put the cross product in the third component of the Jacobian */ 1280 PetscReal x, y, z; 1281 PetscReal *iJ = &J[i * dim * dim]; 1282 PetscReal norm; 1283 1284 x = iJ[1 * dim + 0] * iJ[2 * dim + 1] - iJ[1 * dim + 1] * iJ[2 * dim + 0]; 1285 y = iJ[0 * dim + 1] * iJ[2 * dim + 0] - iJ[0 * dim + 0] * iJ[2 * dim + 1]; 1286 z = iJ[0 * dim + 0] * iJ[1 * dim + 1] - iJ[0 * dim + 1] * iJ[1 * dim + 0]; 1287 norm = PetscSqrtReal(x * x + y * y + z * z); 1288 iJ[2] = x / norm; 1289 iJ[5] = y / norm; 1290 iJ[8] = z / norm; 1291 DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]); 1292 if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);} 1293 } else { 1294 DMPlex_Det2D_Internal(&detJ[i], &J[i * dim * dim]); 1295 if (invJ) {DMPlex_Invert2D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);} 1296 } 1297 } 1298 } 1299 } 1300 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, &numCoords, &coords);CHKERRQ(ierr); 1301 PetscFunctionReturn(0); 1302 } 1303 1304 static PetscErrorCode DMPlexComputeTetrahedronGeometry_Internal(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1305 { 1306 PetscSection coordSection; 1307 Vec coordinates; 1308 PetscScalar *coords = NULL; 1309 const PetscInt dim = 3; 1310 PetscInt d; 1311 PetscErrorCode ierr; 1312 1313 PetscFunctionBegin; 1314 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1315 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1316 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr); 1317 *detJ = 0.0; 1318 if (v0) {for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);} 1319 if (J) { 1320 for (d = 0; d < dim; d++) { 1321 /* I orient with outward face normals */ 1322 J[d*dim+0] = 0.5*(PetscRealPart(coords[2*dim+d]) - PetscRealPart(coords[0*dim+d])); 1323 J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d])); 1324 J[d*dim+2] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d])); 1325 } 1326 ierr = PetscLogFlops(18.0);CHKERRQ(ierr); 1327 DMPlex_Det3D_Internal(detJ, J); 1328 } 1329 if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);} 1330 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr); 1331 PetscFunctionReturn(0); 1332 } 1333 1334 static PetscErrorCode DMPlexComputeHexahedronGeometry_Internal(DM dm, PetscInt e, PetscInt Nq, const PetscReal points[], PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1335 { 1336 PetscSection coordSection; 1337 Vec coordinates; 1338 PetscScalar *coords = NULL; 1339 const PetscInt dim = 3; 1340 PetscInt d; 1341 PetscErrorCode ierr; 1342 1343 PetscFunctionBegin; 1344 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1345 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1346 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr); 1347 if (!Nq) { 1348 *detJ = 0.0; 1349 if (v) {for (d = 0; d < dim; d++) v[d] = PetscRealPart(coords[d]);} 1350 if (J) { 1351 for (d = 0; d < dim; d++) { 1352 J[d*dim+0] = 0.5*(PetscRealPart(coords[3*dim+d]) - PetscRealPart(coords[0*dim+d])); 1353 J[d*dim+1] = 0.5*(PetscRealPart(coords[1*dim+d]) - PetscRealPart(coords[0*dim+d])); 1354 J[d*dim+2] = 0.5*(PetscRealPart(coords[4*dim+d]) - PetscRealPart(coords[0*dim+d])); 1355 } 1356 ierr = PetscLogFlops(18.0);CHKERRQ(ierr); 1357 DMPlex_Det3D_Internal(detJ, J); 1358 } 1359 if (invJ) {DMPlex_Invert3D_Internal(invJ, J, *detJ);} 1360 } else { 1361 const PetscInt Nv = 8; 1362 const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6}; 1363 const PetscInt dim = 3; 1364 const PetscInt dimR = 3; 1365 PetscReal zOrder[24]; 1366 PetscReal zCoeff[24]; 1367 PetscInt i, j, k, l; 1368 1369 for (i = 0; i < Nv; i++) { 1370 PetscInt zi = zToPlex[i]; 1371 1372 for (j = 0; j < dim; j++) { 1373 zOrder[dim * i + j] = PetscRealPart(coords[dim * zi + j]); 1374 } 1375 } 1376 for (j = 0; j < dim; j++) { 1377 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]); 1378 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]); 1379 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]); 1380 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]); 1381 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]); 1382 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]); 1383 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]); 1384 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]); 1385 } 1386 for (i = 0; i < Nq; i++) { 1387 PetscReal xi = points[dimR * i], eta = points[dimR * i + 1], theta = points[dimR * i + 2]; 1388 1389 if (v) { 1390 PetscReal extPoint[8]; 1391 1392 extPoint[0] = 1.; 1393 extPoint[1] = xi; 1394 extPoint[2] = eta; 1395 extPoint[3] = xi * eta; 1396 extPoint[4] = theta; 1397 extPoint[5] = theta * xi; 1398 extPoint[6] = theta * eta; 1399 extPoint[7] = theta * eta * xi; 1400 for (j = 0; j < dim; j++) { 1401 PetscReal val = 0.; 1402 1403 for (k = 0; k < Nv; k++) { 1404 val += extPoint[k] * zCoeff[dim * k + j]; 1405 } 1406 v[i * dim + j] = val; 1407 } 1408 } 1409 if (J) { 1410 PetscReal extJ[24]; 1411 1412 extJ[0] = 0. ; extJ[1] = 0. ; extJ[2] = 0. ; 1413 extJ[3] = 1. ; extJ[4] = 0. ; extJ[5] = 0. ; 1414 extJ[6] = 0. ; extJ[7] = 1. ; extJ[8] = 0. ; 1415 extJ[9] = eta ; extJ[10] = xi ; extJ[11] = 0. ; 1416 extJ[12] = 0. ; extJ[13] = 0. ; extJ[14] = 1. ; 1417 extJ[15] = theta ; extJ[16] = 0. ; extJ[17] = xi ; 1418 extJ[18] = 0. ; extJ[19] = theta ; extJ[20] = eta ; 1419 extJ[21] = theta * eta; extJ[22] = theta * xi; extJ[23] = eta * xi; 1420 1421 for (j = 0; j < dim; j++) { 1422 for (k = 0; k < dimR; k++) { 1423 PetscReal val = 0.; 1424 1425 for (l = 0; l < Nv; l++) { 1426 val += zCoeff[dim * l + j] * extJ[dimR * l + k]; 1427 } 1428 J[i * dim * dim + dim * j + k] = val; 1429 } 1430 } 1431 DMPlex_Det3D_Internal(&detJ[i], &J[i * dim * dim]); 1432 if (invJ) {DMPlex_Invert3D_Internal(&invJ[i * dim * dim], &J[i * dim * dim], detJ[i]);} 1433 } 1434 } 1435 } 1436 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr); 1437 PetscFunctionReturn(0); 1438 } 1439 1440 static PetscErrorCode DMPlexComputeCellGeometryFEM_Implicit(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ) 1441 { 1442 DMPolytopeType ct; 1443 PetscInt depth, dim, coordDim, coneSize, i; 1444 PetscInt Nq = 0; 1445 const PetscReal *points = NULL; 1446 DMLabel depthLabel; 1447 PetscReal xi0[3] = {-1.,-1.,-1.}, v0[3], J0[9], detJ0; 1448 PetscBool isAffine = PETSC_TRUE; 1449 PetscErrorCode ierr; 1450 1451 PetscFunctionBegin; 1452 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1453 ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr); 1454 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 1455 ierr = DMLabelGetValue(depthLabel, cell, &dim);CHKERRQ(ierr); 1456 if (depth == 1 && dim == 1) { 1457 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1458 } 1459 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1460 if (coordDim > 3) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported coordinate dimension %D > 3", coordDim); 1461 if (quad) {ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, &points, NULL);CHKERRQ(ierr);} 1462 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 1463 switch (ct) { 1464 case DM_POLYTOPE_POINT: 1465 ierr = DMPlexComputePointGeometry_Internal(dm, cell, v, J, invJ, detJ);CHKERRQ(ierr); 1466 isAffine = PETSC_FALSE; 1467 break; 1468 case DM_POLYTOPE_SEGMENT: 1469 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1470 if (Nq) {ierr = DMPlexComputeLineGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0);CHKERRQ(ierr);} 1471 else {ierr = DMPlexComputeLineGeometry_Internal(dm, cell, v, J, invJ, detJ);CHKERRQ(ierr);} 1472 break; 1473 case DM_POLYTOPE_TRIANGLE: 1474 if (Nq) {ierr = DMPlexComputeTriangleGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0);CHKERRQ(ierr);} 1475 else {ierr = DMPlexComputeTriangleGeometry_Internal(dm, cell, v, J, invJ, detJ);CHKERRQ(ierr);} 1476 break; 1477 case DM_POLYTOPE_QUADRILATERAL: 1478 ierr = DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_FALSE, Nq, points, v, J, invJ, detJ);CHKERRQ(ierr); 1479 isAffine = PETSC_FALSE; 1480 break; 1481 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1482 ierr = DMPlexComputeRectangleGeometry_Internal(dm, cell, PETSC_TRUE, Nq, points, v, J, invJ, detJ);CHKERRQ(ierr); 1483 isAffine = PETSC_FALSE; 1484 break; 1485 case DM_POLYTOPE_TETRAHEDRON: 1486 if (Nq) {ierr = DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v0, J0, NULL, &detJ0);CHKERRQ(ierr);} 1487 else {ierr = DMPlexComputeTetrahedronGeometry_Internal(dm, cell, v, J, invJ, detJ);CHKERRQ(ierr);} 1488 break; 1489 case DM_POLYTOPE_HEXAHEDRON: 1490 ierr = DMPlexComputeHexahedronGeometry_Internal(dm, cell, Nq, points, v, J, invJ, detJ);CHKERRQ(ierr); 1491 isAffine = PETSC_FALSE; 1492 break; 1493 default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No element geometry for cell %D with type %s", cell, DMPolytopeTypes[ct]); 1494 } 1495 if (isAffine && Nq) { 1496 if (v) { 1497 for (i = 0; i < Nq; i++) { 1498 CoordinatesRefToReal(coordDim, dim, xi0, v0, J0, &points[dim * i], &v[coordDim * i]); 1499 } 1500 } 1501 if (detJ) { 1502 for (i = 0; i < Nq; i++) { 1503 detJ[i] = detJ0; 1504 } 1505 } 1506 if (J) { 1507 PetscInt k; 1508 1509 for (i = 0, k = 0; i < Nq; i++) { 1510 PetscInt j; 1511 1512 for (j = 0; j < coordDim * coordDim; j++, k++) { 1513 J[k] = J0[j]; 1514 } 1515 } 1516 } 1517 if (invJ) { 1518 PetscInt k; 1519 switch (coordDim) { 1520 case 0: 1521 break; 1522 case 1: 1523 invJ[0] = 1./J0[0]; 1524 break; 1525 case 2: 1526 DMPlex_Invert2D_Internal(invJ, J0, detJ0); 1527 break; 1528 case 3: 1529 DMPlex_Invert3D_Internal(invJ, J0, detJ0); 1530 break; 1531 } 1532 for (i = 1, k = coordDim * coordDim; i < Nq; i++) { 1533 PetscInt j; 1534 1535 for (j = 0; j < coordDim * coordDim; j++, k++) { 1536 invJ[k] = invJ[j]; 1537 } 1538 } 1539 } 1540 } 1541 PetscFunctionReturn(0); 1542 } 1543 1544 /*@C 1545 DMPlexComputeCellGeometryAffineFEM - Assuming an affine map, compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell 1546 1547 Collective on dm 1548 1549 Input Arguments: 1550 + dm - the DM 1551 - cell - the cell 1552 1553 Output Arguments: 1554 + v0 - the translation part of this affine transform 1555 . J - the Jacobian of the transform from the reference element 1556 . invJ - the inverse of the Jacobian 1557 - detJ - the Jacobian determinant 1558 1559 Level: advanced 1560 1561 Fortran Notes: 1562 Since it returns arrays, this routine is only available in Fortran 90, and you must 1563 include petsc.h90 in your code. 1564 1565 .seealso: DMPlexComputeCellGeometryFEM(), DMGetCoordinateSection(), DMGetCoordinates() 1566 @*/ 1567 PetscErrorCode DMPlexComputeCellGeometryAffineFEM(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) 1568 { 1569 PetscErrorCode ierr; 1570 1571 PetscFunctionBegin; 1572 ierr = DMPlexComputeCellGeometryFEM_Implicit(dm,cell,NULL,v0,J,invJ,detJ);CHKERRQ(ierr); 1573 PetscFunctionReturn(0); 1574 } 1575 1576 static PetscErrorCode DMPlexComputeCellGeometryFEM_FE(DM dm, PetscFE fe, PetscInt point, PetscQuadrature quad, PetscReal v[], PetscReal J[], PetscReal invJ[], PetscReal *detJ) 1577 { 1578 PetscQuadrature feQuad; 1579 PetscSection coordSection; 1580 Vec coordinates; 1581 PetscScalar *coords = NULL; 1582 const PetscReal *quadPoints; 1583 PetscTabulation T; 1584 PetscInt dim, cdim, pdim, qdim, Nq, numCoords, q; 1585 PetscErrorCode ierr; 1586 1587 PetscFunctionBegin; 1588 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1589 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1590 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, point, &numCoords, &coords);CHKERRQ(ierr); 1591 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1592 ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr); 1593 if (!quad) { /* use the first point of the first functional of the dual space */ 1594 PetscDualSpace dsp; 1595 1596 ierr = PetscFEGetDualSpace(fe, &dsp);CHKERRQ(ierr); 1597 ierr = PetscDualSpaceGetFunctional(dsp, 0, &quad);CHKERRQ(ierr); 1598 ierr = PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL);CHKERRQ(ierr); 1599 Nq = 1; 1600 } else { 1601 ierr = PetscQuadratureGetData(quad, &qdim, NULL, &Nq, &quadPoints, NULL);CHKERRQ(ierr); 1602 } 1603 ierr = PetscFEGetDimension(fe, &pdim);CHKERRQ(ierr); 1604 ierr = PetscFEGetQuadrature(fe, &feQuad);CHKERRQ(ierr); 1605 if (feQuad == quad) { 1606 ierr = PetscFEGetCellTabulation(fe, &T);CHKERRQ(ierr); 1607 if (numCoords != pdim*cdim) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "There are %d coordinates for point %d != %d*%d", numCoords, point, pdim, cdim); 1608 } else { 1609 ierr = PetscFECreateTabulation(fe, 1, Nq, quadPoints, J ? 1 : 0, &T);CHKERRQ(ierr); 1610 } 1611 if (qdim != dim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Point dimension %d != quadrature dimension %d", dim, qdim); 1612 { 1613 const PetscReal *basis = T->T[0]; 1614 const PetscReal *basisDer = T->T[1]; 1615 PetscReal detJt; 1616 1617 if (v) { 1618 ierr = PetscArrayzero(v, Nq*cdim);CHKERRQ(ierr); 1619 for (q = 0; q < Nq; ++q) { 1620 PetscInt i, k; 1621 1622 for (k = 0; k < pdim; ++k) { 1623 const PetscInt vertex = k/cdim; 1624 for (i = 0; i < cdim; ++i) { 1625 v[q*cdim + i] += basis[(q*pdim + k)*cdim + i] * PetscRealPart(coords[vertex*cdim + i]); 1626 } 1627 } 1628 ierr = PetscLogFlops(2.0*pdim*cdim);CHKERRQ(ierr); 1629 } 1630 } 1631 if (J) { 1632 ierr = PetscArrayzero(J, Nq*cdim*cdim);CHKERRQ(ierr); 1633 for (q = 0; q < Nq; ++q) { 1634 PetscInt i, j, k, c, r; 1635 1636 /* J = dx_i/d\xi_j = sum[k=0,n-1] dN_k/d\xi_j * x_i(k) */ 1637 for (k = 0; k < pdim; ++k) { 1638 const PetscInt vertex = k/cdim; 1639 for (j = 0; j < dim; ++j) { 1640 for (i = 0; i < cdim; ++i) { 1641 J[(q*cdim + i)*cdim + j] += basisDer[((q*pdim + k)*cdim + i)*dim + j] * PetscRealPart(coords[vertex*cdim + i]); 1642 } 1643 } 1644 } 1645 ierr = PetscLogFlops(2.0*pdim*dim*cdim);CHKERRQ(ierr); 1646 if (cdim > dim) { 1647 for (c = dim; c < cdim; ++c) 1648 for (r = 0; r < cdim; ++r) 1649 J[r*cdim+c] = r == c ? 1.0 : 0.0; 1650 } 1651 if (!detJ && !invJ) continue; 1652 detJt = 0.; 1653 switch (cdim) { 1654 case 3: 1655 DMPlex_Det3D_Internal(&detJt, &J[q*cdim*dim]); 1656 if (invJ) {DMPlex_Invert3D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);} 1657 break; 1658 case 2: 1659 DMPlex_Det2D_Internal(&detJt, &J[q*cdim*dim]); 1660 if (invJ) {DMPlex_Invert2D_Internal(&invJ[q*cdim*dim], &J[q*cdim*dim], detJt);} 1661 break; 1662 case 1: 1663 detJt = J[q*cdim*dim]; 1664 if (invJ) invJ[q*cdim*dim] = 1.0/detJt; 1665 } 1666 if (detJ) detJ[q] = detJt; 1667 } 1668 } else if (detJ || invJ) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Need J to compute invJ or detJ"); 1669 } 1670 if (feQuad != quad) {ierr = PetscTabulationDestroy(&T);CHKERRQ(ierr);} 1671 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, point, &numCoords, &coords);CHKERRQ(ierr); 1672 PetscFunctionReturn(0); 1673 } 1674 1675 /*@C 1676 DMPlexComputeCellGeometryFEM - Compute the Jacobian, inverse Jacobian, and Jacobian determinant at each quadrature point in the given cell 1677 1678 Collective on dm 1679 1680 Input Arguments: 1681 + dm - the DM 1682 . cell - the cell 1683 - quad - the quadrature containing the points in the reference element where the geometry will be evaluated. If quad == NULL, geometry will be 1684 evaluated at the first vertex of the reference element 1685 1686 Output Arguments: 1687 + v - the image of the transformed quadrature points, otherwise the image of the first vertex in the closure of the reference element 1688 . J - the Jacobian of the transform from the reference element at each quadrature point 1689 . invJ - the inverse of the Jacobian at each quadrature point 1690 - detJ - the Jacobian determinant at each quadrature point 1691 1692 Level: advanced 1693 1694 Fortran Notes: 1695 Since it returns arrays, this routine is only available in Fortran 90, and you must 1696 include petsc.h90 in your code. 1697 1698 .seealso: DMGetCoordinateSection(), DMGetCoordinates() 1699 @*/ 1700 PetscErrorCode DMPlexComputeCellGeometryFEM(DM dm, PetscInt cell, PetscQuadrature quad, PetscReal *v, PetscReal *J, PetscReal *invJ, PetscReal *detJ) 1701 { 1702 DM cdm; 1703 PetscFE fe = NULL; 1704 PetscErrorCode ierr; 1705 1706 PetscFunctionBegin; 1707 PetscValidPointer(detJ, 7); 1708 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 1709 if (cdm) { 1710 PetscClassId id; 1711 PetscInt numFields; 1712 PetscDS prob; 1713 PetscObject disc; 1714 1715 ierr = DMGetNumFields(cdm, &numFields);CHKERRQ(ierr); 1716 if (numFields) { 1717 ierr = DMGetDS(cdm, &prob);CHKERRQ(ierr); 1718 ierr = PetscDSGetDiscretization(prob,0,&disc);CHKERRQ(ierr); 1719 ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); 1720 if (id == PETSCFE_CLASSID) { 1721 fe = (PetscFE) disc; 1722 } 1723 } 1724 } 1725 if (!fe) {ierr = DMPlexComputeCellGeometryFEM_Implicit(dm, cell, quad, v, J, invJ, detJ);CHKERRQ(ierr);} 1726 else {ierr = DMPlexComputeCellGeometryFEM_FE(dm, fe, cell, quad, v, J, invJ, detJ);CHKERRQ(ierr);} 1727 PetscFunctionReturn(0); 1728 } 1729 1730 static PetscErrorCode DMPlexComputeGeometryFVM_1D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[]) 1731 { 1732 PetscSection coordSection; 1733 Vec coordinates; 1734 PetscScalar *coords = NULL; 1735 PetscScalar tmp[2]; 1736 PetscInt coordSize, d; 1737 PetscErrorCode ierr; 1738 1739 PetscFunctionBegin; 1740 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1741 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1742 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr); 1743 ierr = DMLocalizeCoordinate_Internal(dm, dim, coords, &coords[dim], tmp);CHKERRQ(ierr); 1744 if (centroid) { 1745 for (d = 0; d < dim; ++d) centroid[d] = 0.5*PetscRealPart(coords[d] + tmp[d]); 1746 } 1747 if (normal) { 1748 PetscReal norm; 1749 1750 if (dim != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "We only support 2D edges right now"); 1751 normal[0] = -PetscRealPart(coords[1] - tmp[1]); 1752 normal[1] = PetscRealPart(coords[0] - tmp[0]); 1753 norm = DMPlex_NormD_Internal(dim, normal); 1754 for (d = 0; d < dim; ++d) normal[d] /= norm; 1755 } 1756 if (vol) { 1757 *vol = 0.0; 1758 for (d = 0; d < dim; ++d) *vol += PetscSqr(PetscRealPart(coords[d] - tmp[d])); 1759 *vol = PetscSqrtReal(*vol); 1760 } 1761 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr); 1762 PetscFunctionReturn(0); 1763 } 1764 1765 /* Centroid_i = (\sum_n A_n Cn_i ) / A */ 1766 static PetscErrorCode DMPlexComputeGeometryFVM_2D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[]) 1767 { 1768 DMPolytopeType ct; 1769 PetscSection coordSection; 1770 Vec coordinates; 1771 PetscScalar *coords = NULL; 1772 PetscReal vsum = 0.0, csum[3] = {0.0, 0.0, 0.0}, vtmp, ctmp[4], v0[3], R[9]; 1773 PetscBool isHybrid = PETSC_FALSE; 1774 PetscInt fv[4] = {0, 1, 2, 3}; 1775 PetscInt tdim = 2, coordSize, numCorners, p, d, e; 1776 PetscErrorCode ierr; 1777 1778 PetscFunctionBegin; 1779 /* Must check for hybrid cells because prisms have a different orientation scheme */ 1780 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 1781 switch (ct) { 1782 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1783 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1784 case DM_POLYTOPE_TRI_PRISM_TENSOR: 1785 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 1786 isHybrid = PETSC_TRUE; 1787 default: break; 1788 } 1789 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1790 ierr = DMPlexGetConeSize(dm, cell, &numCorners);CHKERRQ(ierr); 1791 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1792 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr); 1793 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 1794 /* Side faces for hybrid cells are are stored as tensor products */ 1795 if (isHybrid && numCorners == 4) {fv[2] = 3; fv[3] = 2;} 1796 1797 if (dim > 2 && centroid) { 1798 v0[0] = PetscRealPart(coords[0]); 1799 v0[1] = PetscRealPart(coords[1]); 1800 v0[2] = PetscRealPart(coords[2]); 1801 } 1802 if (normal) { 1803 if (dim > 2) { 1804 const PetscReal x0 = PetscRealPart(coords[dim*fv[1]+0] - coords[0]), x1 = PetscRealPart(coords[dim*fv[2]+0] - coords[0]); 1805 const PetscReal y0 = PetscRealPart(coords[dim*fv[1]+1] - coords[1]), y1 = PetscRealPart(coords[dim*fv[2]+1] - coords[1]); 1806 const PetscReal z0 = PetscRealPart(coords[dim*fv[1]+2] - coords[2]), z1 = PetscRealPart(coords[dim*fv[2]+2] - coords[2]); 1807 PetscReal norm; 1808 1809 normal[0] = y0*z1 - z0*y1; 1810 normal[1] = z0*x1 - x0*z1; 1811 normal[2] = x0*y1 - y0*x1; 1812 norm = PetscSqrtReal(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]); 1813 normal[0] /= norm; 1814 normal[1] /= norm; 1815 normal[2] /= norm; 1816 } else { 1817 for (d = 0; d < dim; ++d) normal[d] = 0.0; 1818 } 1819 } 1820 if (dim == 3) {ierr = DMPlexComputeProjection3Dto2D(coordSize, coords, R);CHKERRQ(ierr);} 1821 for (p = 0; p < numCorners; ++p) { 1822 const PetscInt pi = p < 4 ? fv[p] : p; 1823 const PetscInt pin = p < 3 ? fv[(p+1)%numCorners] : (p+1)%numCorners; 1824 /* Need to do this copy to get types right */ 1825 for (d = 0; d < tdim; ++d) { 1826 ctmp[d] = PetscRealPart(coords[pi*tdim+d]); 1827 ctmp[tdim+d] = PetscRealPart(coords[pin*tdim+d]); 1828 } 1829 Volume_Triangle_Origin_Internal(&vtmp, ctmp); 1830 vsum += vtmp; 1831 for (d = 0; d < tdim; ++d) { 1832 csum[d] += (ctmp[d] + ctmp[tdim+d])*vtmp; 1833 } 1834 } 1835 for (d = 0; d < tdim; ++d) { 1836 csum[d] /= (tdim+1)*vsum; 1837 } 1838 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, cell, &coordSize, &coords);CHKERRQ(ierr); 1839 if (vol) *vol = PetscAbsReal(vsum); 1840 if (centroid) { 1841 if (dim > 2) { 1842 for (d = 0; d < dim; ++d) { 1843 centroid[d] = v0[d]; 1844 for (e = 0; e < dim; ++e) { 1845 centroid[d] += R[d*dim+e]*csum[e]; 1846 } 1847 } 1848 } else for (d = 0; d < dim; ++d) centroid[d] = csum[d]; 1849 } 1850 PetscFunctionReturn(0); 1851 } 1852 1853 /* Centroid_i = (\sum_n V_n Cn_i ) / V */ 1854 static PetscErrorCode DMPlexComputeGeometryFVM_3D_Internal(DM dm, PetscInt dim, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[]) 1855 { 1856 DMPolytopeType ct; 1857 PetscSection coordSection; 1858 Vec coordinates; 1859 PetscScalar *coords = NULL; 1860 PetscReal vsum = 0.0, vtmp, coordsTmp[3*3]; 1861 const PetscInt *faces, *facesO; 1862 PetscBool isHybrid = PETSC_FALSE; 1863 PetscInt numFaces, f, coordSize, p, d; 1864 PetscErrorCode ierr; 1865 1866 PetscFunctionBegin; 1867 if (PetscUnlikely(dim > 3)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"No support for dim %D > 3",dim); 1868 /* Must check for hybrid cells because prisms have a different orientation scheme */ 1869 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 1870 switch (ct) { 1871 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1872 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1873 case DM_POLYTOPE_TRI_PRISM_TENSOR: 1874 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 1875 isHybrid = PETSC_TRUE; 1876 default: break; 1877 } 1878 1879 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1880 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 1881 1882 if (centroid) for (d = 0; d < dim; ++d) centroid[d] = 0.0; 1883 ierr = DMPlexGetConeSize(dm, cell, &numFaces);CHKERRQ(ierr); 1884 ierr = DMPlexGetCone(dm, cell, &faces);CHKERRQ(ierr); 1885 ierr = DMPlexGetConeOrientation(dm, cell, &facesO);CHKERRQ(ierr); 1886 for (f = 0; f < numFaces; ++f) { 1887 PetscBool flip = isHybrid && f == 0 ? PETSC_TRUE : PETSC_FALSE; /* The first hybrid face is reversed */ 1888 DMPolytopeType ct; 1889 1890 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, faces[f], &coordSize, &coords);CHKERRQ(ierr); 1891 ierr = DMPlexGetCellType(dm, faces[f], &ct);CHKERRQ(ierr); 1892 switch (ct) { 1893 case DM_POLYTOPE_TRIANGLE: 1894 for (d = 0; d < dim; ++d) { 1895 coordsTmp[0*dim+d] = PetscRealPart(coords[0*dim+d]); 1896 coordsTmp[1*dim+d] = PetscRealPart(coords[1*dim+d]); 1897 coordsTmp[2*dim+d] = PetscRealPart(coords[2*dim+d]); 1898 } 1899 Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp); 1900 if (facesO[f] < 0 || flip) vtmp = -vtmp; 1901 vsum += vtmp; 1902 if (centroid) { /* Centroid of OABC = (a+b+c)/4 */ 1903 for (d = 0; d < dim; ++d) { 1904 for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp; 1905 } 1906 } 1907 break; 1908 case DM_POLYTOPE_QUADRILATERAL: 1909 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1910 { 1911 PetscInt fv[4] = {0, 1, 2, 3}; 1912 1913 /* Side faces for hybrid cells are are stored as tensor products */ 1914 if (isHybrid && f > 1) {fv[2] = 3; fv[3] = 2;} 1915 /* DO FOR PYRAMID */ 1916 /* First tet */ 1917 for (d = 0; d < dim; ++d) { 1918 coordsTmp[0*dim+d] = PetscRealPart(coords[fv[0]*dim+d]); 1919 coordsTmp[1*dim+d] = PetscRealPart(coords[fv[1]*dim+d]); 1920 coordsTmp[2*dim+d] = PetscRealPart(coords[fv[3]*dim+d]); 1921 } 1922 Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp); 1923 if (facesO[f] < 0 || flip) vtmp = -vtmp; 1924 vsum += vtmp; 1925 if (centroid) { 1926 for (d = 0; d < dim; ++d) { 1927 for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp; 1928 } 1929 } 1930 /* Second tet */ 1931 for (d = 0; d < dim; ++d) { 1932 coordsTmp[0*dim+d] = PetscRealPart(coords[fv[1]*dim+d]); 1933 coordsTmp[1*dim+d] = PetscRealPart(coords[fv[2]*dim+d]); 1934 coordsTmp[2*dim+d] = PetscRealPart(coords[fv[3]*dim+d]); 1935 } 1936 Volume_Tetrahedron_Origin_Internal(&vtmp, coordsTmp); 1937 if (facesO[f] < 0 || flip) vtmp = -vtmp; 1938 vsum += vtmp; 1939 if (centroid) { 1940 for (d = 0; d < dim; ++d) { 1941 for (p = 0; p < 3; ++p) centroid[d] += coordsTmp[p*dim+d]*vtmp; 1942 } 1943 } 1944 break; 1945 } 1946 default: 1947 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle face %D of type %s", faces[f], DMPolytopeTypes[ct]); 1948 } 1949 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, faces[f], &coordSize, &coords);CHKERRQ(ierr); 1950 } 1951 if (vol) *vol = PetscAbsReal(vsum); 1952 if (normal) for (d = 0; d < dim; ++d) normal[d] = 0.0; 1953 if (centroid) for (d = 0; d < dim; ++d) centroid[d] /= (vsum*4); 1954 PetscFunctionReturn(0); 1955 } 1956 1957 /*@C 1958 DMPlexComputeCellGeometryFVM - Compute the volume for a given cell 1959 1960 Collective on dm 1961 1962 Input Arguments: 1963 + dm - the DM 1964 - cell - the cell 1965 1966 Output Arguments: 1967 + volume - the cell volume 1968 . centroid - the cell centroid 1969 - normal - the cell normal, if appropriate 1970 1971 Level: advanced 1972 1973 Fortran Notes: 1974 Since it returns arrays, this routine is only available in Fortran 90, and you must 1975 include petsc.h90 in your code. 1976 1977 .seealso: DMGetCoordinateSection(), DMGetCoordinates() 1978 @*/ 1979 PetscErrorCode DMPlexComputeCellGeometryFVM(DM dm, PetscInt cell, PetscReal *vol, PetscReal centroid[], PetscReal normal[]) 1980 { 1981 PetscInt depth, dim; 1982 PetscErrorCode ierr; 1983 1984 PetscFunctionBegin; 1985 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1986 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1987 if (depth != dim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh must be interpolated"); 1988 ierr = DMPlexGetPointDepth(dm, cell, &depth);CHKERRQ(ierr); 1989 switch (depth) { 1990 case 1: 1991 ierr = DMPlexComputeGeometryFVM_1D_Internal(dm, dim, cell, vol, centroid, normal);CHKERRQ(ierr); 1992 break; 1993 case 2: 1994 ierr = DMPlexComputeGeometryFVM_2D_Internal(dm, dim, cell, vol, centroid, normal);CHKERRQ(ierr); 1995 break; 1996 case 3: 1997 ierr = DMPlexComputeGeometryFVM_3D_Internal(dm, dim, cell, vol, centroid, normal);CHKERRQ(ierr); 1998 break; 1999 default: 2000 SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D (depth %D) for element geometry computation", dim, depth); 2001 } 2002 PetscFunctionReturn(0); 2003 } 2004 2005 /*@ 2006 DMPlexComputeGeometryFEM - Precompute cell geometry for the entire mesh 2007 2008 Collective on dm 2009 2010 Input Parameter: 2011 . dm - The DMPlex 2012 2013 Output Parameter: 2014 . cellgeom - A vector with the cell geometry data for each cell 2015 2016 Level: beginner 2017 2018 @*/ 2019 PetscErrorCode DMPlexComputeGeometryFEM(DM dm, Vec *cellgeom) 2020 { 2021 DM dmCell; 2022 Vec coordinates; 2023 PetscSection coordSection, sectionCell; 2024 PetscScalar *cgeom; 2025 PetscInt cStart, cEnd, c; 2026 PetscErrorCode ierr; 2027 2028 PetscFunctionBegin; 2029 ierr = DMClone(dm, &dmCell);CHKERRQ(ierr); 2030 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 2031 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 2032 ierr = DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection);CHKERRQ(ierr); 2033 ierr = DMSetCoordinatesLocal(dmCell, coordinates);CHKERRQ(ierr); 2034 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ionCell);CHKERRQ(ierr); 2035 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2036 ierr = PetscSectionSetChart(sectionCell, cStart, cEnd);CHKERRQ(ierr); 2037 /* TODO This needs to be multiplied by Nq for non-affine */ 2038 for (c = cStart; c < cEnd; ++c) {ierr = PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFEGeom))/sizeof(PetscScalar)));CHKERRQ(ierr);} 2039 ierr = PetscSectionSetUp(sectionCell);CHKERRQ(ierr); 2040 ierr = DMSetLocalSection(dmCell, sectionCell);CHKERRQ(ierr); 2041 ierr = PetscSectionDestroy(§ionCell);CHKERRQ(ierr); 2042 ierr = DMCreateLocalVector(dmCell, cellgeom);CHKERRQ(ierr); 2043 ierr = VecGetArray(*cellgeom, &cgeom);CHKERRQ(ierr); 2044 for (c = cStart; c < cEnd; ++c) { 2045 PetscFEGeom *cg; 2046 2047 ierr = DMPlexPointLocalRef(dmCell, c, cgeom, &cg);CHKERRQ(ierr); 2048 ierr = PetscArrayzero(cg, 1);CHKERRQ(ierr); 2049 ierr = DMPlexComputeCellGeometryFEM(dmCell, c, NULL, cg->v, cg->J, cg->invJ, cg->detJ);CHKERRQ(ierr); 2050 if (*cg->detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double) *cg->detJ, c); 2051 } 2052 PetscFunctionReturn(0); 2053 } 2054 2055 /*@ 2056 DMPlexComputeGeometryFVM - Computes the cell and face geometry for a finite volume method 2057 2058 Input Parameter: 2059 . dm - The DM 2060 2061 Output Parameters: 2062 + cellgeom - A Vec of PetscFVCellGeom data 2063 - facegeom - A Vec of PetscFVFaceGeom data 2064 2065 Level: developer 2066 2067 .seealso: PetscFVFaceGeom, PetscFVCellGeom, DMPlexComputeGeometryFEM() 2068 @*/ 2069 PetscErrorCode DMPlexComputeGeometryFVM(DM dm, Vec *cellgeom, Vec *facegeom) 2070 { 2071 DM dmFace, dmCell; 2072 DMLabel ghostLabel; 2073 PetscSection sectionFace, sectionCell; 2074 PetscSection coordSection; 2075 Vec coordinates; 2076 PetscScalar *fgeom, *cgeom; 2077 PetscReal minradius, gminradius; 2078 PetscInt dim, cStart, cEnd, cEndInterior, c, fStart, fEnd, f; 2079 PetscErrorCode ierr; 2080 2081 PetscFunctionBegin; 2082 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2083 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 2084 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 2085 /* Make cell centroids and volumes */ 2086 ierr = DMClone(dm, &dmCell);CHKERRQ(ierr); 2087 ierr = DMSetCoordinateSection(dmCell, PETSC_DETERMINE, coordSection);CHKERRQ(ierr); 2088 ierr = DMSetCoordinatesLocal(dmCell, coordinates);CHKERRQ(ierr); 2089 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ionCell);CHKERRQ(ierr); 2090 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2091 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 2092 ierr = PetscSectionSetChart(sectionCell, cStart, cEnd);CHKERRQ(ierr); 2093 for (c = cStart; c < cEnd; ++c) {ierr = PetscSectionSetDof(sectionCell, c, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVCellGeom))/sizeof(PetscScalar)));CHKERRQ(ierr);} 2094 ierr = PetscSectionSetUp(sectionCell);CHKERRQ(ierr); 2095 ierr = DMSetLocalSection(dmCell, sectionCell);CHKERRQ(ierr); 2096 ierr = PetscSectionDestroy(§ionCell);CHKERRQ(ierr); 2097 ierr = DMCreateLocalVector(dmCell, cellgeom);CHKERRQ(ierr); 2098 if (cEndInterior < 0) cEndInterior = cEnd; 2099 ierr = VecGetArray(*cellgeom, &cgeom);CHKERRQ(ierr); 2100 for (c = cStart; c < cEndInterior; ++c) { 2101 PetscFVCellGeom *cg; 2102 2103 ierr = DMPlexPointLocalRef(dmCell, c, cgeom, &cg);CHKERRQ(ierr); 2104 ierr = PetscArrayzero(cg, 1);CHKERRQ(ierr); 2105 ierr = DMPlexComputeCellGeometryFVM(dmCell, c, &cg->volume, cg->centroid, NULL);CHKERRQ(ierr); 2106 } 2107 /* Compute face normals and minimum cell radius */ 2108 ierr = DMClone(dm, &dmFace);CHKERRQ(ierr); 2109 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ionFace);CHKERRQ(ierr); 2110 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 2111 ierr = PetscSectionSetChart(sectionFace, fStart, fEnd);CHKERRQ(ierr); 2112 for (f = fStart; f < fEnd; ++f) {ierr = PetscSectionSetDof(sectionFace, f, (PetscInt) PetscCeilReal(((PetscReal) sizeof(PetscFVFaceGeom))/sizeof(PetscScalar)));CHKERRQ(ierr);} 2113 ierr = PetscSectionSetUp(sectionFace);CHKERRQ(ierr); 2114 ierr = DMSetLocalSection(dmFace, sectionFace);CHKERRQ(ierr); 2115 ierr = PetscSectionDestroy(§ionFace);CHKERRQ(ierr); 2116 ierr = DMCreateLocalVector(dmFace, facegeom);CHKERRQ(ierr); 2117 ierr = VecGetArray(*facegeom, &fgeom);CHKERRQ(ierr); 2118 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 2119 minradius = PETSC_MAX_REAL; 2120 for (f = fStart; f < fEnd; ++f) { 2121 PetscFVFaceGeom *fg; 2122 PetscReal area; 2123 const PetscInt *cells; 2124 PetscInt ncells, ghost = -1, d, numChildren; 2125 2126 if (ghostLabel) {ierr = DMLabelGetValue(ghostLabel, f, &ghost);CHKERRQ(ierr);} 2127 ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); 2128 ierr = DMPlexGetSupport(dm, f, &cells);CHKERRQ(ierr); 2129 ierr = DMPlexGetSupportSize(dm, f, &ncells);CHKERRQ(ierr); 2130 /* It is possible to get a face with no support when using partition overlap */ 2131 if (!ncells || ghost >= 0 || numChildren) continue; 2132 ierr = DMPlexPointLocalRef(dmFace, f, fgeom, &fg);CHKERRQ(ierr); 2133 ierr = DMPlexComputeCellGeometryFVM(dm, f, &area, fg->centroid, fg->normal);CHKERRQ(ierr); 2134 for (d = 0; d < dim; ++d) fg->normal[d] *= area; 2135 /* Flip face orientation if necessary to match ordering in support, and Update minimum radius */ 2136 { 2137 PetscFVCellGeom *cL, *cR; 2138 PetscReal *lcentroid, *rcentroid; 2139 PetscReal l[3], r[3], v[3]; 2140 2141 ierr = DMPlexPointLocalRead(dmCell, cells[0], cgeom, &cL);CHKERRQ(ierr); 2142 lcentroid = cells[0] >= cEndInterior ? fg->centroid : cL->centroid; 2143 if (ncells > 1) { 2144 ierr = DMPlexPointLocalRead(dmCell, cells[1], cgeom, &cR);CHKERRQ(ierr); 2145 rcentroid = cells[1] >= cEndInterior ? fg->centroid : cR->centroid; 2146 } 2147 else { 2148 rcentroid = fg->centroid; 2149 } 2150 ierr = DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, lcentroid, l);CHKERRQ(ierr); 2151 ierr = DMLocalizeCoordinateReal_Internal(dm, dim, fg->centroid, rcentroid, r);CHKERRQ(ierr); 2152 DMPlex_WaxpyD_Internal(dim, -1, l, r, v); 2153 if (DMPlex_DotRealD_Internal(dim, fg->normal, v) < 0) { 2154 for (d = 0; d < dim; ++d) fg->normal[d] = -fg->normal[d]; 2155 } 2156 if (DMPlex_DotRealD_Internal(dim, fg->normal, v) <= 0) { 2157 if (dim == 2) SETERRQ5(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Direction for face %d 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]); 2158 if (dim == 3) SETERRQ7(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Direction for face %d 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]); 2159 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Direction for face %d could not be fixed", f); 2160 } 2161 if (cells[0] < cEndInterior) { 2162 DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cL->centroid, v); 2163 minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v)); 2164 } 2165 if (ncells > 1 && cells[1] < cEndInterior) { 2166 DMPlex_WaxpyD_Internal(dim, -1, fg->centroid, cR->centroid, v); 2167 minradius = PetscMin(minradius, DMPlex_NormD_Internal(dim, v)); 2168 } 2169 } 2170 } 2171 ierr = MPIU_Allreduce(&minradius, &gminradius, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 2172 ierr = DMPlexSetMinRadius(dm, gminradius);CHKERRQ(ierr); 2173 /* Compute centroids of ghost cells */ 2174 for (c = cEndInterior; c < cEnd; ++c) { 2175 PetscFVFaceGeom *fg; 2176 const PetscInt *cone, *support; 2177 PetscInt coneSize, supportSize, s; 2178 2179 ierr = DMPlexGetConeSize(dmCell, c, &coneSize);CHKERRQ(ierr); 2180 if (coneSize != 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %d has cone size %d != 1", c, coneSize); 2181 ierr = DMPlexGetCone(dmCell, c, &cone);CHKERRQ(ierr); 2182 ierr = DMPlexGetSupportSize(dmCell, cone[0], &supportSize);CHKERRQ(ierr); 2183 if (supportSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d has support size %d != 2", cone[0], supportSize); 2184 ierr = DMPlexGetSupport(dmCell, cone[0], &support);CHKERRQ(ierr); 2185 ierr = DMPlexPointLocalRef(dmFace, cone[0], fgeom, &fg);CHKERRQ(ierr); 2186 for (s = 0; s < 2; ++s) { 2187 /* Reflect ghost centroid across plane of face */ 2188 if (support[s] == c) { 2189 PetscFVCellGeom *ci; 2190 PetscFVCellGeom *cg; 2191 PetscReal c2f[3], a; 2192 2193 ierr = DMPlexPointLocalRead(dmCell, support[(s+1)%2], cgeom, &ci);CHKERRQ(ierr); 2194 DMPlex_WaxpyD_Internal(dim, -1, ci->centroid, fg->centroid, c2f); /* cell to face centroid */ 2195 a = DMPlex_DotRealD_Internal(dim, c2f, fg->normal)/DMPlex_DotRealD_Internal(dim, fg->normal, fg->normal); 2196 ierr = DMPlexPointLocalRef(dmCell, support[s], cgeom, &cg);CHKERRQ(ierr); 2197 DMPlex_WaxpyD_Internal(dim, 2*a, fg->normal, ci->centroid, cg->centroid); 2198 cg->volume = ci->volume; 2199 } 2200 } 2201 } 2202 ierr = VecRestoreArray(*facegeom, &fgeom);CHKERRQ(ierr); 2203 ierr = VecRestoreArray(*cellgeom, &cgeom);CHKERRQ(ierr); 2204 ierr = DMDestroy(&dmCell);CHKERRQ(ierr); 2205 ierr = DMDestroy(&dmFace);CHKERRQ(ierr); 2206 PetscFunctionReturn(0); 2207 } 2208 2209 /*@C 2210 DMPlexGetMinRadius - Returns the minimum distance from any cell centroid to a face 2211 2212 Not collective 2213 2214 Input Argument: 2215 . dm - the DM 2216 2217 Output Argument: 2218 . minradius - the minium cell radius 2219 2220 Level: developer 2221 2222 .seealso: DMGetCoordinates() 2223 @*/ 2224 PetscErrorCode DMPlexGetMinRadius(DM dm, PetscReal *minradius) 2225 { 2226 PetscFunctionBegin; 2227 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2228 PetscValidPointer(minradius,2); 2229 *minradius = ((DM_Plex*) dm->data)->minradius; 2230 PetscFunctionReturn(0); 2231 } 2232 2233 /*@C 2234 DMPlexSetMinRadius - Sets the minimum distance from the cell centroid to a face 2235 2236 Logically collective 2237 2238 Input Arguments: 2239 + dm - the DM 2240 - minradius - the minium cell radius 2241 2242 Level: developer 2243 2244 .seealso: DMSetCoordinates() 2245 @*/ 2246 PetscErrorCode DMPlexSetMinRadius(DM dm, PetscReal minradius) 2247 { 2248 PetscFunctionBegin; 2249 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2250 ((DM_Plex*) dm->data)->minradius = minradius; 2251 PetscFunctionReturn(0); 2252 } 2253 2254 static PetscErrorCode BuildGradientReconstruction_Internal(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom) 2255 { 2256 DMLabel ghostLabel; 2257 PetscScalar *dx, *grad, **gref; 2258 PetscInt dim, cStart, cEnd, c, cEndInterior, maxNumFaces; 2259 PetscErrorCode ierr; 2260 2261 PetscFunctionBegin; 2262 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2263 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2264 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 2265 ierr = DMPlexGetMaxSizes(dm, &maxNumFaces, NULL);CHKERRQ(ierr); 2266 ierr = PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces);CHKERRQ(ierr); 2267 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 2268 ierr = PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref);CHKERRQ(ierr); 2269 for (c = cStart; c < cEndInterior; c++) { 2270 const PetscInt *faces; 2271 PetscInt numFaces, usedFaces, f, d; 2272 PetscFVCellGeom *cg; 2273 PetscBool boundary; 2274 PetscInt ghost; 2275 2276 ierr = DMPlexPointLocalRead(dmCell, c, cgeom, &cg);CHKERRQ(ierr); 2277 ierr = DMPlexGetConeSize(dm, c, &numFaces);CHKERRQ(ierr); 2278 ierr = DMPlexGetCone(dm, c, &faces);CHKERRQ(ierr); 2279 if (numFaces < dim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell %D has only %D faces, not enough for gradient reconstruction", c, numFaces); 2280 for (f = 0, usedFaces = 0; f < numFaces; ++f) { 2281 PetscFVCellGeom *cg1; 2282 PetscFVFaceGeom *fg; 2283 const PetscInt *fcells; 2284 PetscInt ncell, side; 2285 2286 ierr = DMLabelGetValue(ghostLabel, faces[f], &ghost);CHKERRQ(ierr); 2287 ierr = DMIsBoundaryPoint(dm, faces[f], &boundary);CHKERRQ(ierr); 2288 if ((ghost >= 0) || boundary) continue; 2289 ierr = DMPlexGetSupport(dm, faces[f], &fcells);CHKERRQ(ierr); 2290 side = (c != fcells[0]); /* c is on left=0 or right=1 of face */ 2291 ncell = fcells[!side]; /* the neighbor */ 2292 ierr = DMPlexPointLocalRef(dmFace, faces[f], fgeom, &fg);CHKERRQ(ierr); 2293 ierr = DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1);CHKERRQ(ierr); 2294 for (d = 0; d < dim; ++d) dx[usedFaces*dim+d] = cg1->centroid[d] - cg->centroid[d]; 2295 gref[usedFaces++] = fg->grad[side]; /* Gradient reconstruction term will go here */ 2296 } 2297 if (!usedFaces) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Mesh contains isolated cell (no neighbors). Is it intentional?"); 2298 ierr = PetscFVComputeGradient(fvm, usedFaces, dx, grad);CHKERRQ(ierr); 2299 for (f = 0, usedFaces = 0; f < numFaces; ++f) { 2300 ierr = DMLabelGetValue(ghostLabel, faces[f], &ghost);CHKERRQ(ierr); 2301 ierr = DMIsBoundaryPoint(dm, faces[f], &boundary);CHKERRQ(ierr); 2302 if ((ghost >= 0) || boundary) continue; 2303 for (d = 0; d < dim; ++d) gref[usedFaces][d] = grad[usedFaces*dim+d]; 2304 ++usedFaces; 2305 } 2306 } 2307 ierr = PetscFree3(dx, grad, gref);CHKERRQ(ierr); 2308 PetscFunctionReturn(0); 2309 } 2310 2311 static PetscErrorCode BuildGradientReconstruction_Internal_Tree(DM dm, PetscFV fvm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom) 2312 { 2313 DMLabel ghostLabel; 2314 PetscScalar *dx, *grad, **gref; 2315 PetscInt dim, cStart, cEnd, c, cEndInterior, fStart, fEnd, f, nStart, nEnd, maxNumFaces = 0; 2316 PetscSection neighSec; 2317 PetscInt (*neighbors)[2]; 2318 PetscInt *counter; 2319 PetscErrorCode ierr; 2320 2321 PetscFunctionBegin; 2322 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2323 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2324 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 2325 if (cEndInterior < 0) cEndInterior = cEnd; 2326 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&neighSec);CHKERRQ(ierr); 2327 ierr = PetscSectionSetChart(neighSec,cStart,cEndInterior);CHKERRQ(ierr); 2328 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 2329 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 2330 for (f = fStart; f < fEnd; f++) { 2331 const PetscInt *fcells; 2332 PetscBool boundary; 2333 PetscInt ghost = -1; 2334 PetscInt numChildren, numCells, c; 2335 2336 if (ghostLabel) {ierr = DMLabelGetValue(ghostLabel, f, &ghost);CHKERRQ(ierr);} 2337 ierr = DMIsBoundaryPoint(dm, f, &boundary);CHKERRQ(ierr); 2338 ierr = DMPlexGetTreeChildren(dm, f, &numChildren, NULL);CHKERRQ(ierr); 2339 if ((ghost >= 0) || boundary || numChildren) continue; 2340 ierr = DMPlexGetSupportSize(dm, f, &numCells);CHKERRQ(ierr); 2341 if (numCells == 2) { 2342 ierr = DMPlexGetSupport(dm, f, &fcells);CHKERRQ(ierr); 2343 for (c = 0; c < 2; c++) { 2344 PetscInt cell = fcells[c]; 2345 2346 if (cell >= cStart && cell < cEndInterior) { 2347 ierr = PetscSectionAddDof(neighSec,cell,1);CHKERRQ(ierr); 2348 } 2349 } 2350 } 2351 } 2352 ierr = PetscSectionSetUp(neighSec);CHKERRQ(ierr); 2353 ierr = PetscSectionGetMaxDof(neighSec,&maxNumFaces);CHKERRQ(ierr); 2354 ierr = PetscFVLeastSquaresSetMaxFaces(fvm, maxNumFaces);CHKERRQ(ierr); 2355 nStart = 0; 2356 ierr = PetscSectionGetStorageSize(neighSec,&nEnd);CHKERRQ(ierr); 2357 ierr = PetscMalloc1((nEnd-nStart),&neighbors);CHKERRQ(ierr); 2358 ierr = PetscCalloc1((cEndInterior-cStart),&counter);CHKERRQ(ierr); 2359 for (f = fStart; f < fEnd; f++) { 2360 const PetscInt *fcells; 2361 PetscBool boundary; 2362 PetscInt ghost = -1; 2363 PetscInt numChildren, numCells, c; 2364 2365 if (ghostLabel) {ierr = DMLabelGetValue(ghostLabel, f, &ghost);CHKERRQ(ierr);} 2366 ierr = DMIsBoundaryPoint(dm, f, &boundary);CHKERRQ(ierr); 2367 ierr = DMPlexGetTreeChildren(dm, f, &numChildren, NULL);CHKERRQ(ierr); 2368 if ((ghost >= 0) || boundary || numChildren) continue; 2369 ierr = DMPlexGetSupportSize(dm, f, &numCells);CHKERRQ(ierr); 2370 if (numCells == 2) { 2371 ierr = DMPlexGetSupport(dm, f, &fcells);CHKERRQ(ierr); 2372 for (c = 0; c < 2; c++) { 2373 PetscInt cell = fcells[c], off; 2374 2375 if (cell >= cStart && cell < cEndInterior) { 2376 ierr = PetscSectionGetOffset(neighSec,cell,&off);CHKERRQ(ierr); 2377 off += counter[cell - cStart]++; 2378 neighbors[off][0] = f; 2379 neighbors[off][1] = fcells[1 - c]; 2380 } 2381 } 2382 } 2383 } 2384 ierr = PetscFree(counter);CHKERRQ(ierr); 2385 ierr = PetscMalloc3(maxNumFaces*dim, &dx, maxNumFaces*dim, &grad, maxNumFaces, &gref);CHKERRQ(ierr); 2386 for (c = cStart; c < cEndInterior; c++) { 2387 PetscInt numFaces, f, d, off, ghost = -1; 2388 PetscFVCellGeom *cg; 2389 2390 ierr = DMPlexPointLocalRead(dmCell, c, cgeom, &cg);CHKERRQ(ierr); 2391 ierr = PetscSectionGetDof(neighSec, c, &numFaces);CHKERRQ(ierr); 2392 ierr = PetscSectionGetOffset(neighSec, c, &off);CHKERRQ(ierr); 2393 if (ghostLabel) {ierr = DMLabelGetValue(ghostLabel, c, &ghost);CHKERRQ(ierr);} 2394 if (ghost < 0 && numFaces < dim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell %D has only %D faces, not enough for gradient reconstruction", c, numFaces); 2395 for (f = 0; f < numFaces; ++f) { 2396 PetscFVCellGeom *cg1; 2397 PetscFVFaceGeom *fg; 2398 const PetscInt *fcells; 2399 PetscInt ncell, side, nface; 2400 2401 nface = neighbors[off + f][0]; 2402 ncell = neighbors[off + f][1]; 2403 ierr = DMPlexGetSupport(dm,nface,&fcells);CHKERRQ(ierr); 2404 side = (c != fcells[0]); 2405 ierr = DMPlexPointLocalRef(dmFace, nface, fgeom, &fg);CHKERRQ(ierr); 2406 ierr = DMPlexPointLocalRead(dmCell, ncell, cgeom, &cg1);CHKERRQ(ierr); 2407 for (d = 0; d < dim; ++d) dx[f*dim+d] = cg1->centroid[d] - cg->centroid[d]; 2408 gref[f] = fg->grad[side]; /* Gradient reconstruction term will go here */ 2409 } 2410 ierr = PetscFVComputeGradient(fvm, numFaces, dx, grad);CHKERRQ(ierr); 2411 for (f = 0; f < numFaces; ++f) { 2412 for (d = 0; d < dim; ++d) gref[f][d] = grad[f*dim+d]; 2413 } 2414 } 2415 ierr = PetscFree3(dx, grad, gref);CHKERRQ(ierr); 2416 ierr = PetscSectionDestroy(&neighSec);CHKERRQ(ierr); 2417 ierr = PetscFree(neighbors);CHKERRQ(ierr); 2418 PetscFunctionReturn(0); 2419 } 2420 2421 /*@ 2422 DMPlexComputeGradientFVM - Compute geometric factors for gradient reconstruction, which are stored in the geometry data, and compute layout for gradient data 2423 2424 Collective on dm 2425 2426 Input Arguments: 2427 + dm - The DM 2428 . fvm - The PetscFV 2429 . faceGeometry - The face geometry from DMPlexComputeFaceGeometryFVM() 2430 - cellGeometry - The face geometry from DMPlexComputeCellGeometryFVM() 2431 2432 Output Parameters: 2433 + faceGeometry - The geometric factors for gradient calculation are inserted 2434 - dmGrad - The DM describing the layout of gradient data 2435 2436 Level: developer 2437 2438 .seealso: DMPlexGetFaceGeometryFVM(), DMPlexGetCellGeometryFVM() 2439 @*/ 2440 PetscErrorCode DMPlexComputeGradientFVM(DM dm, PetscFV fvm, Vec faceGeometry, Vec cellGeometry, DM *dmGrad) 2441 { 2442 DM dmFace, dmCell; 2443 PetscScalar *fgeom, *cgeom; 2444 PetscSection sectionGrad, parentSection; 2445 PetscInt dim, pdim, cStart, cEnd, cEndInterior, c; 2446 PetscErrorCode ierr; 2447 2448 PetscFunctionBegin; 2449 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2450 ierr = PetscFVGetNumComponents(fvm, &pdim);CHKERRQ(ierr); 2451 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2452 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 2453 /* Construct the interpolant corresponding to each face from the least-square solution over the cell neighborhood */ 2454 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 2455 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 2456 ierr = VecGetArray(faceGeometry, &fgeom);CHKERRQ(ierr); 2457 ierr = VecGetArray(cellGeometry, &cgeom);CHKERRQ(ierr); 2458 ierr = DMPlexGetTree(dm,&parentSection,NULL,NULL,NULL,NULL);CHKERRQ(ierr); 2459 if (!parentSection) { 2460 ierr = BuildGradientReconstruction_Internal(dm, fvm, dmFace, fgeom, dmCell, cgeom);CHKERRQ(ierr); 2461 } else { 2462 ierr = BuildGradientReconstruction_Internal_Tree(dm, fvm, dmFace, fgeom, dmCell, cgeom);CHKERRQ(ierr); 2463 } 2464 ierr = VecRestoreArray(faceGeometry, &fgeom);CHKERRQ(ierr); 2465 ierr = VecRestoreArray(cellGeometry, &cgeom);CHKERRQ(ierr); 2466 /* Create storage for gradients */ 2467 ierr = DMClone(dm, dmGrad);CHKERRQ(ierr); 2468 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ionGrad);CHKERRQ(ierr); 2469 ierr = PetscSectionSetChart(sectionGrad, cStart, cEnd);CHKERRQ(ierr); 2470 for (c = cStart; c < cEnd; ++c) {ierr = PetscSectionSetDof(sectionGrad, c, pdim*dim);CHKERRQ(ierr);} 2471 ierr = PetscSectionSetUp(sectionGrad);CHKERRQ(ierr); 2472 ierr = DMSetLocalSection(*dmGrad, sectionGrad);CHKERRQ(ierr); 2473 ierr = PetscSectionDestroy(§ionGrad);CHKERRQ(ierr); 2474 PetscFunctionReturn(0); 2475 } 2476 2477 /*@ 2478 DMPlexGetDataFVM - Retrieve precomputed cell geometry 2479 2480 Collective on dm 2481 2482 Input Arguments: 2483 + dm - The DM 2484 - fvm - The PetscFV 2485 2486 Output Parameters: 2487 + cellGeometry - The cell geometry 2488 . faceGeometry - The face geometry 2489 - dmGrad - The gradient matrices 2490 2491 Level: developer 2492 2493 .seealso: DMPlexComputeGeometryFVM() 2494 @*/ 2495 PetscErrorCode DMPlexGetDataFVM(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM) 2496 { 2497 PetscObject cellgeomobj, facegeomobj; 2498 PetscErrorCode ierr; 2499 2500 PetscFunctionBegin; 2501 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj);CHKERRQ(ierr); 2502 if (!cellgeomobj) { 2503 Vec cellgeomInt, facegeomInt; 2504 2505 ierr = DMPlexComputeGeometryFVM(dm, &cellgeomInt, &facegeomInt);CHKERRQ(ierr); 2506 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_cellgeom_fvm",(PetscObject)cellgeomInt);CHKERRQ(ierr); 2507 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_facegeom_fvm",(PetscObject)facegeomInt);CHKERRQ(ierr); 2508 ierr = VecDestroy(&cellgeomInt);CHKERRQ(ierr); 2509 ierr = VecDestroy(&facegeomInt);CHKERRQ(ierr); 2510 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj);CHKERRQ(ierr); 2511 } 2512 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_facegeom_fvm", &facegeomobj);CHKERRQ(ierr); 2513 if (cellgeom) *cellgeom = (Vec) cellgeomobj; 2514 if (facegeom) *facegeom = (Vec) facegeomobj; 2515 if (gradDM) { 2516 PetscObject gradobj; 2517 PetscBool computeGradients; 2518 2519 ierr = PetscFVGetComputeGradients(fv,&computeGradients);CHKERRQ(ierr); 2520 if (!computeGradients) { 2521 *gradDM = NULL; 2522 PetscFunctionReturn(0); 2523 } 2524 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj);CHKERRQ(ierr); 2525 if (!gradobj) { 2526 DM dmGradInt; 2527 2528 ierr = DMPlexComputeGradientFVM(dm,fv,(Vec) facegeomobj,(Vec) cellgeomobj,&dmGradInt);CHKERRQ(ierr); 2529 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_dmgrad_fvm", (PetscObject)dmGradInt);CHKERRQ(ierr); 2530 ierr = DMDestroy(&dmGradInt);CHKERRQ(ierr); 2531 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj);CHKERRQ(ierr); 2532 } 2533 *gradDM = (DM) gradobj; 2534 } 2535 PetscFunctionReturn(0); 2536 } 2537 2538 static PetscErrorCode DMPlexCoordinatesToReference_NewtonUpdate(PetscInt dimC, PetscInt dimR, PetscScalar *J, PetscScalar *invJ, PetscScalar *work, PetscReal *resNeg, PetscReal *guess) 2539 { 2540 PetscInt l, m; 2541 2542 PetscFunctionBeginHot; 2543 if (dimC == dimR && dimR <= 3) { 2544 /* invert Jacobian, multiply */ 2545 PetscScalar det, idet; 2546 2547 switch (dimR) { 2548 case 1: 2549 invJ[0] = 1./ J[0]; 2550 break; 2551 case 2: 2552 det = J[0] * J[3] - J[1] * J[2]; 2553 idet = 1./det; 2554 invJ[0] = J[3] * idet; 2555 invJ[1] = -J[1] * idet; 2556 invJ[2] = -J[2] * idet; 2557 invJ[3] = J[0] * idet; 2558 break; 2559 case 3: 2560 { 2561 invJ[0] = J[4] * J[8] - J[5] * J[7]; 2562 invJ[1] = J[2] * J[7] - J[1] * J[8]; 2563 invJ[2] = J[1] * J[5] - J[2] * J[4]; 2564 det = invJ[0] * J[0] + invJ[1] * J[3] + invJ[2] * J[6]; 2565 idet = 1./det; 2566 invJ[0] *= idet; 2567 invJ[1] *= idet; 2568 invJ[2] *= idet; 2569 invJ[3] = idet * (J[5] * J[6] - J[3] * J[8]); 2570 invJ[4] = idet * (J[0] * J[8] - J[2] * J[6]); 2571 invJ[5] = idet * (J[2] * J[3] - J[0] * J[5]); 2572 invJ[6] = idet * (J[3] * J[7] - J[4] * J[6]); 2573 invJ[7] = idet * (J[1] * J[6] - J[0] * J[7]); 2574 invJ[8] = idet * (J[0] * J[4] - J[1] * J[3]); 2575 } 2576 break; 2577 } 2578 for (l = 0; l < dimR; l++) { 2579 for (m = 0; m < dimC; m++) { 2580 guess[l] += PetscRealPart(invJ[l * dimC + m]) * resNeg[m]; 2581 } 2582 } 2583 } else { 2584 #if defined(PETSC_USE_COMPLEX) 2585 char transpose = 'C'; 2586 #else 2587 char transpose = 'T'; 2588 #endif 2589 PetscBLASInt m = dimR; 2590 PetscBLASInt n = dimC; 2591 PetscBLASInt one = 1; 2592 PetscBLASInt worksize = dimR * dimC, info; 2593 2594 for (l = 0; l < dimC; l++) {invJ[l] = resNeg[l];} 2595 2596 PetscStackCallBLAS("LAPACKgels",LAPACKgels_(&transpose,&m,&n,&one,J,&m,invJ,&n,work,&worksize, &info)); 2597 if (info != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELS"); 2598 2599 for (l = 0; l < dimR; l++) {guess[l] += PetscRealPart(invJ[l]);} 2600 } 2601 PetscFunctionReturn(0); 2602 } 2603 2604 static PetscErrorCode DMPlexCoordinatesToReference_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt dimC, PetscInt dimR) 2605 { 2606 PetscInt coordSize, i, j, k, l, m, maxIts = 7, numV = (1 << dimR); 2607 PetscScalar *coordsScalar = NULL; 2608 PetscReal *cellData, *cellCoords, *cellCoeffs, *extJ, *resNeg; 2609 PetscScalar *J, *invJ, *work; 2610 PetscErrorCode ierr; 2611 2612 PetscFunctionBegin; 2613 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2614 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2615 if (coordSize < dimC * numV) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %D coordinates, got %D",dimC * (1 << dimR), coordSize); 2616 ierr = DMGetWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData);CHKERRQ(ierr); 2617 ierr = DMGetWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J);CHKERRQ(ierr); 2618 cellCoords = &cellData[0]; 2619 cellCoeffs = &cellData[coordSize]; 2620 extJ = &cellData[2 * coordSize]; 2621 resNeg = &cellData[2 * coordSize + dimR]; 2622 invJ = &J[dimR * dimC]; 2623 work = &J[2 * dimR * dimC]; 2624 if (dimR == 2) { 2625 const PetscInt zToPlex[4] = {0, 1, 3, 2}; 2626 2627 for (i = 0; i < 4; i++) { 2628 PetscInt plexI = zToPlex[i]; 2629 2630 for (j = 0; j < dimC; j++) { 2631 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2632 } 2633 } 2634 } else if (dimR == 3) { 2635 const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6}; 2636 2637 for (i = 0; i < 8; i++) { 2638 PetscInt plexI = zToPlex[i]; 2639 2640 for (j = 0; j < dimC; j++) { 2641 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2642 } 2643 } 2644 } else { 2645 for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);} 2646 } 2647 /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */ 2648 for (i = 0; i < dimR; i++) { 2649 PetscReal *swap; 2650 2651 for (j = 0; j < (numV / 2); j++) { 2652 for (k = 0; k < dimC; k++) { 2653 cellCoeffs[dimC * j + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]); 2654 cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]); 2655 } 2656 } 2657 2658 if (i < dimR - 1) { 2659 swap = cellCoeffs; 2660 cellCoeffs = cellCoords; 2661 cellCoords = swap; 2662 } 2663 } 2664 ierr = PetscArrayzero(refCoords,numPoints * dimR);CHKERRQ(ierr); 2665 for (j = 0; j < numPoints; j++) { 2666 for (i = 0; i < maxIts; i++) { 2667 PetscReal *guess = &refCoords[dimR * j]; 2668 2669 /* compute -residual and Jacobian */ 2670 for (k = 0; k < dimC; k++) {resNeg[k] = realCoords[dimC * j + k];} 2671 for (k = 0; k < dimC * dimR; k++) {J[k] = 0.;} 2672 for (k = 0; k < numV; k++) { 2673 PetscReal extCoord = 1.; 2674 for (l = 0; l < dimR; l++) { 2675 PetscReal coord = guess[l]; 2676 PetscInt dep = (k & (1 << l)) >> l; 2677 2678 extCoord *= dep * coord + !dep; 2679 extJ[l] = dep; 2680 2681 for (m = 0; m < dimR; m++) { 2682 PetscReal coord = guess[m]; 2683 PetscInt dep = ((k & (1 << m)) >> m) && (m != l); 2684 PetscReal mult = dep * coord + !dep; 2685 2686 extJ[l] *= mult; 2687 } 2688 } 2689 for (l = 0; l < dimC; l++) { 2690 PetscReal coeff = cellCoeffs[dimC * k + l]; 2691 2692 resNeg[l] -= coeff * extCoord; 2693 for (m = 0; m < dimR; m++) { 2694 J[dimR * l + m] += coeff * extJ[m]; 2695 } 2696 } 2697 } 2698 if (0 && PetscDefined(USE_DEBUG)) { 2699 PetscReal maxAbs = 0.; 2700 2701 for (l = 0; l < dimC; l++) { 2702 maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l])); 2703 } 2704 ierr = PetscInfo4(dm,"cell %D, point %D, iter %D: res %g\n",cell,j,i,(double) maxAbs);CHKERRQ(ierr); 2705 } 2706 2707 ierr = DMPlexCoordinatesToReference_NewtonUpdate(dimC,dimR,J,invJ,work,resNeg,guess);CHKERRQ(ierr); 2708 } 2709 } 2710 ierr = DMRestoreWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J);CHKERRQ(ierr); 2711 ierr = DMRestoreWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData);CHKERRQ(ierr); 2712 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2713 PetscFunctionReturn(0); 2714 } 2715 2716 static PetscErrorCode DMPlexReferenceToCoordinates_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt dimC, PetscInt dimR) 2717 { 2718 PetscInt coordSize, i, j, k, l, numV = (1 << dimR); 2719 PetscScalar *coordsScalar = NULL; 2720 PetscReal *cellData, *cellCoords, *cellCoeffs; 2721 PetscErrorCode ierr; 2722 2723 PetscFunctionBegin; 2724 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2725 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2726 if (coordSize < dimC * numV) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %D coordinates, got %D",dimC * (1 << dimR), coordSize); 2727 ierr = DMGetWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData);CHKERRQ(ierr); 2728 cellCoords = &cellData[0]; 2729 cellCoeffs = &cellData[coordSize]; 2730 if (dimR == 2) { 2731 const PetscInt zToPlex[4] = {0, 1, 3, 2}; 2732 2733 for (i = 0; i < 4; i++) { 2734 PetscInt plexI = zToPlex[i]; 2735 2736 for (j = 0; j < dimC; j++) { 2737 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2738 } 2739 } 2740 } else if (dimR == 3) { 2741 const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6}; 2742 2743 for (i = 0; i < 8; i++) { 2744 PetscInt plexI = zToPlex[i]; 2745 2746 for (j = 0; j < dimC; j++) { 2747 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2748 } 2749 } 2750 } else { 2751 for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);} 2752 } 2753 /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */ 2754 for (i = 0; i < dimR; i++) { 2755 PetscReal *swap; 2756 2757 for (j = 0; j < (numV / 2); j++) { 2758 for (k = 0; k < dimC; k++) { 2759 cellCoeffs[dimC * j + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]); 2760 cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]); 2761 } 2762 } 2763 2764 if (i < dimR - 1) { 2765 swap = cellCoeffs; 2766 cellCoeffs = cellCoords; 2767 cellCoords = swap; 2768 } 2769 } 2770 ierr = PetscArrayzero(realCoords,numPoints * dimC);CHKERRQ(ierr); 2771 for (j = 0; j < numPoints; j++) { 2772 const PetscReal *guess = &refCoords[dimR * j]; 2773 PetscReal *mapped = &realCoords[dimC * j]; 2774 2775 for (k = 0; k < numV; k++) { 2776 PetscReal extCoord = 1.; 2777 for (l = 0; l < dimR; l++) { 2778 PetscReal coord = guess[l]; 2779 PetscInt dep = (k & (1 << l)) >> l; 2780 2781 extCoord *= dep * coord + !dep; 2782 } 2783 for (l = 0; l < dimC; l++) { 2784 PetscReal coeff = cellCoeffs[dimC * k + l]; 2785 2786 mapped[l] += coeff * extCoord; 2787 } 2788 } 2789 } 2790 ierr = DMRestoreWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData);CHKERRQ(ierr); 2791 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2792 PetscFunctionReturn(0); 2793 } 2794 2795 /* TODO: TOBY please fix this for Nc > 1 */ 2796 static PetscErrorCode DMPlexCoordinatesToReference_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt Nc, PetscInt dimR) 2797 { 2798 PetscInt numComp, pdim, i, j, k, l, m, maxIter = 7, coordSize; 2799 PetscScalar *nodes = NULL; 2800 PetscReal *invV, *modes; 2801 PetscReal *B, *D, *resNeg; 2802 PetscScalar *J, *invJ, *work; 2803 PetscErrorCode ierr; 2804 2805 PetscFunctionBegin; 2806 ierr = PetscFEGetDimension(fe, &pdim);CHKERRQ(ierr); 2807 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 2808 if (numComp != Nc) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"coordinate discretization must have as many components (%D) as embedding dimension (!= %D)",numComp,Nc); 2809 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2810 /* convert nodes to values in the stable evaluation basis */ 2811 ierr = DMGetWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2812 invV = fe->invV; 2813 for (i = 0; i < pdim; ++i) { 2814 modes[i] = 0.; 2815 for (j = 0; j < pdim; ++j) { 2816 modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]); 2817 } 2818 } 2819 ierr = DMGetWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2820 D = &B[pdim*Nc]; 2821 resNeg = &D[pdim*Nc * dimR]; 2822 ierr = DMGetWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J);CHKERRQ(ierr); 2823 invJ = &J[Nc * dimR]; 2824 work = &invJ[Nc * dimR]; 2825 for (i = 0; i < numPoints * dimR; i++) {refCoords[i] = 0.;} 2826 for (j = 0; j < numPoints; j++) { 2827 for (i = 0; i < maxIter; i++) { /* we could batch this so that we're not making big B and D arrays all the time */ 2828 PetscReal *guess = &refCoords[j * dimR]; 2829 ierr = PetscSpaceEvaluate(fe->basisSpace, 1, guess, B, D, NULL);CHKERRQ(ierr); 2830 for (k = 0; k < Nc; k++) {resNeg[k] = realCoords[j * Nc + k];} 2831 for (k = 0; k < Nc * dimR; k++) {J[k] = 0.;} 2832 for (k = 0; k < pdim; k++) { 2833 for (l = 0; l < Nc; l++) { 2834 resNeg[l] -= modes[k] * B[k * Nc + l]; 2835 for (m = 0; m < dimR; m++) { 2836 J[l * dimR + m] += modes[k] * D[(k * Nc + l) * dimR + m]; 2837 } 2838 } 2839 } 2840 if (0 && PetscDefined(USE_DEBUG)) { 2841 PetscReal maxAbs = 0.; 2842 2843 for (l = 0; l < Nc; l++) { 2844 maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l])); 2845 } 2846 ierr = PetscInfo4(dm,"cell %D, point %D, iter %D: res %g\n",cell,j,i,(double) maxAbs);CHKERRQ(ierr); 2847 } 2848 ierr = DMPlexCoordinatesToReference_NewtonUpdate(Nc,dimR,J,invJ,work,resNeg,guess);CHKERRQ(ierr); 2849 } 2850 } 2851 ierr = DMRestoreWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J);CHKERRQ(ierr); 2852 ierr = DMRestoreWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2853 ierr = DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2854 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2855 PetscFunctionReturn(0); 2856 } 2857 2858 /* TODO: TOBY please fix this for Nc > 1 */ 2859 static PetscErrorCode DMPlexReferenceToCoordinates_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt Nc, PetscInt dimR) 2860 { 2861 PetscInt numComp, pdim, i, j, k, l, coordSize; 2862 PetscScalar *nodes = NULL; 2863 PetscReal *invV, *modes; 2864 PetscReal *B; 2865 PetscErrorCode ierr; 2866 2867 PetscFunctionBegin; 2868 ierr = PetscFEGetDimension(fe, &pdim);CHKERRQ(ierr); 2869 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 2870 if (numComp != Nc) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"coordinate discretization must have as many components (%D) as embedding dimension (!= %D)",numComp,Nc); 2871 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2872 /* convert nodes to values in the stable evaluation basis */ 2873 ierr = DMGetWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2874 invV = fe->invV; 2875 for (i = 0; i < pdim; ++i) { 2876 modes[i] = 0.; 2877 for (j = 0; j < pdim; ++j) { 2878 modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]); 2879 } 2880 } 2881 ierr = DMGetWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2882 ierr = PetscSpaceEvaluate(fe->basisSpace, numPoints, refCoords, B, NULL, NULL);CHKERRQ(ierr); 2883 for (i = 0; i < numPoints * Nc; i++) {realCoords[i] = 0.;} 2884 for (j = 0; j < numPoints; j++) { 2885 PetscReal *mapped = &realCoords[j * Nc]; 2886 2887 for (k = 0; k < pdim; k++) { 2888 for (l = 0; l < Nc; l++) { 2889 mapped[l] += modes[k] * B[(j * pdim + k) * Nc + l]; 2890 } 2891 } 2892 } 2893 ierr = DMRestoreWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2894 ierr = DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2895 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2896 PetscFunctionReturn(0); 2897 } 2898 2899 /*@ 2900 DMPlexCoordinatesToReference - Pull coordinates back from the mesh to the reference element using a single element 2901 map. This inversion will be accurate inside the reference element, but may be inaccurate for mappings that do not 2902 extend uniquely outside the reference cell (e.g, most non-affine maps) 2903 2904 Not collective 2905 2906 Input Parameters: 2907 + dm - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or 2908 implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or 2909 as a multilinear map for tensor-product elements 2910 . cell - the cell whose map is used. 2911 . numPoints - the number of points to locate 2912 - realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim()) 2913 2914 Output Parameters: 2915 . refCoords - (numPoints x dimension) array of reference coordinates (see DMGetDimension()) 2916 2917 Level: intermediate 2918 2919 .seealso: DMPlexReferenceToCoordinates() 2920 @*/ 2921 PetscErrorCode DMPlexCoordinatesToReference(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[]) 2922 { 2923 PetscInt dimC, dimR, depth, cStart, cEnd, i; 2924 DM coordDM = NULL; 2925 Vec coords; 2926 PetscFE fe = NULL; 2927 PetscErrorCode ierr; 2928 2929 PetscFunctionBegin; 2930 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2931 ierr = DMGetDimension(dm,&dimR);CHKERRQ(ierr); 2932 ierr = DMGetCoordinateDim(dm,&dimC);CHKERRQ(ierr); 2933 if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0); 2934 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 2935 ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr); 2936 ierr = DMGetCoordinateDM(dm,&coordDM);CHKERRQ(ierr); 2937 if (coordDM) { 2938 PetscInt coordFields; 2939 2940 ierr = DMGetNumFields(coordDM,&coordFields);CHKERRQ(ierr); 2941 if (coordFields) { 2942 PetscClassId id; 2943 PetscObject disc; 2944 2945 ierr = DMGetField(coordDM,0,NULL,&disc);CHKERRQ(ierr); 2946 ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); 2947 if (id == PETSCFE_CLASSID) { 2948 fe = (PetscFE) disc; 2949 } 2950 } 2951 } 2952 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2953 if (cell < cStart || cell >= cEnd) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"point %D not in cell range [%D,%D)",cell,cStart,cEnd); 2954 if (!fe) { /* implicit discretization: affine or multilinear */ 2955 PetscInt coneSize; 2956 PetscBool isSimplex, isTensor; 2957 2958 ierr = DMPlexGetConeSize(dm,cell,&coneSize);CHKERRQ(ierr); 2959 isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE; 2960 isTensor = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE; 2961 if (isSimplex) { 2962 PetscReal detJ, *v0, *J, *invJ; 2963 2964 ierr = DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 2965 J = &v0[dimC]; 2966 invJ = &J[dimC * dimC]; 2967 ierr = DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, invJ, &detJ);CHKERRQ(ierr); 2968 for (i = 0; i < numPoints; i++) { /* Apply the inverse affine transformation for each point */ 2969 const PetscReal x0[3] = {-1.,-1.,-1.}; 2970 2971 CoordinatesRealToRef(dimC, dimR, x0, v0, invJ, &realCoords[dimC * i], &refCoords[dimR * i]); 2972 } 2973 ierr = DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 2974 } else if (isTensor) { 2975 ierr = DMPlexCoordinatesToReference_Tensor(coordDM, cell, numPoints, realCoords, refCoords, coords, dimC, dimR);CHKERRQ(ierr); 2976 } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %D",coneSize); 2977 } else { 2978 ierr = DMPlexCoordinatesToReference_FE(coordDM, fe, cell, numPoints, realCoords, refCoords, coords, dimC, dimR);CHKERRQ(ierr); 2979 } 2980 PetscFunctionReturn(0); 2981 } 2982 2983 /*@ 2984 DMPlexReferenceToCoordinates - Map references coordinates to coordinates in the the mesh for a single element map. 2985 2986 Not collective 2987 2988 Input Parameters: 2989 + dm - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or 2990 implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or 2991 as a multilinear map for tensor-product elements 2992 . cell - the cell whose map is used. 2993 . numPoints - the number of points to locate 2994 - refCoords - (numPoints x dimension) array of reference coordinates (see DMGetDimension()) 2995 2996 Output Parameters: 2997 . realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim()) 2998 2999 Level: intermediate 3000 3001 .seealso: DMPlexCoordinatesToReference() 3002 @*/ 3003 PetscErrorCode DMPlexReferenceToCoordinates(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[]) 3004 { 3005 PetscInt dimC, dimR, depth, cStart, cEnd, i; 3006 DM coordDM = NULL; 3007 Vec coords; 3008 PetscFE fe = NULL; 3009 PetscErrorCode ierr; 3010 3011 PetscFunctionBegin; 3012 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 3013 ierr = DMGetDimension(dm,&dimR);CHKERRQ(ierr); 3014 ierr = DMGetCoordinateDim(dm,&dimC);CHKERRQ(ierr); 3015 if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0); 3016 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 3017 ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr); 3018 ierr = DMGetCoordinateDM(dm,&coordDM);CHKERRQ(ierr); 3019 if (coordDM) { 3020 PetscInt coordFields; 3021 3022 ierr = DMGetNumFields(coordDM,&coordFields);CHKERRQ(ierr); 3023 if (coordFields) { 3024 PetscClassId id; 3025 PetscObject disc; 3026 3027 ierr = DMGetField(coordDM,0,NULL,&disc);CHKERRQ(ierr); 3028 ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); 3029 if (id == PETSCFE_CLASSID) { 3030 fe = (PetscFE) disc; 3031 } 3032 } 3033 } 3034 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3035 if (cell < cStart || cell >= cEnd) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"point %D not in cell range [%D,%D)",cell,cStart,cEnd); 3036 if (!fe) { /* implicit discretization: affine or multilinear */ 3037 PetscInt coneSize; 3038 PetscBool isSimplex, isTensor; 3039 3040 ierr = DMPlexGetConeSize(dm,cell,&coneSize);CHKERRQ(ierr); 3041 isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE; 3042 isTensor = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE; 3043 if (isSimplex) { 3044 PetscReal detJ, *v0, *J; 3045 3046 ierr = DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 3047 J = &v0[dimC]; 3048 ierr = DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, NULL, &detJ);CHKERRQ(ierr); 3049 for (i = 0; i < numPoints; i++) { /* Apply the affine transformation for each point */ 3050 const PetscReal xi0[3] = {-1.,-1.,-1.}; 3051 3052 CoordinatesRefToReal(dimC, dimR, xi0, v0, J, &refCoords[dimR * i], &realCoords[dimC * i]); 3053 } 3054 ierr = DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 3055 } else if (isTensor) { 3056 ierr = DMPlexReferenceToCoordinates_Tensor(coordDM, cell, numPoints, refCoords, realCoords, coords, dimC, dimR);CHKERRQ(ierr); 3057 } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %D",coneSize); 3058 } else { 3059 ierr = DMPlexReferenceToCoordinates_FE(coordDM, fe, cell, numPoints, refCoords, realCoords, coords, dimC, dimR);CHKERRQ(ierr); 3060 } 3061 PetscFunctionReturn(0); 3062 } 3063 3064 /*@C 3065 DMPlexRemapGeometry - This function maps the original DM coordinates to new coordinates. 3066 3067 Not collective 3068 3069 Input Parameters: 3070 + dm - The DM 3071 . time - The time 3072 - func - The function transforming current coordinates to new coordaintes 3073 3074 Calling sequence of func: 3075 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 3076 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 3077 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 3078 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 3079 3080 + dim - The spatial dimension 3081 . Nf - The number of input fields (here 1) 3082 . NfAux - The number of input auxiliary fields 3083 . uOff - The offset of the coordinates in u[] (here 0) 3084 . uOff_x - The offset of the coordinates in u_x[] (here 0) 3085 . u - The coordinate values at this point in space 3086 . u_t - The coordinate time derivative at this point in space (here NULL) 3087 . u_x - The coordinate derivatives at this point in space 3088 . aOff - The offset of each auxiliary field in u[] 3089 . aOff_x - The offset of each auxiliary field in u_x[] 3090 . a - The auxiliary field values at this point in space 3091 . a_t - The auxiliary field time derivative at this point in space (or NULL) 3092 . a_x - The auxiliary field derivatives at this point in space 3093 . t - The current time 3094 . x - The coordinates of this point (here not used) 3095 . numConstants - The number of constants 3096 . constants - The value of each constant 3097 - f - The new coordinates at this point in space 3098 3099 Level: intermediate 3100 3101 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMProjectFieldLocal(), DMProjectFieldLabelLocal() 3102 @*/ 3103 PetscErrorCode DMPlexRemapGeometry(DM dm, PetscReal time, 3104 void (*func)(PetscInt, PetscInt, PetscInt, 3105 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 3106 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 3107 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) 3108 { 3109 DM cdm; 3110 DMField cf; 3111 Vec lCoords, tmpCoords; 3112 PetscErrorCode ierr; 3113 3114 PetscFunctionBegin; 3115 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 3116 ierr = DMGetCoordinatesLocal(dm, &lCoords);CHKERRQ(ierr); 3117 ierr = DMGetLocalVector(cdm, &tmpCoords);CHKERRQ(ierr); 3118 ierr = VecCopy(lCoords, tmpCoords);CHKERRQ(ierr); 3119 /* We have to do the coordinate field manually right now since the coordinate DM will not have its own */ 3120 ierr = DMGetCoordinateField(dm, &cf);CHKERRQ(ierr); 3121 cdm->coordinateField = cf; 3122 ierr = DMProjectFieldLocal(cdm, time, tmpCoords, &func, INSERT_VALUES, lCoords);CHKERRQ(ierr); 3123 cdm->coordinateField = NULL; 3124 ierr = DMRestoreLocalVector(cdm, &tmpCoords);CHKERRQ(ierr); 3125 PetscFunctionReturn(0); 3126 } 3127 3128 /* Shear applies the transformation, assuming we fix z, 3129 / 1 0 m_0 \ 3130 | 0 1 m_1 | 3131 \ 0 0 1 / 3132 */ 3133 static void f0_shear(PetscInt dim, PetscInt Nf, PetscInt NfAux, 3134 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 3135 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 3136 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar coords[]) 3137 { 3138 const PetscInt Nc = uOff[1]-uOff[0]; 3139 const PetscInt ax = (PetscInt) PetscRealPart(constants[0]); 3140 PetscInt c; 3141 3142 for (c = 0; c < Nc; ++c) { 3143 coords[c] = u[c] + constants[c+1]*u[ax]; 3144 } 3145 } 3146 3147 /*@C 3148 DMPlexShearGeometry - This shears the domain, meaning adds a multiple of the shear coordinate to all other coordinates. 3149 3150 Not collective 3151 3152 Input Parameters: 3153 + dm - The DM 3154 . direction - The shear coordinate direction, e.g. 0 is the x-axis 3155 - multipliers - The multiplier m for each direction which is not the shear direction 3156 3157 Level: intermediate 3158 3159 .seealso: DMPlexRemapGeometry() 3160 @*/ 3161 PetscErrorCode DMPlexShearGeometry(DM dm, DMDirection direction, PetscReal multipliers[]) 3162 { 3163 DM cdm; 3164 PetscDS cds; 3165 PetscObject obj; 3166 PetscClassId id; 3167 PetscScalar *moduli; 3168 const PetscInt dir = (PetscInt) direction; 3169 PetscInt dE, d, e; 3170 PetscErrorCode ierr; 3171 3172 PetscFunctionBegin; 3173 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 3174 ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr); 3175 ierr = PetscMalloc1(dE+1, &moduli);CHKERRQ(ierr); 3176 moduli[0] = dir; 3177 for (d = 0, e = 0; d < dE; ++d) moduli[d] = d == dir ? 0.0 : (multipliers ? multipliers[e++] : 1.0); 3178 ierr = DMGetDS(cdm, &cds);CHKERRQ(ierr); 3179 ierr = PetscDSGetDiscretization(cds, 0, &obj);CHKERRQ(ierr); 3180 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3181 if (id != PETSCFE_CLASSID) { 3182 Vec lCoords; 3183 PetscSection cSection; 3184 PetscScalar *coords; 3185 PetscInt vStart, vEnd, v; 3186 3187 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3188 ierr = DMGetCoordinateSection(dm, &cSection);CHKERRQ(ierr); 3189 ierr = DMGetCoordinatesLocal(dm, &lCoords);CHKERRQ(ierr); 3190 ierr = VecGetArray(lCoords, &coords);CHKERRQ(ierr); 3191 for (v = vStart; v < vEnd; ++v) { 3192 PetscReal ds; 3193 PetscInt off, c; 3194 3195 ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr); 3196 ds = PetscRealPart(coords[off+dir]); 3197 for (c = 0; c < dE; ++c) coords[off+c] += moduli[c]*ds; 3198 } 3199 ierr = VecRestoreArray(lCoords, &coords);CHKERRQ(ierr); 3200 } else { 3201 ierr = PetscDSSetConstants(cds, dE+1, moduli);CHKERRQ(ierr); 3202 ierr = DMPlexRemapGeometry(dm, 0.0, f0_shear);CHKERRQ(ierr); 3203 } 3204 ierr = PetscFree(moduli);CHKERRQ(ierr); 3205 PetscFunctionReturn(0); 3206 } 3207