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