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