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