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