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