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/Output Parameter: 831 . coords - The coordinates of a segment, on output the new y-coordinate, and 0 for x 832 833 Output Parameter: 834 . R - The rotation which accomplishes the projection 835 836 Level: developer 837 838 .seealso: DMPlexComputeProjection3Dto1D(), DMPlexComputeProjection3Dto2D() 839 @*/ 840 PetscErrorCode DMPlexComputeProjection2Dto1D(PetscScalar coords[], PetscReal R[]) 841 { 842 const PetscReal x = PetscRealPart(coords[2] - coords[0]); 843 const PetscReal y = PetscRealPart(coords[3] - coords[1]); 844 const PetscReal r = PetscSqrtReal(x*x + y*y), c = x/r, s = y/r; 845 846 PetscFunctionBegin; 847 R[0] = c; R[1] = -s; 848 R[2] = s; R[3] = c; 849 coords[0] = 0.0; 850 coords[1] = r; 851 PetscFunctionReturn(0); 852 } 853 854 /*@C 855 DMPlexComputeProjection3Dto1D - Rewrite coordinates to be the 1D projection of the 3D coordinates 856 857 Not collective 858 859 Input/Output Parameter: 860 . coords - The coordinates of a segment; on output, the new y-coordinate, and 0 for x and z 861 862 Output Parameter: 863 . R - The rotation which accomplishes the projection 864 865 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 866 867 Level: developer 868 869 .seealso: DMPlexComputeProjection2Dto1D(), DMPlexComputeProjection3Dto2D() 870 @*/ 871 PetscErrorCode DMPlexComputeProjection3Dto1D(PetscScalar coords[], PetscReal R[]) 872 { 873 PetscReal x = PetscRealPart(coords[3] - coords[0]); 874 PetscReal y = PetscRealPart(coords[4] - coords[1]); 875 PetscReal z = PetscRealPart(coords[5] - coords[2]); 876 PetscReal r = PetscSqrtReal(x*x + y*y + z*z); 877 PetscReal rinv = 1. / r; 878 PetscFunctionBegin; 879 880 x *= rinv; y *= rinv; z *= rinv; 881 if (x > 0.) { 882 PetscReal inv1pX = 1./ (1. + x); 883 884 R[0] = x; R[1] = -y; R[2] = -z; 885 R[3] = y; R[4] = 1. - y*y*inv1pX; R[5] = -y*z*inv1pX; 886 R[6] = z; R[7] = -y*z*inv1pX; R[8] = 1. - z*z*inv1pX; 887 } 888 else { 889 PetscReal inv1mX = 1./ (1. - x); 890 891 R[0] = x; R[1] = z; R[2] = y; 892 R[3] = y; R[4] = -y*z*inv1mX; R[5] = 1. - y*y*inv1mX; 893 R[6] = z; R[7] = 1. - z*z*inv1mX; R[8] = -y*z*inv1mX; 894 } 895 coords[0] = 0.0; 896 coords[1] = r; 897 PetscFunctionReturn(0); 898 } 899 900 /*@ 901 DMPlexComputeProjection3Dto2D - Rewrite coordinates of 3 or more coplanar 3D points to a common 2D basis for the 902 plane. The normal is defined by positive orientation of the first 3 points. 903 904 Not collective 905 906 Input Parameter: 907 . coordSize - Length of coordinate array (3x number of points); must be at least 9 (3 points) 908 909 Input/Output Parameter: 910 . coords - The interlaced coordinates of each coplanar 3D point; on output the first 911 2*coordSize/3 entries contain interlaced 2D points, with the rest undefined 912 913 Output Parameter: 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 Parameters: 1572 + dm - the DM 1573 - cell - the cell 1574 1575 Output Parameters: 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 Parameters: 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 Parameters: 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 Parameters: 1991 + dm - the DM 1992 - cell - the cell 1993 1994 Output Parameters: 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 Parameter: 2243 . dm - the DM 2244 2245 Output Parameter: 2246 . minradius - the minimum 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 Parameters: 2267 + dm - the DM 2268 - minradius - the minimum 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 Parameters: 2456 + dm - The DM 2457 . fvm - The PetscFV 2458 - cellGeometry - The face geometry from DMPlexComputeCellGeometryFVM() 2459 2460 Input/Output Parameter: 2461 . faceGeometry - The face geometry from DMPlexComputeFaceGeometryFVM(); on output 2462 the geometric factors for gradient calculation are inserted 2463 2464 Output Parameter: 2465 . dmGrad - The DM describing the layout of gradient data 2466 2467 Level: developer 2468 2469 .seealso: DMPlexGetFaceGeometryFVM(), DMPlexGetCellGeometryFVM() 2470 @*/ 2471 PetscErrorCode DMPlexComputeGradientFVM(DM dm, PetscFV fvm, Vec faceGeometry, Vec cellGeometry, DM *dmGrad) 2472 { 2473 DM dmFace, dmCell; 2474 PetscScalar *fgeom, *cgeom; 2475 PetscSection sectionGrad, parentSection; 2476 PetscInt dim, pdim, cStart, cEnd, cEndInterior, c; 2477 PetscErrorCode ierr; 2478 2479 PetscFunctionBegin; 2480 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2481 ierr = PetscFVGetNumComponents(fvm, &pdim);CHKERRQ(ierr); 2482 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2483 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 2484 /* Construct the interpolant corresponding to each face from the least-square solution over the cell neighborhood */ 2485 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 2486 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 2487 ierr = VecGetArray(faceGeometry, &fgeom);CHKERRQ(ierr); 2488 ierr = VecGetArray(cellGeometry, &cgeom);CHKERRQ(ierr); 2489 ierr = DMPlexGetTree(dm,&parentSection,NULL,NULL,NULL,NULL);CHKERRQ(ierr); 2490 if (!parentSection) { 2491 ierr = BuildGradientReconstruction_Internal(dm, fvm, dmFace, fgeom, dmCell, cgeom);CHKERRQ(ierr); 2492 } else { 2493 ierr = BuildGradientReconstruction_Internal_Tree(dm, fvm, dmFace, fgeom, dmCell, cgeom);CHKERRQ(ierr); 2494 } 2495 ierr = VecRestoreArray(faceGeometry, &fgeom);CHKERRQ(ierr); 2496 ierr = VecRestoreArray(cellGeometry, &cgeom);CHKERRQ(ierr); 2497 /* Create storage for gradients */ 2498 ierr = DMClone(dm, dmGrad);CHKERRQ(ierr); 2499 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ionGrad);CHKERRQ(ierr); 2500 ierr = PetscSectionSetChart(sectionGrad, cStart, cEnd);CHKERRQ(ierr); 2501 for (c = cStart; c < cEnd; ++c) {ierr = PetscSectionSetDof(sectionGrad, c, pdim*dim);CHKERRQ(ierr);} 2502 ierr = PetscSectionSetUp(sectionGrad);CHKERRQ(ierr); 2503 ierr = DMSetLocalSection(*dmGrad, sectionGrad);CHKERRQ(ierr); 2504 ierr = PetscSectionDestroy(§ionGrad);CHKERRQ(ierr); 2505 PetscFunctionReturn(0); 2506 } 2507 2508 /*@ 2509 DMPlexGetDataFVM - Retrieve precomputed cell geometry 2510 2511 Collective on dm 2512 2513 Input Parameters: 2514 + dm - The DM 2515 - fv - The PetscFV 2516 2517 Output Parameters: 2518 + cellGeometry - The cell geometry 2519 . faceGeometry - The face geometry 2520 - gradDM - The gradient matrices 2521 2522 Level: developer 2523 2524 .seealso: DMPlexComputeGeometryFVM() 2525 @*/ 2526 PetscErrorCode DMPlexGetDataFVM(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM) 2527 { 2528 PetscObject cellgeomobj, facegeomobj; 2529 PetscErrorCode ierr; 2530 2531 PetscFunctionBegin; 2532 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj);CHKERRQ(ierr); 2533 if (!cellgeomobj) { 2534 Vec cellgeomInt, facegeomInt; 2535 2536 ierr = DMPlexComputeGeometryFVM(dm, &cellgeomInt, &facegeomInt);CHKERRQ(ierr); 2537 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_cellgeom_fvm",(PetscObject)cellgeomInt);CHKERRQ(ierr); 2538 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_facegeom_fvm",(PetscObject)facegeomInt);CHKERRQ(ierr); 2539 ierr = VecDestroy(&cellgeomInt);CHKERRQ(ierr); 2540 ierr = VecDestroy(&facegeomInt);CHKERRQ(ierr); 2541 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_cellgeom_fvm", &cellgeomobj);CHKERRQ(ierr); 2542 } 2543 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_facegeom_fvm", &facegeomobj);CHKERRQ(ierr); 2544 if (cellgeom) *cellgeom = (Vec) cellgeomobj; 2545 if (facegeom) *facegeom = (Vec) facegeomobj; 2546 if (gradDM) { 2547 PetscObject gradobj; 2548 PetscBool computeGradients; 2549 2550 ierr = PetscFVGetComputeGradients(fv,&computeGradients);CHKERRQ(ierr); 2551 if (!computeGradients) { 2552 *gradDM = NULL; 2553 PetscFunctionReturn(0); 2554 } 2555 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj);CHKERRQ(ierr); 2556 if (!gradobj) { 2557 DM dmGradInt; 2558 2559 ierr = DMPlexComputeGradientFVM(dm,fv,(Vec) facegeomobj,(Vec) cellgeomobj,&dmGradInt);CHKERRQ(ierr); 2560 ierr = PetscObjectCompose((PetscObject) dm, "DMPlex_dmgrad_fvm", (PetscObject)dmGradInt);CHKERRQ(ierr); 2561 ierr = DMDestroy(&dmGradInt);CHKERRQ(ierr); 2562 ierr = PetscObjectQuery((PetscObject) dm, "DMPlex_dmgrad_fvm", &gradobj);CHKERRQ(ierr); 2563 } 2564 *gradDM = (DM) gradobj; 2565 } 2566 PetscFunctionReturn(0); 2567 } 2568 2569 static PetscErrorCode DMPlexCoordinatesToReference_NewtonUpdate(PetscInt dimC, PetscInt dimR, PetscScalar *J, PetscScalar *invJ, PetscScalar *work, PetscReal *resNeg, PetscReal *guess) 2570 { 2571 PetscInt l, m; 2572 2573 PetscFunctionBeginHot; 2574 if (dimC == dimR && dimR <= 3) { 2575 /* invert Jacobian, multiply */ 2576 PetscScalar det, idet; 2577 2578 switch (dimR) { 2579 case 1: 2580 invJ[0] = 1./ J[0]; 2581 break; 2582 case 2: 2583 det = J[0] * J[3] - J[1] * J[2]; 2584 idet = 1./det; 2585 invJ[0] = J[3] * idet; 2586 invJ[1] = -J[1] * idet; 2587 invJ[2] = -J[2] * idet; 2588 invJ[3] = J[0] * idet; 2589 break; 2590 case 3: 2591 { 2592 invJ[0] = J[4] * J[8] - J[5] * J[7]; 2593 invJ[1] = J[2] * J[7] - J[1] * J[8]; 2594 invJ[2] = J[1] * J[5] - J[2] * J[4]; 2595 det = invJ[0] * J[0] + invJ[1] * J[3] + invJ[2] * J[6]; 2596 idet = 1./det; 2597 invJ[0] *= idet; 2598 invJ[1] *= idet; 2599 invJ[2] *= idet; 2600 invJ[3] = idet * (J[5] * J[6] - J[3] * J[8]); 2601 invJ[4] = idet * (J[0] * J[8] - J[2] * J[6]); 2602 invJ[5] = idet * (J[2] * J[3] - J[0] * J[5]); 2603 invJ[6] = idet * (J[3] * J[7] - J[4] * J[6]); 2604 invJ[7] = idet * (J[1] * J[6] - J[0] * J[7]); 2605 invJ[8] = idet * (J[0] * J[4] - J[1] * J[3]); 2606 } 2607 break; 2608 } 2609 for (l = 0; l < dimR; l++) { 2610 for (m = 0; m < dimC; m++) { 2611 guess[l] += PetscRealPart(invJ[l * dimC + m]) * resNeg[m]; 2612 } 2613 } 2614 } else { 2615 #if defined(PETSC_USE_COMPLEX) 2616 char transpose = 'C'; 2617 #else 2618 char transpose = 'T'; 2619 #endif 2620 PetscBLASInt m = dimR; 2621 PetscBLASInt n = dimC; 2622 PetscBLASInt one = 1; 2623 PetscBLASInt worksize = dimR * dimC, info; 2624 2625 for (l = 0; l < dimC; l++) {invJ[l] = resNeg[l];} 2626 2627 PetscStackCallBLAS("LAPACKgels",LAPACKgels_(&transpose,&m,&n,&one,J,&m,invJ,&n,work,&worksize, &info)); 2628 if (info != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELS"); 2629 2630 for (l = 0; l < dimR; l++) {guess[l] += PetscRealPart(invJ[l]);} 2631 } 2632 PetscFunctionReturn(0); 2633 } 2634 2635 static PetscErrorCode DMPlexCoordinatesToReference_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt dimC, PetscInt dimR) 2636 { 2637 PetscInt coordSize, i, j, k, l, m, maxIts = 7, numV = (1 << dimR); 2638 PetscScalar *coordsScalar = NULL; 2639 PetscReal *cellData, *cellCoords, *cellCoeffs, *extJ, *resNeg; 2640 PetscScalar *J, *invJ, *work; 2641 PetscErrorCode ierr; 2642 2643 PetscFunctionBegin; 2644 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2645 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2646 if (coordSize < dimC * numV) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %D coordinates, got %D",dimC * (1 << dimR), coordSize); 2647 ierr = DMGetWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData);CHKERRQ(ierr); 2648 ierr = DMGetWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J);CHKERRQ(ierr); 2649 cellCoords = &cellData[0]; 2650 cellCoeffs = &cellData[coordSize]; 2651 extJ = &cellData[2 * coordSize]; 2652 resNeg = &cellData[2 * coordSize + dimR]; 2653 invJ = &J[dimR * dimC]; 2654 work = &J[2 * dimR * dimC]; 2655 if (dimR == 2) { 2656 const PetscInt zToPlex[4] = {0, 1, 3, 2}; 2657 2658 for (i = 0; i < 4; i++) { 2659 PetscInt plexI = zToPlex[i]; 2660 2661 for (j = 0; j < dimC; j++) { 2662 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2663 } 2664 } 2665 } else if (dimR == 3) { 2666 const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6}; 2667 2668 for (i = 0; i < 8; i++) { 2669 PetscInt plexI = zToPlex[i]; 2670 2671 for (j = 0; j < dimC; j++) { 2672 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2673 } 2674 } 2675 } else { 2676 for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);} 2677 } 2678 /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */ 2679 for (i = 0; i < dimR; i++) { 2680 PetscReal *swap; 2681 2682 for (j = 0; j < (numV / 2); j++) { 2683 for (k = 0; k < dimC; k++) { 2684 cellCoeffs[dimC * j + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]); 2685 cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]); 2686 } 2687 } 2688 2689 if (i < dimR - 1) { 2690 swap = cellCoeffs; 2691 cellCoeffs = cellCoords; 2692 cellCoords = swap; 2693 } 2694 } 2695 ierr = PetscArrayzero(refCoords,numPoints * dimR);CHKERRQ(ierr); 2696 for (j = 0; j < numPoints; j++) { 2697 for (i = 0; i < maxIts; i++) { 2698 PetscReal *guess = &refCoords[dimR * j]; 2699 2700 /* compute -residual and Jacobian */ 2701 for (k = 0; k < dimC; k++) {resNeg[k] = realCoords[dimC * j + k];} 2702 for (k = 0; k < dimC * dimR; k++) {J[k] = 0.;} 2703 for (k = 0; k < numV; k++) { 2704 PetscReal extCoord = 1.; 2705 for (l = 0; l < dimR; l++) { 2706 PetscReal coord = guess[l]; 2707 PetscInt dep = (k & (1 << l)) >> l; 2708 2709 extCoord *= dep * coord + !dep; 2710 extJ[l] = dep; 2711 2712 for (m = 0; m < dimR; m++) { 2713 PetscReal coord = guess[m]; 2714 PetscInt dep = ((k & (1 << m)) >> m) && (m != l); 2715 PetscReal mult = dep * coord + !dep; 2716 2717 extJ[l] *= mult; 2718 } 2719 } 2720 for (l = 0; l < dimC; l++) { 2721 PetscReal coeff = cellCoeffs[dimC * k + l]; 2722 2723 resNeg[l] -= coeff * extCoord; 2724 for (m = 0; m < dimR; m++) { 2725 J[dimR * l + m] += coeff * extJ[m]; 2726 } 2727 } 2728 } 2729 if (0 && PetscDefined(USE_DEBUG)) { 2730 PetscReal maxAbs = 0.; 2731 2732 for (l = 0; l < dimC; l++) { 2733 maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l])); 2734 } 2735 ierr = PetscInfo4(dm,"cell %D, point %D, iter %D: res %g\n",cell,j,i,(double) maxAbs);CHKERRQ(ierr); 2736 } 2737 2738 ierr = DMPlexCoordinatesToReference_NewtonUpdate(dimC,dimR,J,invJ,work,resNeg,guess);CHKERRQ(ierr); 2739 } 2740 } 2741 ierr = DMRestoreWorkArray(dm, 3 * dimR * dimC, MPIU_SCALAR, &J);CHKERRQ(ierr); 2742 ierr = DMRestoreWorkArray(dm, 2 * coordSize + dimR + dimC, MPIU_REAL, &cellData);CHKERRQ(ierr); 2743 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2744 PetscFunctionReturn(0); 2745 } 2746 2747 static PetscErrorCode DMPlexReferenceToCoordinates_Tensor(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt dimC, PetscInt dimR) 2748 { 2749 PetscInt coordSize, i, j, k, l, numV = (1 << dimR); 2750 PetscScalar *coordsScalar = NULL; 2751 PetscReal *cellData, *cellCoords, *cellCoeffs; 2752 PetscErrorCode ierr; 2753 2754 PetscFunctionBegin; 2755 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2756 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2757 if (coordSize < dimC * numV) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expecting at least %D coordinates, got %D",dimC * (1 << dimR), coordSize); 2758 ierr = DMGetWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData);CHKERRQ(ierr); 2759 cellCoords = &cellData[0]; 2760 cellCoeffs = &cellData[coordSize]; 2761 if (dimR == 2) { 2762 const PetscInt zToPlex[4] = {0, 1, 3, 2}; 2763 2764 for (i = 0; i < 4; i++) { 2765 PetscInt plexI = zToPlex[i]; 2766 2767 for (j = 0; j < dimC; j++) { 2768 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2769 } 2770 } 2771 } else if (dimR == 3) { 2772 const PetscInt zToPlex[8] = {0, 3, 1, 2, 4, 5, 7, 6}; 2773 2774 for (i = 0; i < 8; i++) { 2775 PetscInt plexI = zToPlex[i]; 2776 2777 for (j = 0; j < dimC; j++) { 2778 cellCoords[dimC * i + j] = PetscRealPart(coordsScalar[dimC * plexI + j]); 2779 } 2780 } 2781 } else { 2782 for (i = 0; i < coordSize; i++) {cellCoords[i] = PetscRealPart(coordsScalar[i]);} 2783 } 2784 /* Perform the shuffling transform that converts values at the corners of [-1,1]^d to coefficients */ 2785 for (i = 0; i < dimR; i++) { 2786 PetscReal *swap; 2787 2788 for (j = 0; j < (numV / 2); j++) { 2789 for (k = 0; k < dimC; k++) { 2790 cellCoeffs[dimC * j + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] + cellCoords[dimC * 2 * j + k]); 2791 cellCoeffs[dimC * (j + (numV / 2)) + k] = 0.5 * (cellCoords[dimC * (2 * j + 1) + k] - cellCoords[dimC * 2 * j + k]); 2792 } 2793 } 2794 2795 if (i < dimR - 1) { 2796 swap = cellCoeffs; 2797 cellCoeffs = cellCoords; 2798 cellCoords = swap; 2799 } 2800 } 2801 ierr = PetscArrayzero(realCoords,numPoints * dimC);CHKERRQ(ierr); 2802 for (j = 0; j < numPoints; j++) { 2803 const PetscReal *guess = &refCoords[dimR * j]; 2804 PetscReal *mapped = &realCoords[dimC * j]; 2805 2806 for (k = 0; k < numV; k++) { 2807 PetscReal extCoord = 1.; 2808 for (l = 0; l < dimR; l++) { 2809 PetscReal coord = guess[l]; 2810 PetscInt dep = (k & (1 << l)) >> l; 2811 2812 extCoord *= dep * coord + !dep; 2813 } 2814 for (l = 0; l < dimC; l++) { 2815 PetscReal coeff = cellCoeffs[dimC * k + l]; 2816 2817 mapped[l] += coeff * extCoord; 2818 } 2819 } 2820 } 2821 ierr = DMRestoreWorkArray(dm, 2 * coordSize, MPIU_REAL, &cellData);CHKERRQ(ierr); 2822 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &coordsScalar);CHKERRQ(ierr); 2823 PetscFunctionReturn(0); 2824 } 2825 2826 /* TODO: TOBY please fix this for Nc > 1 */ 2827 static PetscErrorCode DMPlexCoordinatesToReference_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[], Vec coords, PetscInt Nc, PetscInt dimR) 2828 { 2829 PetscInt numComp, pdim, i, j, k, l, m, maxIter = 7, coordSize; 2830 PetscScalar *nodes = NULL; 2831 PetscReal *invV, *modes; 2832 PetscReal *B, *D, *resNeg; 2833 PetscScalar *J, *invJ, *work; 2834 PetscErrorCode ierr; 2835 2836 PetscFunctionBegin; 2837 ierr = PetscFEGetDimension(fe, &pdim);CHKERRQ(ierr); 2838 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 2839 if (numComp != Nc) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"coordinate discretization must have as many components (%D) as embedding dimension (!= %D)",numComp,Nc); 2840 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2841 /* convert nodes to values in the stable evaluation basis */ 2842 ierr = DMGetWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2843 invV = fe->invV; 2844 for (i = 0; i < pdim; ++i) { 2845 modes[i] = 0.; 2846 for (j = 0; j < pdim; ++j) { 2847 modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]); 2848 } 2849 } 2850 ierr = DMGetWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2851 D = &B[pdim*Nc]; 2852 resNeg = &D[pdim*Nc * dimR]; 2853 ierr = DMGetWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J);CHKERRQ(ierr); 2854 invJ = &J[Nc * dimR]; 2855 work = &invJ[Nc * dimR]; 2856 for (i = 0; i < numPoints * dimR; i++) {refCoords[i] = 0.;} 2857 for (j = 0; j < numPoints; j++) { 2858 for (i = 0; i < maxIter; i++) { /* we could batch this so that we're not making big B and D arrays all the time */ 2859 PetscReal *guess = &refCoords[j * dimR]; 2860 ierr = PetscSpaceEvaluate(fe->basisSpace, 1, guess, B, D, NULL);CHKERRQ(ierr); 2861 for (k = 0; k < Nc; k++) {resNeg[k] = realCoords[j * Nc + k];} 2862 for (k = 0; k < Nc * dimR; k++) {J[k] = 0.;} 2863 for (k = 0; k < pdim; k++) { 2864 for (l = 0; l < Nc; l++) { 2865 resNeg[l] -= modes[k] * B[k * Nc + l]; 2866 for (m = 0; m < dimR; m++) { 2867 J[l * dimR + m] += modes[k] * D[(k * Nc + l) * dimR + m]; 2868 } 2869 } 2870 } 2871 if (0 && PetscDefined(USE_DEBUG)) { 2872 PetscReal maxAbs = 0.; 2873 2874 for (l = 0; l < Nc; l++) { 2875 maxAbs = PetscMax(maxAbs,PetscAbsReal(resNeg[l])); 2876 } 2877 ierr = PetscInfo4(dm,"cell %D, point %D, iter %D: res %g\n",cell,j,i,(double) maxAbs);CHKERRQ(ierr); 2878 } 2879 ierr = DMPlexCoordinatesToReference_NewtonUpdate(Nc,dimR,J,invJ,work,resNeg,guess);CHKERRQ(ierr); 2880 } 2881 } 2882 ierr = DMRestoreWorkArray(dm,3 * Nc * dimR,MPIU_SCALAR,&J);CHKERRQ(ierr); 2883 ierr = DMRestoreWorkArray(dm,pdim * Nc + pdim * Nc * dimR + Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2884 ierr = DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2885 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2886 PetscFunctionReturn(0); 2887 } 2888 2889 /* TODO: TOBY please fix this for Nc > 1 */ 2890 static PetscErrorCode DMPlexReferenceToCoordinates_FE(DM dm, PetscFE fe, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[], Vec coords, PetscInt Nc, PetscInt dimR) 2891 { 2892 PetscInt numComp, pdim, i, j, k, l, coordSize; 2893 PetscScalar *nodes = NULL; 2894 PetscReal *invV, *modes; 2895 PetscReal *B; 2896 PetscErrorCode ierr; 2897 2898 PetscFunctionBegin; 2899 ierr = PetscFEGetDimension(fe, &pdim);CHKERRQ(ierr); 2900 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 2901 if (numComp != Nc) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"coordinate discretization must have as many components (%D) as embedding dimension (!= %D)",numComp,Nc); 2902 ierr = DMPlexVecGetClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2903 /* convert nodes to values in the stable evaluation basis */ 2904 ierr = DMGetWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2905 invV = fe->invV; 2906 for (i = 0; i < pdim; ++i) { 2907 modes[i] = 0.; 2908 for (j = 0; j < pdim; ++j) { 2909 modes[i] += invV[i * pdim + j] * PetscRealPart(nodes[j]); 2910 } 2911 } 2912 ierr = DMGetWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2913 ierr = PetscSpaceEvaluate(fe->basisSpace, numPoints, refCoords, B, NULL, NULL);CHKERRQ(ierr); 2914 for (i = 0; i < numPoints * Nc; i++) {realCoords[i] = 0.;} 2915 for (j = 0; j < numPoints; j++) { 2916 PetscReal *mapped = &realCoords[j * Nc]; 2917 2918 for (k = 0; k < pdim; k++) { 2919 for (l = 0; l < Nc; l++) { 2920 mapped[l] += modes[k] * B[(j * pdim + k) * Nc + l]; 2921 } 2922 } 2923 } 2924 ierr = DMRestoreWorkArray(dm,numPoints * pdim * Nc,MPIU_REAL,&B);CHKERRQ(ierr); 2925 ierr = DMRestoreWorkArray(dm,pdim,MPIU_REAL,&modes);CHKERRQ(ierr); 2926 ierr = DMPlexVecRestoreClosure(dm, NULL, coords, cell, &coordSize, &nodes);CHKERRQ(ierr); 2927 PetscFunctionReturn(0); 2928 } 2929 2930 /*@ 2931 DMPlexCoordinatesToReference - Pull coordinates back from the mesh to the reference element using a single element 2932 map. This inversion will be accurate inside the reference element, but may be inaccurate for mappings that do not 2933 extend uniquely outside the reference cell (e.g, most non-affine maps) 2934 2935 Not collective 2936 2937 Input Parameters: 2938 + dm - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or 2939 implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or 2940 as a multilinear map for tensor-product elements 2941 . cell - the cell whose map is used. 2942 . numPoints - the number of points to locate 2943 - realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim()) 2944 2945 Output Parameters: 2946 . refCoords - (numPoints x dimension) array of reference coordinates (see DMGetDimension()) 2947 2948 Level: intermediate 2949 2950 .seealso: DMPlexReferenceToCoordinates() 2951 @*/ 2952 PetscErrorCode DMPlexCoordinatesToReference(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal realCoords[], PetscReal refCoords[]) 2953 { 2954 PetscInt dimC, dimR, depth, cStart, cEnd, i; 2955 DM coordDM = NULL; 2956 Vec coords; 2957 PetscFE fe = NULL; 2958 PetscErrorCode ierr; 2959 2960 PetscFunctionBegin; 2961 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 2962 ierr = DMGetDimension(dm,&dimR);CHKERRQ(ierr); 2963 ierr = DMGetCoordinateDim(dm,&dimC);CHKERRQ(ierr); 2964 if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0); 2965 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 2966 ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr); 2967 ierr = DMGetCoordinateDM(dm,&coordDM);CHKERRQ(ierr); 2968 if (coordDM) { 2969 PetscInt coordFields; 2970 2971 ierr = DMGetNumFields(coordDM,&coordFields);CHKERRQ(ierr); 2972 if (coordFields) { 2973 PetscClassId id; 2974 PetscObject disc; 2975 2976 ierr = DMGetField(coordDM,0,NULL,&disc);CHKERRQ(ierr); 2977 ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); 2978 if (id == PETSCFE_CLASSID) { 2979 fe = (PetscFE) disc; 2980 } 2981 } 2982 } 2983 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2984 if (cell < cStart || cell >= cEnd) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"point %D not in cell range [%D,%D)",cell,cStart,cEnd); 2985 if (!fe) { /* implicit discretization: affine or multilinear */ 2986 PetscInt coneSize; 2987 PetscBool isSimplex, isTensor; 2988 2989 ierr = DMPlexGetConeSize(dm,cell,&coneSize);CHKERRQ(ierr); 2990 isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE; 2991 isTensor = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE; 2992 if (isSimplex) { 2993 PetscReal detJ, *v0, *J, *invJ; 2994 2995 ierr = DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 2996 J = &v0[dimC]; 2997 invJ = &J[dimC * dimC]; 2998 ierr = DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, invJ, &detJ);CHKERRQ(ierr); 2999 for (i = 0; i < numPoints; i++) { /* Apply the inverse affine transformation for each point */ 3000 const PetscReal x0[3] = {-1.,-1.,-1.}; 3001 3002 CoordinatesRealToRef(dimC, dimR, x0, v0, invJ, &realCoords[dimC * i], &refCoords[dimR * i]); 3003 } 3004 ierr = DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 3005 } else if (isTensor) { 3006 ierr = DMPlexCoordinatesToReference_Tensor(coordDM, cell, numPoints, realCoords, refCoords, coords, dimC, dimR);CHKERRQ(ierr); 3007 } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %D",coneSize); 3008 } else { 3009 ierr = DMPlexCoordinatesToReference_FE(coordDM, fe, cell, numPoints, realCoords, refCoords, coords, dimC, dimR);CHKERRQ(ierr); 3010 } 3011 PetscFunctionReturn(0); 3012 } 3013 3014 /*@ 3015 DMPlexReferenceToCoordinates - Map references coordinates to coordinates in the the mesh for a single element map. 3016 3017 Not collective 3018 3019 Input Parameters: 3020 + dm - The mesh, with coordinate maps defined either by a PetscDS for the coordinate DM (see DMGetCoordinateDM()) or 3021 implicitly by the coordinates of the corner vertices of the cell: as an affine map for simplicial elements, or 3022 as a multilinear map for tensor-product elements 3023 . cell - the cell whose map is used. 3024 . numPoints - the number of points to locate 3025 - refCoords - (numPoints x dimension) array of reference coordinates (see DMGetDimension()) 3026 3027 Output Parameters: 3028 . realCoords - (numPoints x coordinate dimension) array of coordinates (see DMGetCoordinateDim()) 3029 3030 Level: intermediate 3031 3032 .seealso: DMPlexCoordinatesToReference() 3033 @*/ 3034 PetscErrorCode DMPlexReferenceToCoordinates(DM dm, PetscInt cell, PetscInt numPoints, const PetscReal refCoords[], PetscReal realCoords[]) 3035 { 3036 PetscInt dimC, dimR, depth, cStart, cEnd, i; 3037 DM coordDM = NULL; 3038 Vec coords; 3039 PetscFE fe = NULL; 3040 PetscErrorCode ierr; 3041 3042 PetscFunctionBegin; 3043 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 3044 ierr = DMGetDimension(dm,&dimR);CHKERRQ(ierr); 3045 ierr = DMGetCoordinateDim(dm,&dimC);CHKERRQ(ierr); 3046 if (dimR <= 0 || dimC <= 0 || numPoints <= 0) PetscFunctionReturn(0); 3047 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 3048 ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr); 3049 ierr = DMGetCoordinateDM(dm,&coordDM);CHKERRQ(ierr); 3050 if (coordDM) { 3051 PetscInt coordFields; 3052 3053 ierr = DMGetNumFields(coordDM,&coordFields);CHKERRQ(ierr); 3054 if (coordFields) { 3055 PetscClassId id; 3056 PetscObject disc; 3057 3058 ierr = DMGetField(coordDM,0,NULL,&disc);CHKERRQ(ierr); 3059 ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); 3060 if (id == PETSCFE_CLASSID) { 3061 fe = (PetscFE) disc; 3062 } 3063 } 3064 } 3065 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3066 if (cell < cStart || cell >= cEnd) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"point %D not in cell range [%D,%D)",cell,cStart,cEnd); 3067 if (!fe) { /* implicit discretization: affine or multilinear */ 3068 PetscInt coneSize; 3069 PetscBool isSimplex, isTensor; 3070 3071 ierr = DMPlexGetConeSize(dm,cell,&coneSize);CHKERRQ(ierr); 3072 isSimplex = (coneSize == (dimR + 1)) ? PETSC_TRUE : PETSC_FALSE; 3073 isTensor = (coneSize == ((depth == 1) ? (1 << dimR) : (2 * dimR))) ? PETSC_TRUE : PETSC_FALSE; 3074 if (isSimplex) { 3075 PetscReal detJ, *v0, *J; 3076 3077 ierr = DMGetWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 3078 J = &v0[dimC]; 3079 ierr = DMPlexComputeCellGeometryAffineFEM(dm, cell, v0, J, NULL, &detJ);CHKERRQ(ierr); 3080 for (i = 0; i < numPoints; i++) { /* Apply the affine transformation for each point */ 3081 const PetscReal xi0[3] = {-1.,-1.,-1.}; 3082 3083 CoordinatesRefToReal(dimC, dimR, xi0, v0, J, &refCoords[dimR * i], &realCoords[dimC * i]); 3084 } 3085 ierr = DMRestoreWorkArray(dm,dimC + 2 * dimC * dimC, MPIU_REAL, &v0);CHKERRQ(ierr); 3086 } else if (isTensor) { 3087 ierr = DMPlexReferenceToCoordinates_Tensor(coordDM, cell, numPoints, refCoords, realCoords, coords, dimC, dimR);CHKERRQ(ierr); 3088 } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unrecognized cone size %D",coneSize); 3089 } else { 3090 ierr = DMPlexReferenceToCoordinates_FE(coordDM, fe, cell, numPoints, refCoords, realCoords, coords, dimC, dimR);CHKERRQ(ierr); 3091 } 3092 PetscFunctionReturn(0); 3093 } 3094 3095 /*@C 3096 DMPlexRemapGeometry - This function maps the original DM coordinates to new coordinates. 3097 3098 Not collective 3099 3100 Input Parameters: 3101 + dm - The DM 3102 . time - The time 3103 - func - The function transforming current coordinates to new coordaintes 3104 3105 Calling sequence of func: 3106 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 3107 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 3108 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 3109 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 3110 3111 + dim - The spatial dimension 3112 . Nf - The number of input fields (here 1) 3113 . NfAux - The number of input auxiliary fields 3114 . uOff - The offset of the coordinates in u[] (here 0) 3115 . uOff_x - The offset of the coordinates in u_x[] (here 0) 3116 . u - The coordinate values at this point in space 3117 . u_t - The coordinate time derivative at this point in space (here NULL) 3118 . u_x - The coordinate derivatives at this point in space 3119 . aOff - The offset of each auxiliary field in u[] 3120 . aOff_x - The offset of each auxiliary field in u_x[] 3121 . a - The auxiliary field values at this point in space 3122 . a_t - The auxiliary field time derivative at this point in space (or NULL) 3123 . a_x - The auxiliary field derivatives at this point in space 3124 . t - The current time 3125 . x - The coordinates of this point (here not used) 3126 . numConstants - The number of constants 3127 . constants - The value of each constant 3128 - f - The new coordinates at this point in space 3129 3130 Level: intermediate 3131 3132 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMProjectFieldLocal(), DMProjectFieldLabelLocal() 3133 @*/ 3134 PetscErrorCode DMPlexRemapGeometry(DM dm, PetscReal time, 3135 void (*func)(PetscInt, PetscInt, PetscInt, 3136 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 3137 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 3138 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) 3139 { 3140 DM cdm; 3141 DMField cf; 3142 Vec lCoords, tmpCoords; 3143 PetscErrorCode ierr; 3144 3145 PetscFunctionBegin; 3146 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 3147 ierr = DMGetCoordinatesLocal(dm, &lCoords);CHKERRQ(ierr); 3148 ierr = DMGetLocalVector(cdm, &tmpCoords);CHKERRQ(ierr); 3149 ierr = VecCopy(lCoords, tmpCoords);CHKERRQ(ierr); 3150 /* We have to do the coordinate field manually right now since the coordinate DM will not have its own */ 3151 ierr = DMGetCoordinateField(dm, &cf);CHKERRQ(ierr); 3152 cdm->coordinateField = cf; 3153 ierr = DMProjectFieldLocal(cdm, time, tmpCoords, &func, INSERT_VALUES, lCoords);CHKERRQ(ierr); 3154 cdm->coordinateField = NULL; 3155 ierr = DMRestoreLocalVector(cdm, &tmpCoords);CHKERRQ(ierr); 3156 ierr = DMSetCoordinatesLocal(dm, lCoords);CHKERRQ(ierr); 3157 PetscFunctionReturn(0); 3158 } 3159 3160 /* Shear applies the transformation, assuming we fix z, 3161 / 1 0 m_0 \ 3162 | 0 1 m_1 | 3163 \ 0 0 1 / 3164 */ 3165 static void f0_shear(PetscInt dim, PetscInt Nf, PetscInt NfAux, 3166 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 3167 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 3168 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar coords[]) 3169 { 3170 const PetscInt Nc = uOff[1]-uOff[0]; 3171 const PetscInt ax = (PetscInt) PetscRealPart(constants[0]); 3172 PetscInt c; 3173 3174 for (c = 0; c < Nc; ++c) { 3175 coords[c] = u[c] + constants[c+1]*u[ax]; 3176 } 3177 } 3178 3179 /*@C 3180 DMPlexShearGeometry - This shears the domain, meaning adds a multiple of the shear coordinate to all other coordinates. 3181 3182 Not collective 3183 3184 Input Parameters: 3185 + dm - The DM 3186 . direction - The shear coordinate direction, e.g. 0 is the x-axis 3187 - multipliers - The multiplier m for each direction which is not the shear direction 3188 3189 Level: intermediate 3190 3191 .seealso: DMPlexRemapGeometry() 3192 @*/ 3193 PetscErrorCode DMPlexShearGeometry(DM dm, DMDirection direction, PetscReal multipliers[]) 3194 { 3195 DM cdm; 3196 PetscDS cds; 3197 PetscObject obj; 3198 PetscClassId id; 3199 PetscScalar *moduli; 3200 const PetscInt dir = (PetscInt) direction; 3201 PetscInt dE, d, e; 3202 PetscErrorCode ierr; 3203 3204 PetscFunctionBegin; 3205 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 3206 ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr); 3207 ierr = PetscMalloc1(dE+1, &moduli);CHKERRQ(ierr); 3208 moduli[0] = dir; 3209 for (d = 0, e = 0; d < dE; ++d) moduli[d+1] = d == dir ? 0.0 : (multipliers ? multipliers[e++] : 1.0); 3210 ierr = DMGetDS(cdm, &cds);CHKERRQ(ierr); 3211 ierr = PetscDSGetDiscretization(cds, 0, &obj);CHKERRQ(ierr); 3212 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3213 if (id != PETSCFE_CLASSID) { 3214 Vec lCoords; 3215 PetscSection cSection; 3216 PetscScalar *coords; 3217 PetscInt vStart, vEnd, v; 3218 3219 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3220 ierr = DMGetCoordinateSection(dm, &cSection);CHKERRQ(ierr); 3221 ierr = DMGetCoordinatesLocal(dm, &lCoords);CHKERRQ(ierr); 3222 ierr = VecGetArray(lCoords, &coords);CHKERRQ(ierr); 3223 for (v = vStart; v < vEnd; ++v) { 3224 PetscReal ds; 3225 PetscInt off, c; 3226 3227 ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr); 3228 ds = PetscRealPart(coords[off+dir]); 3229 for (c = 0; c < dE; ++c) coords[off+c] += moduli[c]*ds; 3230 } 3231 ierr = VecRestoreArray(lCoords, &coords);CHKERRQ(ierr); 3232 } else { 3233 ierr = PetscDSSetConstants(cds, dE+1, moduli);CHKERRQ(ierr); 3234 ierr = DMPlexRemapGeometry(dm, 0.0, f0_shear);CHKERRQ(ierr); 3235 } 3236 ierr = PetscFree(moduli);CHKERRQ(ierr); 3237 PetscFunctionReturn(0); 3238 } 3239