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