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