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