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