13e72e933SJed Brown #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 23e72e933SJed Brown #include <petscsf.h> 33e72e933SJed Brown #include <petsc/private/hashset.h> 43e72e933SJed Brown 53e72e933SJed Brown typedef uint64_t ZCode; 63e72e933SJed Brown 73e72e933SJed Brown PETSC_HASH_SET(ZSet, ZCode, PetscHash_UInt64, PetscHashEqual) 83e72e933SJed Brown 93e72e933SJed Brown typedef struct { 103e72e933SJed Brown PetscInt i, j, k; 113e72e933SJed Brown } Ijk; 123e72e933SJed Brown 133e72e933SJed Brown typedef struct { 143e72e933SJed Brown Ijk eextent; 153e72e933SJed Brown Ijk vextent; 163e72e933SJed Brown PetscMPIInt comm_size; 173e72e933SJed Brown ZCode *zstarts; 183e72e933SJed Brown } ZLayout; 193e72e933SJed Brown 203e72e933SJed Brown static unsigned ZCodeSplit1(ZCode z) 213e72e933SJed Brown { 223e72e933SJed Brown z = ((z & 01001001001001001) | ((z >> 2) & 02002002002002002) | ((z >> 4) & 04004004004004004)); 233e72e933SJed Brown z = (z | (z >> 6) | (z >> 12)) & 0000000777000000777; 243e72e933SJed Brown z = (z | (z >> 18)) & 0777777; 253e72e933SJed Brown return (unsigned)z; 263e72e933SJed Brown } 273e72e933SJed Brown 283e72e933SJed Brown static ZCode ZEncode1(unsigned t) 293e72e933SJed Brown { 303e72e933SJed Brown ZCode z = t; 313e72e933SJed Brown z = (z | (z << 18)) & 0777000000777; 323e72e933SJed Brown z = (z | (z << 6) | (z << 12)) & 07007007007007007; 333e72e933SJed Brown z = (z | (z << 2) | (z << 4)) & 0111111111111111111; 343e72e933SJed Brown return z; 353e72e933SJed Brown } 363e72e933SJed Brown 373e72e933SJed Brown static Ijk ZCodeSplit(ZCode z) 383e72e933SJed Brown { 393e72e933SJed Brown Ijk c; 403e72e933SJed Brown c.i = ZCodeSplit1(z >> 2); 413e72e933SJed Brown c.j = ZCodeSplit1(z >> 1); 423e72e933SJed Brown c.k = ZCodeSplit1(z >> 0); 433e72e933SJed Brown return c; 443e72e933SJed Brown } 453e72e933SJed Brown 463e72e933SJed Brown static ZCode ZEncode(Ijk c) 473e72e933SJed Brown { 483e72e933SJed Brown ZCode z = (ZEncode1(c.i) << 2) | (ZEncode1(c.j) << 1) | ZEncode1(c.k); 493e72e933SJed Brown return z; 503e72e933SJed Brown } 513e72e933SJed Brown 523e72e933SJed Brown static PetscBool IjkActive(Ijk extent, Ijk l) 533e72e933SJed Brown { 543e72e933SJed Brown if (l.i < extent.i && l.j < extent.j && l.k < extent.k) return PETSC_TRUE; 553e72e933SJed Brown return PETSC_FALSE; 563e72e933SJed Brown } 573e72e933SJed Brown 583e72e933SJed Brown // Since element/vertex box extents are typically not equal powers of 2, Z codes that lie within the domain are not contiguous. 59c77877e3SJed Brown static PetscErrorCode ZLayoutCreate(PetscMPIInt size, const PetscInt eextent[3], const PetscInt vextent[3], ZLayout *zlayout) 603e72e933SJed Brown { 613e72e933SJed Brown ZLayout layout; 62c77877e3SJed Brown 63c77877e3SJed Brown PetscFunctionBegin; 643e72e933SJed Brown layout.eextent.i = eextent[0]; 653e72e933SJed Brown layout.eextent.j = eextent[1]; 663e72e933SJed Brown layout.eextent.k = eextent[2]; 673e72e933SJed Brown layout.vextent.i = vextent[0]; 683e72e933SJed Brown layout.vextent.j = vextent[1]; 693e72e933SJed Brown layout.vextent.k = vextent[2]; 703e72e933SJed Brown layout.comm_size = size; 71c77877e3SJed Brown PetscCall(PetscMalloc1(size + 1, &layout.zstarts)); 723e72e933SJed Brown 733e72e933SJed Brown PetscInt total_elems = eextent[0] * eextent[1] * eextent[2]; 743e72e933SJed Brown ZCode z = 0; 753e72e933SJed Brown layout.zstarts[0] = 0; 763e72e933SJed Brown for (PetscMPIInt r = 0; r < size; r++) { 773e72e933SJed Brown PetscInt elems_needed = (total_elems / size) + (total_elems % size > r), count; 783e72e933SJed Brown for (count = 0; count < elems_needed; z++) { 793e72e933SJed Brown Ijk loc = ZCodeSplit(z); 803e72e933SJed Brown if (IjkActive(layout.eextent, loc)) count++; 813e72e933SJed Brown } 823e72e933SJed Brown // Pick up any extra vertices in the Z ordering before the next rank's first owned element. 83c77877e3SJed Brown // 84c77877e3SJed Brown // TODO: This leads to poorly balanced vertices when eextent is a power of 2, since all the fringe vertices end up 85c77877e3SJed Brown // on the last rank. A possible solution is to balance the Z-order vertices independently from the cells, which will 86c77877e3SJed Brown // result in a lot of element closures being remote. We could finish marking boundary conditions, then do a round of 87c77877e3SJed Brown // vertex ownership smoothing (which would reorder and redistribute vertices without touching element distribution). 88c77877e3SJed Brown // Another would be to have an analytic ownership criteria for vertices in the fringe veextent - eextent. This would 89c77877e3SJed Brown // complicate the job of identifying an owner and its offset. 903e72e933SJed Brown for (; z <= ZEncode(layout.vextent); z++) { 913e72e933SJed Brown Ijk loc = ZCodeSplit(z); 923e72e933SJed Brown if (IjkActive(layout.eextent, loc)) break; 933e72e933SJed Brown } 943e72e933SJed Brown layout.zstarts[r + 1] = z; 953e72e933SJed Brown } 96c77877e3SJed Brown *zlayout = layout; 97c77877e3SJed Brown PetscFunctionReturn(0); 983e72e933SJed Brown } 993e72e933SJed Brown 1004e2e9504SJed Brown static PetscInt ZLayoutElementsOnRank(const ZLayout *layout, PetscMPIInt rank) 1014e2e9504SJed Brown { 1024e2e9504SJed Brown PetscInt remote_elem = 0; 1034e2e9504SJed Brown for (ZCode rz = layout->zstarts[rank]; rz < layout->zstarts[rank + 1]; rz++) { 1044e2e9504SJed Brown Ijk loc = ZCodeSplit(rz); 1054e2e9504SJed Brown if (IjkActive(layout->eextent, loc)) remote_elem++; 1064e2e9504SJed Brown } 1074e2e9504SJed Brown return remote_elem; 1084e2e9504SJed Brown } 1094e2e9504SJed Brown 1103e72e933SJed Brown PetscInt ZCodeFind(ZCode key, PetscInt n, const ZCode X[]) 1113e72e933SJed Brown { 1123e72e933SJed Brown PetscInt lo = 0, hi = n; 1133e72e933SJed Brown 1143e72e933SJed Brown if (n == 0) return -1; 1153e72e933SJed Brown while (hi - lo > 1) { 1163e72e933SJed Brown PetscInt mid = lo + (hi - lo) / 2; 1173e72e933SJed Brown if (key < X[mid]) hi = mid; 1183e72e933SJed Brown else lo = mid; 1193e72e933SJed Brown } 1203e72e933SJed Brown return key == X[lo] ? lo : -(lo + (key > X[lo]) + 1); 1213e72e933SJed Brown } 1223e72e933SJed Brown 123*6725e60dSJed Brown static PetscErrorCode DMPlexCreateBoxMesh_Tensor_SFC_Periodicity_Private(DM dm, const ZLayout *layout, const ZCode *vert_z, PetscSegBuffer per_faces, const DMBoundaryType *periodicity, PetscSegBuffer donor_face_closure, PetscSegBuffer my_donor_faces) 1244e2e9504SJed Brown { 1254e2e9504SJed Brown MPI_Comm comm; 1264e2e9504SJed Brown size_t num_faces; 1274e2e9504SJed Brown PetscInt dim, *faces, vStart, vEnd; 1284e2e9504SJed Brown PetscMPIInt size; 1294e2e9504SJed Brown ZCode *donor_verts, *donor_minz; 1304e2e9504SJed Brown PetscSFNode *leaf; 1314e2e9504SJed Brown 1324e2e9504SJed Brown PetscFunctionBegin; 1334e2e9504SJed Brown PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1344e2e9504SJed Brown PetscCallMPI(MPI_Comm_size(comm, &size)); 1354e2e9504SJed Brown PetscCall(DMGetDimension(dm, &dim)); 1364e2e9504SJed Brown const PetscInt csize = PetscPowInt(2, dim - 1); 1374e2e9504SJed Brown PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1384e2e9504SJed Brown PetscCall(PetscSegBufferGetSize(per_faces, &num_faces)); 1394e2e9504SJed Brown PetscCall(PetscSegBufferExtractInPlace(per_faces, &faces)); 1404e2e9504SJed Brown PetscCall(PetscSegBufferExtractInPlace(donor_face_closure, &donor_verts)); 1414e2e9504SJed Brown PetscCall(PetscMalloc1(num_faces, &donor_minz)); 1424e2e9504SJed Brown PetscCall(PetscMalloc1(num_faces, &leaf)); 1434e2e9504SJed Brown for (PetscInt i = 0; i < (PetscInt)num_faces; i++) { 1444e2e9504SJed Brown ZCode minz = donor_verts[i * csize]; 1454e2e9504SJed Brown for (PetscInt j = 1; j < csize; j++) minz = PetscMin(minz, donor_verts[i * csize + j]); 1464e2e9504SJed Brown donor_minz[i] = minz; 1474e2e9504SJed Brown } 1484e2e9504SJed Brown { 1494e2e9504SJed Brown PetscBool sorted; 1504e2e9504SJed Brown PetscCall(PetscSortedInt64(num_faces, (const PetscInt64 *)donor_minz, &sorted)); 1514e2e9504SJed Brown PetscCheck(sorted, comm, PETSC_ERR_PLIB, "minz not sorted; periodicity in multiple dimensions not yet supported"); 1524e2e9504SJed Brown } 1534e2e9504SJed Brown for (PetscInt i = 0; i < (PetscInt)num_faces;) { 1544e2e9504SJed Brown ZCode z = donor_minz[i]; 1554e2e9504SJed Brown PetscInt remote_rank = ZCodeFind(z, size + 1, layout->zstarts), remote_count = 0; 1564e2e9504SJed Brown if (remote_rank < 0) remote_rank = -(remote_rank + 1) - 1; 1574e2e9504SJed Brown // Process all the vertices on this rank 1584e2e9504SJed Brown for (ZCode rz = layout->zstarts[remote_rank]; rz < layout->zstarts[remote_rank + 1]; rz++) { 1594e2e9504SJed Brown Ijk loc = ZCodeSplit(rz); 1604e2e9504SJed Brown if (rz == z) { 1614e2e9504SJed Brown leaf[i].rank = remote_rank; 1624e2e9504SJed Brown leaf[i].index = remote_count; 1634e2e9504SJed Brown i++; 1644e2e9504SJed Brown if (i == (PetscInt)num_faces) break; 1654e2e9504SJed Brown z = donor_minz[i]; 1664e2e9504SJed Brown } 1674e2e9504SJed Brown if (IjkActive(layout->vextent, loc)) remote_count++; 1684e2e9504SJed Brown } 1694e2e9504SJed Brown } 1704e2e9504SJed Brown PetscCall(PetscFree(donor_minz)); 1714e2e9504SJed Brown PetscSF sfper; 1724e2e9504SJed Brown PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &sfper)); 1734e2e9504SJed Brown PetscCall(PetscSFSetGraph(sfper, vEnd - vStart, num_faces, PETSC_NULL, PETSC_USE_POINTER, leaf, PETSC_USE_POINTER)); 1744e2e9504SJed Brown const PetscInt *my_donor_degree; 1754e2e9504SJed Brown PetscCall(PetscSFComputeDegreeBegin(sfper, &my_donor_degree)); 1764e2e9504SJed Brown PetscCall(PetscSFComputeDegreeEnd(sfper, &my_donor_degree)); 1774e2e9504SJed Brown PetscInt num_multiroots = 0; 1784e2e9504SJed Brown for (PetscInt i = 0; i < vEnd - vStart; i++) { 1794e2e9504SJed Brown num_multiroots += my_donor_degree[i]; 1804e2e9504SJed Brown if (my_donor_degree[i] == 0) continue; 1814e2e9504SJed Brown PetscAssert(my_donor_degree[i] == 1, comm, PETSC_ERR_SUP, "Local vertex has multiple faces"); 1824e2e9504SJed Brown } 1834e2e9504SJed Brown PetscInt *my_donors, *donor_indices, *my_donor_indices; 1844e2e9504SJed Brown size_t num_my_donors; 1854e2e9504SJed Brown PetscCall(PetscSegBufferGetSize(my_donor_faces, &num_my_donors)); 1864e2e9504SJed Brown PetscCheck((PetscInt)num_my_donors == num_multiroots, PETSC_COMM_SELF, PETSC_ERR_SUP, "Donor request does not match expected donors"); 1874e2e9504SJed Brown PetscCall(PetscSegBufferExtractInPlace(my_donor_faces, &my_donors)); 1884e2e9504SJed Brown PetscCall(PetscMalloc1(vEnd - vStart, &my_donor_indices)); 1894e2e9504SJed Brown for (PetscInt i = 0; i < (PetscInt)num_my_donors; i++) { 1904e2e9504SJed Brown PetscInt f = my_donors[i]; 1914e2e9504SJed Brown PetscInt num_points, *points = NULL, minv = PETSC_MAX_INT; 1924e2e9504SJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &num_points, &points)); 1934e2e9504SJed Brown for (PetscInt j = 0; j < num_points; j++) { 1944e2e9504SJed Brown PetscInt p = points[2 * j]; 1954e2e9504SJed Brown if (p < vStart || vEnd <= p) continue; 1964e2e9504SJed Brown minv = PetscMin(minv, p); 1974e2e9504SJed Brown } 1984e2e9504SJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &num_points, &points)); 1994e2e9504SJed Brown PetscAssert(my_donor_degree[minv - vStart] == 1, comm, PETSC_ERR_SUP, "Local vertex not requested"); 2004e2e9504SJed Brown my_donor_indices[minv - vStart] = f; 2014e2e9504SJed Brown } 2024e2e9504SJed Brown PetscCall(PetscMalloc1(num_faces, &donor_indices)); 2034e2e9504SJed Brown PetscCall(PetscSFBcastBegin(sfper, MPIU_INT, my_donor_indices, donor_indices, MPI_REPLACE)); 2044e2e9504SJed Brown PetscCall(PetscSFBcastEnd(sfper, MPIU_INT, my_donor_indices, donor_indices, MPI_REPLACE)); 2054e2e9504SJed Brown PetscCall(PetscFree(my_donor_indices)); 2064e2e9504SJed Brown // Modify our leafs so they point to donor faces instead of donor minz. Additionally, give them indices as faces. 2074e2e9504SJed Brown for (PetscInt i = 0; i < (PetscInt)num_faces; i++) leaf[i].index = donor_indices[i]; 2084e2e9504SJed Brown PetscCall(PetscFree(donor_indices)); 2094e2e9504SJed Brown PetscInt pStart, pEnd; 2104e2e9504SJed Brown PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2114e2e9504SJed Brown PetscCall(PetscSFSetGraph(sfper, pEnd - pStart, num_faces, faces, PETSC_COPY_VALUES, leaf, PETSC_OWN_POINTER)); 2124e2e9504SJed Brown PetscCall(PetscObjectSetName((PetscObject)sfper, "Periodic Faces")); 2134e2e9504SJed Brown PetscCall(PetscSFViewFromOptions(sfper, NULL, "-sfper_view")); 2144e2e9504SJed Brown 2154e2e9504SJed Brown PetscCall(DMPlexSetPeriodicFaceSF(dm, sfper)); 216*6725e60dSJed Brown 217*6725e60dSJed Brown PetscScalar t[4][4] = {{0}}; 218*6725e60dSJed Brown t[0][0] = 1; 219*6725e60dSJed Brown t[1][1] = 1; 220*6725e60dSJed Brown t[2][2] = 1; 221*6725e60dSJed Brown t[3][3] = 1; 222*6725e60dSJed Brown for (PetscInt i = 0; i < dim; i++) 223*6725e60dSJed Brown if (periodicity[i] == DM_BOUNDARY_PERIODIC) t[i][3] = 1; 224*6725e60dSJed Brown PetscCall(DMPlexSetPeriodicFaceTransform(dm, t)); 2254e2e9504SJed Brown PetscCall(PetscSFDestroy(&sfper)); 2264e2e9504SJed Brown PetscFunctionReturn(0); 2274e2e9504SJed Brown } 2284e2e9504SJed Brown 229*6725e60dSJed Brown static PetscErrorCode DMCoordAddPeriodicOffsets_Private(DM dm, Vec g, InsertMode mode, Vec l, void *ctx) 230*6725e60dSJed Brown { 231*6725e60dSJed Brown PetscFunctionBegin; 232*6725e60dSJed Brown PetscCall(VecScatterBegin(dm->periodic.affine_to_local, dm->periodic.affine, l, ADD_VALUES, SCATTER_FORWARD)); 233*6725e60dSJed Brown PetscCall(VecScatterEnd(dm->periodic.affine_to_local, dm->periodic.affine, l, ADD_VALUES, SCATTER_FORWARD)); 234*6725e60dSJed Brown PetscFunctionReturn(0); 235*6725e60dSJed Brown } 236*6725e60dSJed Brown 237*6725e60dSJed Brown // Start with an SF for a positive depth (e.g., faces) and create a new SF for matched closure. 238*6725e60dSJed Brown // 239*6725e60dSJed Brown // While the image face and corresponding donor face might not have the same orientation, it is assumed that the vertex 240*6725e60dSJed Brown // numbering is consistent. 241*6725e60dSJed Brown static PetscErrorCode DMPlexSFCreateClosureSF_Private(DM dm, PetscSF face_sf, PetscSF *closure_sf, IS *is_points) 242*6725e60dSJed Brown { 243*6725e60dSJed Brown MPI_Comm comm; 244*6725e60dSJed Brown PetscInt nroots, nleaves, npoints; 245*6725e60dSJed Brown const PetscInt *filocal, *pilocal; 246*6725e60dSJed Brown const PetscSFNode *firemote, *piremote; 247*6725e60dSJed Brown PetscMPIInt rank; 248*6725e60dSJed Brown PetscSF point_sf; 249*6725e60dSJed Brown 250*6725e60dSJed Brown PetscFunctionBegin; 251*6725e60dSJed Brown PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 252*6725e60dSJed Brown PetscCallMPI(MPI_Comm_rank(comm, &rank)); 253*6725e60dSJed Brown PetscCall(PetscSFGetGraph(face_sf, &nroots, &nleaves, &filocal, &firemote)); 254*6725e60dSJed Brown PetscCall(DMGetPointSF(dm, &point_sf)); // Point SF has remote points 255*6725e60dSJed Brown PetscCall(PetscSFGetGraph(point_sf, NULL, &npoints, &pilocal, &piremote)); 256*6725e60dSJed Brown PetscInt *rootdata, *leafdata; 257*6725e60dSJed Brown PetscCall(PetscCalloc2(2 * nroots, &rootdata, 2 * nroots, &leafdata)); 258*6725e60dSJed Brown for (PetscInt i = 0; i < nleaves; i++) { 259*6725e60dSJed Brown PetscInt point = filocal[i], cl_size, *closure = NULL; 260*6725e60dSJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &cl_size, &closure)); 261*6725e60dSJed Brown leafdata[point] = cl_size - 1; 262*6725e60dSJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &cl_size, &closure)); 263*6725e60dSJed Brown } 264*6725e60dSJed Brown PetscCall(PetscSFReduceBegin(face_sf, MPIU_INT, leafdata, rootdata + nroots, MPIU_SUM)); 265*6725e60dSJed Brown PetscCall(PetscSFReduceEnd(face_sf, MPIU_INT, leafdata, rootdata + nroots, MPIU_SUM)); 266*6725e60dSJed Brown 267*6725e60dSJed Brown PetscInt root_offset = 0; 268*6725e60dSJed Brown for (PetscInt p = 0; p < nroots; p++) { 269*6725e60dSJed Brown const PetscInt *donor_dof = rootdata + nroots; 270*6725e60dSJed Brown if (donor_dof[p] == 0) { 271*6725e60dSJed Brown rootdata[2 * p] = -1; 272*6725e60dSJed Brown rootdata[2 * p + 1] = -1; 273*6725e60dSJed Brown continue; 274*6725e60dSJed Brown } 275*6725e60dSJed Brown PetscInt cl_size; 276*6725e60dSJed Brown PetscInt *closure = NULL; 277*6725e60dSJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &cl_size, &closure)); 278*6725e60dSJed Brown // cl_size - 1 = points not including self 279*6725e60dSJed Brown PetscAssert(donor_dof[p] == cl_size - 1, comm, PETSC_ERR_PLIB, "Reduced leaf cone sizes do not match root cone sizes"); 280*6725e60dSJed Brown rootdata[2 * p] = root_offset; 281*6725e60dSJed Brown rootdata[2 * p + 1] = cl_size - 1; 282*6725e60dSJed Brown root_offset += cl_size - 1; 283*6725e60dSJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &cl_size, &closure)); 284*6725e60dSJed Brown } 285*6725e60dSJed Brown PetscCall(PetscSFBcastBegin(face_sf, MPIU_2INT, rootdata, leafdata, MPI_REPLACE)); 286*6725e60dSJed Brown PetscCall(PetscSFBcastEnd(face_sf, MPIU_2INT, rootdata, leafdata, MPI_REPLACE)); 287*6725e60dSJed Brown // Count how many leaves we need to communicate the closures 288*6725e60dSJed Brown PetscInt leaf_offset = 0; 289*6725e60dSJed Brown for (PetscInt i = 0; i < nleaves; i++) { 290*6725e60dSJed Brown PetscInt point = filocal[i]; 291*6725e60dSJed Brown if (leafdata[2 * point + 1] < 0) continue; 292*6725e60dSJed Brown leaf_offset += leafdata[2 * point + 1]; 293*6725e60dSJed Brown } 294*6725e60dSJed Brown 295*6725e60dSJed Brown PetscSFNode *closure_leaf; 296*6725e60dSJed Brown PetscCall(PetscMalloc1(leaf_offset, &closure_leaf)); 297*6725e60dSJed Brown leaf_offset = 0; 298*6725e60dSJed Brown for (PetscInt i = 0; i < nleaves; i++) { 299*6725e60dSJed Brown PetscInt point = filocal[i]; 300*6725e60dSJed Brown PetscInt cl_size = leafdata[2 * point + 1]; 301*6725e60dSJed Brown if (cl_size < 0) continue; 302*6725e60dSJed Brown for (PetscInt j = 0; j < cl_size; j++) { 303*6725e60dSJed Brown closure_leaf[leaf_offset].rank = firemote[i].rank; 304*6725e60dSJed Brown closure_leaf[leaf_offset].index = leafdata[2 * point] + j; 305*6725e60dSJed Brown leaf_offset++; 306*6725e60dSJed Brown } 307*6725e60dSJed Brown } 308*6725e60dSJed Brown 309*6725e60dSJed Brown PetscSF sf_closure; 310*6725e60dSJed Brown PetscCall(PetscSFCreate(comm, &sf_closure)); 311*6725e60dSJed Brown PetscCall(PetscSFSetGraph(sf_closure, root_offset, leaf_offset, NULL, PETSC_USE_POINTER, closure_leaf, PETSC_OWN_POINTER)); 312*6725e60dSJed Brown 313*6725e60dSJed Brown // Pack root buffer with owner for every point in the root cones 314*6725e60dSJed Brown PetscSFNode *donor_closure; 315*6725e60dSJed Brown PetscCall(PetscCalloc1(root_offset, &donor_closure)); 316*6725e60dSJed Brown root_offset = 0; 317*6725e60dSJed Brown for (PetscInt p = 0; p < nroots; p++) { 318*6725e60dSJed Brown if (rootdata[2 * p] < 0) continue; 319*6725e60dSJed Brown PetscInt cl_size; 320*6725e60dSJed Brown PetscInt *closure = NULL; 321*6725e60dSJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &cl_size, &closure)); 322*6725e60dSJed Brown for (PetscInt j = 1; j < cl_size; j++) { 323*6725e60dSJed Brown PetscInt c = closure[2 * j]; 324*6725e60dSJed Brown if (pilocal) { 325*6725e60dSJed Brown PetscInt found = -1; 326*6725e60dSJed Brown if (npoints > 0) PetscCall(PetscFindInt(c, npoints, pilocal, &found)); 327*6725e60dSJed Brown if (found >= 0) { 328*6725e60dSJed Brown donor_closure[root_offset++] = piremote[found]; 329*6725e60dSJed Brown continue; 330*6725e60dSJed Brown } 331*6725e60dSJed Brown } 332*6725e60dSJed Brown // we own c 333*6725e60dSJed Brown donor_closure[root_offset].rank = rank; 334*6725e60dSJed Brown donor_closure[root_offset].index = c; 335*6725e60dSJed Brown root_offset++; 336*6725e60dSJed Brown } 337*6725e60dSJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &cl_size, &closure)); 338*6725e60dSJed Brown } 339*6725e60dSJed Brown 340*6725e60dSJed Brown PetscSFNode *leaf_donor_closure; 341*6725e60dSJed Brown PetscCall(PetscMalloc1(leaf_offset, &leaf_donor_closure)); 342*6725e60dSJed Brown PetscCall(PetscSFBcastBegin(sf_closure, MPIU_2INT, donor_closure, leaf_donor_closure, MPI_REPLACE)); 343*6725e60dSJed Brown PetscCall(PetscSFBcastEnd(sf_closure, MPIU_2INT, donor_closure, leaf_donor_closure, MPI_REPLACE)); 344*6725e60dSJed Brown PetscCall(PetscSFDestroy(&sf_closure)); 345*6725e60dSJed Brown PetscCall(PetscFree(donor_closure)); 346*6725e60dSJed Brown 347*6725e60dSJed Brown PetscSFNode *new_iremote; 348*6725e60dSJed Brown PetscCall(PetscCalloc1(nroots, &new_iremote)); 349*6725e60dSJed Brown for (PetscInt i = 0; i < nroots; i++) new_iremote[i].rank = -1; 350*6725e60dSJed Brown // Walk leaves and match vertices 351*6725e60dSJed Brown leaf_offset = 0; 352*6725e60dSJed Brown for (PetscInt i = 0; i < nleaves; i++) { 353*6725e60dSJed Brown PetscInt point = filocal[i], cl_size; 354*6725e60dSJed Brown PetscInt *closure = NULL; 355*6725e60dSJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &cl_size, &closure)); 356*6725e60dSJed Brown for (PetscInt j = 1; j < cl_size; j++) { // TODO: should we send donor edge orientations so we can flip for consistency? 357*6725e60dSJed Brown PetscInt c = closure[2 * j]; 358*6725e60dSJed Brown PetscSFNode lc = leaf_donor_closure[leaf_offset]; 359*6725e60dSJed Brown // printf("[%d] face %d.%d: %d ?-- (%d,%d)\n", rank, point, j, c, lc.rank, lc.index); 360*6725e60dSJed Brown if (new_iremote[c].rank == -1) { 361*6725e60dSJed Brown new_iremote[c] = lc; 362*6725e60dSJed Brown } else PetscCheck(new_iremote[c].rank == lc.rank && new_iremote[c].index == lc.index, comm, PETSC_ERR_PLIB, "Mismatched cone ordering between faces"); 363*6725e60dSJed Brown leaf_offset++; 364*6725e60dSJed Brown } 365*6725e60dSJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &cl_size, &closure)); 366*6725e60dSJed Brown } 367*6725e60dSJed Brown PetscCall(PetscFree(leaf_donor_closure)); 368*6725e60dSJed Brown 369*6725e60dSJed Brown // Include face points in closure SF 370*6725e60dSJed Brown for (PetscInt i = 0; i < nleaves; i++) new_iremote[filocal[i]] = firemote[i]; 371*6725e60dSJed Brown // consolidate leaves 372*6725e60dSJed Brown PetscInt num_new_leaves = 0; 373*6725e60dSJed Brown for (PetscInt i = 0; i < nroots; i++) { 374*6725e60dSJed Brown if (new_iremote[i].rank == -1) continue; 375*6725e60dSJed Brown new_iremote[num_new_leaves] = new_iremote[i]; 376*6725e60dSJed Brown leafdata[num_new_leaves] = i; 377*6725e60dSJed Brown num_new_leaves++; 378*6725e60dSJed Brown } 379*6725e60dSJed Brown PetscCall(ISCreateGeneral(comm, num_new_leaves, leafdata, PETSC_COPY_VALUES, is_points)); 380*6725e60dSJed Brown 381*6725e60dSJed Brown PetscSF csf; 382*6725e60dSJed Brown PetscCall(PetscSFCreate(comm, &csf)); 383*6725e60dSJed Brown PetscCall(PetscSFSetGraph(csf, nroots, num_new_leaves, leafdata, PETSC_COPY_VALUES, new_iremote, PETSC_COPY_VALUES)); 384*6725e60dSJed Brown PetscCall(PetscFree(new_iremote)); // copy and delete because new_iremote is longer than it needs to be 385*6725e60dSJed Brown PetscCall(PetscFree2(rootdata, leafdata)); 386*6725e60dSJed Brown 387*6725e60dSJed Brown // TODO: this is a lie; it's only the periodic point SF; need to compose with standard point SF 388*6725e60dSJed Brown PetscCall(PetscObjectSetName((PetscObject)csf, "Composed Periodic Points")); 389*6725e60dSJed Brown PetscSFViewFromOptions(csf, NULL, "-csf_view"); 390*6725e60dSJed Brown *closure_sf = csf; 391*6725e60dSJed Brown PetscFunctionReturn(0); 392*6725e60dSJed Brown } 393*6725e60dSJed Brown 394*6725e60dSJed Brown static PetscErrorCode DMGetPointSFComposed_Plex(DM dm, PetscSF *sf) 395*6725e60dSJed Brown { 396*6725e60dSJed Brown DM_Plex *plex = (DM_Plex *)dm->data; 397*6725e60dSJed Brown 398*6725e60dSJed Brown PetscFunctionBegin; 399*6725e60dSJed Brown if (!plex->periodic.composed_sf) { 400*6725e60dSJed Brown PetscSF face_sf = plex->periodic.face_sf; 401*6725e60dSJed Brown 402*6725e60dSJed Brown PetscCall(DMPlexSFCreateClosureSF_Private(dm, face_sf, &plex->periodic.composed_sf, &plex->periodic.periodic_points)); 403*6725e60dSJed Brown } 404*6725e60dSJed Brown if (sf) *sf = plex->periodic.composed_sf; 405*6725e60dSJed Brown PetscFunctionReturn(0); 406*6725e60dSJed Brown } 407*6725e60dSJed Brown 408*6725e60dSJed Brown PetscErrorCode DMPeriodicCoordinateSetUp_Internal(DM dm) 409*6725e60dSJed Brown { 410*6725e60dSJed Brown DM_Plex *plex = (DM_Plex *)dm->data; 411*6725e60dSJed Brown PetscFunctionBegin; 412*6725e60dSJed Brown if (!plex->periodic.face_sf) PetscFunctionReturn(0); 413*6725e60dSJed Brown PetscCall(DMGetPointSFComposed_Plex(dm, NULL)); 414*6725e60dSJed Brown PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetPointSFComposed_C", DMGetPointSFComposed_Plex)); 415*6725e60dSJed Brown 416*6725e60dSJed Brown PetscInt dim; 417*6725e60dSJed Brown PetscCall(DMGetDimension(dm, &dim)); 418*6725e60dSJed Brown size_t count; 419*6725e60dSJed Brown IS isdof; 420*6725e60dSJed Brown { 421*6725e60dSJed Brown PetscInt npoints; 422*6725e60dSJed Brown const PetscInt *points; 423*6725e60dSJed Brown IS is = plex->periodic.periodic_points; 424*6725e60dSJed Brown PetscSegBuffer seg; 425*6725e60dSJed Brown PetscSection section; 426*6725e60dSJed Brown PetscCall(DMGetLocalSection(dm, §ion)); 427*6725e60dSJed Brown PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 32, &seg)); 428*6725e60dSJed Brown PetscCall(ISGetSize(is, &npoints)); 429*6725e60dSJed Brown PetscCall(ISGetIndices(is, &points)); 430*6725e60dSJed Brown for (PetscInt i = 0; i < npoints; i++) { 431*6725e60dSJed Brown PetscInt point = points[i], off, dof; 432*6725e60dSJed Brown PetscCall(PetscSectionGetOffset(section, point, &off)); 433*6725e60dSJed Brown PetscCall(PetscSectionGetDof(section, point, &dof)); 434*6725e60dSJed Brown PetscAssert(dof % dim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected dof %" PetscInt_FMT " not divisible by dimension %" PetscInt_FMT, dof, dim); 435*6725e60dSJed Brown for (PetscInt j = 0; j < dof / dim; j++) { 436*6725e60dSJed Brown PetscInt *slot; 437*6725e60dSJed Brown PetscCall(PetscSegBufferGetInts(seg, 1, &slot)); 438*6725e60dSJed Brown *slot = off / dim; 439*6725e60dSJed Brown } 440*6725e60dSJed Brown } 441*6725e60dSJed Brown PetscInt *ind; 442*6725e60dSJed Brown PetscCall(PetscSegBufferGetSize(seg, &count)); 443*6725e60dSJed Brown PetscCall(PetscSegBufferExtractAlloc(seg, &ind)); 444*6725e60dSJed Brown PetscCall(PetscSegBufferDestroy(&seg)); 445*6725e60dSJed Brown PetscCall(ISCreateBlock(PETSC_COMM_SELF, dim, count, ind, PETSC_OWN_POINTER, &isdof)); 446*6725e60dSJed Brown } 447*6725e60dSJed Brown Vec L, P; 448*6725e60dSJed Brown VecType vec_type; 449*6725e60dSJed Brown VecScatter scatter; 450*6725e60dSJed Brown PetscCall(DMGetLocalVector(dm, &L)); 451*6725e60dSJed Brown PetscCall(VecCreate(PETSC_COMM_SELF, &P)); 452*6725e60dSJed Brown PetscCall(VecSetSizes(P, count * dim, count * dim)); 453*6725e60dSJed Brown PetscCall(VecGetType(L, &vec_type)); 454*6725e60dSJed Brown PetscCall(VecSetType(P, vec_type)); 455*6725e60dSJed Brown PetscCall(VecScatterCreate(P, NULL, L, isdof, &scatter)); 456*6725e60dSJed Brown PetscCall(DMRestoreLocalVector(dm, &L)); 457*6725e60dSJed Brown PetscCall(ISDestroy(&isdof)); 458*6725e60dSJed Brown 459*6725e60dSJed Brown { 460*6725e60dSJed Brown PetscScalar *x; 461*6725e60dSJed Brown PetscCall(VecGetArrayWrite(P, &x)); 462*6725e60dSJed Brown for (PetscInt i = 0; i < (PetscInt)count; i++) { 463*6725e60dSJed Brown for (PetscInt j = 0; j < dim; j++) x[i * dim + j] = plex->periodic.transform[j][3]; 464*6725e60dSJed Brown } 465*6725e60dSJed Brown PetscCall(VecRestoreArrayWrite(P, &x)); 466*6725e60dSJed Brown } 467*6725e60dSJed Brown 468*6725e60dSJed Brown dm->periodic.affine_to_local = scatter; 469*6725e60dSJed Brown dm->periodic.affine = P; 470*6725e60dSJed Brown PetscCall(DMGlobalToLocalHookAdd(dm, NULL, DMCoordAddPeriodicOffsets_Private, NULL)); 471*6725e60dSJed Brown PetscFunctionReturn(0); 472*6725e60dSJed Brown } 473*6725e60dSJed Brown 4743e72e933SJed Brown PetscErrorCode DMPlexCreateBoxMesh_Tensor_SFC_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate) 4753e72e933SJed Brown { 4763e72e933SJed Brown PetscInt eextent[3] = {1, 1, 1}, vextent[3] = {1, 1, 1}; 4773e72e933SJed Brown const Ijk closure_1[] = { 4783e72e933SJed Brown {0, 0, 0}, 4793e72e933SJed Brown {1, 0, 0}, 4803e72e933SJed Brown }; 4813e72e933SJed Brown const Ijk closure_2[] = { 4823e72e933SJed Brown {0, 0, 0}, 4833e72e933SJed Brown {1, 0, 0}, 4843e72e933SJed Brown {1, 1, 0}, 4853e72e933SJed Brown {0, 1, 0}, 4863e72e933SJed Brown }; 4873e72e933SJed Brown const Ijk closure_3[] = { 4883e72e933SJed Brown {0, 0, 0}, 4893e72e933SJed Brown {0, 1, 0}, 4903e72e933SJed Brown {1, 1, 0}, 4913e72e933SJed Brown {1, 0, 0}, 4923e72e933SJed Brown {0, 0, 1}, 4933e72e933SJed Brown {1, 0, 1}, 4943e72e933SJed Brown {1, 1, 1}, 4953e72e933SJed Brown {0, 1, 1}, 4963e72e933SJed Brown }; 4973431e603SJed Brown const Ijk *const closure_dim[] = {NULL, closure_1, closure_2, closure_3}; 4983431e603SJed Brown // This must be kept consistent with DMPlexCreateCubeMesh_Internal 4993431e603SJed Brown const PetscInt face_marker_1[] = {1, 2}; 5003431e603SJed Brown const PetscInt face_marker_2[] = {4, 2, 1, 3}; 5013431e603SJed Brown const PetscInt face_marker_3[] = {6, 5, 3, 4, 1, 2}; 5023431e603SJed Brown const PetscInt *const face_marker_dim[] = {NULL, face_marker_1, face_marker_2, face_marker_3}; 503*6725e60dSJed Brown // Orient faces so the normal is in the positive axis and the first vertex is the one closest to zero. 504*6725e60dSJed Brown // These orientations can be determined by examining cones of a reference quad and hex element. 505*6725e60dSJed Brown const PetscInt face_orient_1[] = {0, 0}; 506*6725e60dSJed Brown const PetscInt face_orient_2[] = {-1, 0, 0, -1}; 507*6725e60dSJed Brown const PetscInt face_orient_3[] = {-2, 0, -2, 1, -2, 0}; 508*6725e60dSJed Brown const PetscInt *const face_orient_dim[] = {NULL, face_orient_1, face_orient_2, face_orient_3}; 5093e72e933SJed Brown 5103e72e933SJed Brown PetscFunctionBegin; 5113e72e933SJed Brown PetscValidPointer(dm, 1); 5123e72e933SJed Brown PetscValidLogicalCollectiveInt(dm, dim, 2); 5133e72e933SJed Brown PetscCall(DMSetDimension(dm, dim)); 5143e72e933SJed Brown PetscMPIInt rank, size; 5153e72e933SJed Brown PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 5163e72e933SJed Brown PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 5173e72e933SJed Brown for (PetscInt i = 0; i < dim; i++) { 5183e72e933SJed Brown eextent[i] = faces[i]; 5193e72e933SJed Brown vextent[i] = faces[i] + 1; 5203e72e933SJed Brown } 521c77877e3SJed Brown ZLayout layout; 522c77877e3SJed Brown PetscCall(ZLayoutCreate(size, eextent, vextent, &layout)); 5233e72e933SJed Brown PetscZSet vset; // set of all vertices in the closure of the owned elements 5243e72e933SJed Brown PetscCall(PetscZSetCreate(&vset)); 5253e72e933SJed Brown PetscInt local_elems = 0; 5263e72e933SJed Brown for (ZCode z = layout.zstarts[rank]; z < layout.zstarts[rank + 1]; z++) { 5273e72e933SJed Brown Ijk loc = ZCodeSplit(z); 5283e72e933SJed Brown if (IjkActive(layout.vextent, loc)) PetscZSetAdd(vset, z); 5293e72e933SJed Brown if (IjkActive(layout.eextent, loc)) { 5303e72e933SJed Brown local_elems++; 5313e72e933SJed Brown // Add all neighboring vertices to set 5323e72e933SJed Brown for (PetscInt n = 0; n < PetscPowInt(2, dim); n++) { 5333e72e933SJed Brown Ijk inc = closure_dim[dim][n]; 5343e72e933SJed Brown Ijk nloc = {loc.i + inc.i, loc.j + inc.j, loc.k + inc.k}; 5353e72e933SJed Brown ZCode v = ZEncode(nloc); 5363e72e933SJed Brown PetscZSetAdd(vset, v); 5373e72e933SJed Brown } 5383e72e933SJed Brown } 5393e72e933SJed Brown } 5403e72e933SJed Brown PetscInt local_verts, off = 0; 5413e72e933SJed Brown ZCode *vert_z; 5423e72e933SJed Brown PetscCall(PetscZSetGetSize(vset, &local_verts)); 5433e72e933SJed Brown PetscCall(PetscMalloc1(local_verts, &vert_z)); 5443e72e933SJed Brown PetscCall(PetscZSetGetElems(vset, &off, vert_z)); 5453e72e933SJed Brown PetscCall(PetscZSetDestroy(&vset)); 5463e72e933SJed Brown // ZCode is unsigned for bitwise convenience, but highest bit should never be set, so can interpret as signed 5473e72e933SJed Brown PetscCall(PetscSortInt64(local_verts, (PetscInt64 *)vert_z)); 5483e72e933SJed Brown 5493e72e933SJed Brown PetscCall(DMPlexSetChart(dm, 0, local_elems + local_verts)); 5503e72e933SJed Brown for (PetscInt e = 0; e < local_elems; e++) PetscCall(DMPlexSetConeSize(dm, e, PetscPowInt(2, dim))); 5513e72e933SJed Brown PetscCall(DMSetUp(dm)); 5523e72e933SJed Brown { 5533e72e933SJed Brown PetscInt e = 0; 5543e72e933SJed Brown for (ZCode z = layout.zstarts[rank]; z < layout.zstarts[rank + 1]; z++) { 5553e72e933SJed Brown Ijk loc = ZCodeSplit(z); 5563e72e933SJed Brown if (!IjkActive(layout.eextent, loc)) continue; 5573e72e933SJed Brown PetscInt cone[8], orient[8] = {0}; 5583e72e933SJed Brown for (PetscInt n = 0; n < PetscPowInt(2, dim); n++) { 5593e72e933SJed Brown Ijk inc = closure_dim[dim][n]; 5603e72e933SJed Brown Ijk nloc = {loc.i + inc.i, loc.j + inc.j, loc.k + inc.k}; 5613e72e933SJed Brown ZCode v = ZEncode(nloc); 5623e72e933SJed Brown PetscInt ci = ZCodeFind(v, local_verts, vert_z); 5633e72e933SJed Brown PetscAssert(ci >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not find neighbor vertex in set"); 5643e72e933SJed Brown cone[n] = local_elems + ci; 5653e72e933SJed Brown } 5663e72e933SJed Brown PetscCall(DMPlexSetCone(dm, e, cone)); 5673e72e933SJed Brown PetscCall(DMPlexSetConeOrientation(dm, e, orient)); 5683e72e933SJed Brown e++; 5693e72e933SJed Brown } 5703e72e933SJed Brown } 5713e72e933SJed Brown 5723e72e933SJed Brown PetscCall(DMPlexSymmetrize(dm)); 5733e72e933SJed Brown PetscCall(DMPlexStratify(dm)); 574*6725e60dSJed Brown 5753e72e933SJed Brown { // Create point SF 5763e72e933SJed Brown PetscSF sf; 5773e72e933SJed Brown PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf); 5783e72e933SJed Brown PetscInt owned_verts = ZCodeFind(layout.zstarts[rank + 1], local_verts, vert_z); 5793e72e933SJed Brown if (owned_verts < 0) owned_verts = -(owned_verts + 1); // We don't care whether the key was found 5803e72e933SJed Brown PetscInt num_ghosts = local_verts - owned_verts; // Due to sorting, owned vertices always come first 5813e72e933SJed Brown PetscInt *local_ghosts; 5823e72e933SJed Brown PetscSFNode *ghosts; 5833e72e933SJed Brown PetscCall(PetscMalloc1(num_ghosts, &local_ghosts)); 5843e72e933SJed Brown PetscCall(PetscMalloc1(num_ghosts, &ghosts)); 5853e72e933SJed Brown for (PetscInt i = 0; i < num_ghosts;) { 5863e72e933SJed Brown ZCode z = vert_z[owned_verts + i]; 5873e72e933SJed Brown PetscInt remote_rank = ZCodeFind(z, size + 1, layout.zstarts), remote_count = 0; 5883e72e933SJed Brown if (remote_rank < 0) remote_rank = -(remote_rank + 1) - 1; 5893e72e933SJed Brown // We have a new remote rank; find all the ghost indices (which are contiguous in vert_z) 5903e72e933SJed Brown 5913e72e933SJed Brown // Count the elements on remote_rank 5924e2e9504SJed Brown PetscInt remote_elem = ZLayoutElementsOnRank(&layout, remote_rank); 5933e72e933SJed Brown 5943e72e933SJed Brown // Traverse vertices and make ghost links 5953e72e933SJed Brown for (ZCode rz = layout.zstarts[remote_rank]; rz < layout.zstarts[remote_rank + 1]; rz++) { 5963e72e933SJed Brown Ijk loc = ZCodeSplit(rz); 5973e72e933SJed Brown if (rz == z) { 5983e72e933SJed Brown local_ghosts[i] = local_elems + owned_verts + i; 5993e72e933SJed Brown ghosts[i].rank = remote_rank; 6003e72e933SJed Brown ghosts[i].index = remote_elem + remote_count; 6013e72e933SJed Brown i++; 6023e72e933SJed Brown if (i == num_ghosts) break; 6033e72e933SJed Brown z = vert_z[owned_verts + i]; 6043e72e933SJed Brown } 6053e72e933SJed Brown if (IjkActive(layout.vextent, loc)) remote_count++; 6063e72e933SJed Brown } 6073e72e933SJed Brown } 6083e72e933SJed Brown PetscCall(PetscSFSetGraph(sf, local_elems + local_verts, num_ghosts, local_ghosts, PETSC_OWN_POINTER, ghosts, PETSC_OWN_POINTER)); 6093e72e933SJed Brown PetscCall(PetscObjectSetName((PetscObject)sf, "SFC Point SF")); 6103e72e933SJed Brown PetscCall(DMSetPointSF(dm, sf)); 6113e72e933SJed Brown PetscCall(PetscSFDestroy(&sf)); 6123e72e933SJed Brown } 6133e72e933SJed Brown { 6143e72e933SJed Brown Vec coordinates; 6153e72e933SJed Brown PetscScalar *coords; 6163e72e933SJed Brown PetscSection coord_section; 6173e72e933SJed Brown PetscInt coord_size; 6183e72e933SJed Brown PetscCall(DMGetCoordinateSection(dm, &coord_section)); 6193e72e933SJed Brown PetscCall(PetscSectionSetNumFields(coord_section, 1)); 6203e72e933SJed Brown PetscCall(PetscSectionSetFieldComponents(coord_section, 0, dim)); 6213e72e933SJed Brown PetscCall(PetscSectionSetChart(coord_section, local_elems, local_elems + local_verts)); 6223e72e933SJed Brown for (PetscInt v = 0; v < local_verts; v++) { 6233e72e933SJed Brown PetscInt point = local_elems + v; 6243e72e933SJed Brown PetscCall(PetscSectionSetDof(coord_section, point, dim)); 6253e72e933SJed Brown PetscCall(PetscSectionSetFieldDof(coord_section, point, 0, dim)); 6263e72e933SJed Brown } 6273e72e933SJed Brown PetscCall(PetscSectionSetUp(coord_section)); 6283e72e933SJed Brown PetscCall(PetscSectionGetStorageSize(coord_section, &coord_size)); 6293e72e933SJed Brown PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6303e72e933SJed Brown PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6313e72e933SJed Brown PetscCall(VecSetSizes(coordinates, coord_size, PETSC_DETERMINE)); 6323e72e933SJed Brown PetscCall(VecSetBlockSize(coordinates, dim)); 6333e72e933SJed Brown PetscCall(VecSetType(coordinates, VECSTANDARD)); 6343e72e933SJed Brown PetscCall(VecGetArray(coordinates, &coords)); 6353e72e933SJed Brown for (PetscInt v = 0; v < local_verts; v++) { 6363e72e933SJed Brown Ijk loc = ZCodeSplit(vert_z[v]); 6373e72e933SJed Brown coords[v * dim + 0] = lower[0] + loc.i * (upper[0] - lower[0]) / layout.eextent.i; 6383e72e933SJed Brown if (dim > 1) coords[v * dim + 1] = lower[1] + loc.j * (upper[1] - lower[1]) / layout.eextent.j; 6393e72e933SJed Brown if (dim > 2) coords[v * dim + 2] = lower[2] + loc.k * (upper[2] - lower[2]) / layout.eextent.k; 6403e72e933SJed Brown } 6413e72e933SJed Brown PetscCall(VecRestoreArray(coordinates, &coords)); 6423e72e933SJed Brown PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6433e72e933SJed Brown PetscCall(VecDestroy(&coordinates)); 6443e72e933SJed Brown } 6453e72e933SJed Brown if (interpolate) { 6463431e603SJed Brown PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 6473431e603SJed Brown 6483431e603SJed Brown DMLabel label; 6493431e603SJed Brown PetscCall(DMCreateLabel(dm, "Face Sets")); 6503431e603SJed Brown PetscCall(DMGetLabel(dm, "Face Sets", &label)); 6514e2e9504SJed Brown PetscSegBuffer per_faces, donor_face_closure, my_donor_faces; 6524e2e9504SJed Brown PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 64, &per_faces)); 6534e2e9504SJed Brown PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 64, &my_donor_faces)); 6544e2e9504SJed Brown PetscCall(PetscSegBufferCreate(sizeof(ZCode), 64 * PetscPowInt(2, dim), &donor_face_closure)); 6553431e603SJed Brown PetscInt fStart, fEnd, vStart, vEnd; 6563431e603SJed Brown PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 6573431e603SJed Brown PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6583431e603SJed Brown for (PetscInt f = fStart; f < fEnd; f++) { 6594e2e9504SJed Brown PetscInt npoints, *points = NULL, num_fverts = 0, fverts[8]; 6603431e603SJed Brown PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &npoints, &points)); 6613431e603SJed Brown PetscInt bc_count[6] = {0}; 6623431e603SJed Brown for (PetscInt i = 0; i < npoints; i++) { 6633431e603SJed Brown PetscInt p = points[2 * i]; 6643431e603SJed Brown if (p < vStart || vEnd <= p) continue; 6654e2e9504SJed Brown fverts[num_fverts++] = p; 6663431e603SJed Brown Ijk loc = ZCodeSplit(vert_z[p - vStart]); 6673431e603SJed Brown // Convention here matches DMPlexCreateCubeMesh_Internal 6683431e603SJed Brown bc_count[0] += loc.i == 0; 6693431e603SJed Brown bc_count[1] += loc.i == layout.vextent.i - 1; 6703431e603SJed Brown bc_count[2] += loc.j == 0; 6713431e603SJed Brown bc_count[3] += loc.j == layout.vextent.j - 1; 6723431e603SJed Brown bc_count[4] += loc.k == 0; 6733431e603SJed Brown bc_count[5] += loc.k == layout.vextent.k - 1; 6743e72e933SJed Brown } 6753431e603SJed Brown PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &npoints, &points)); 6763431e603SJed Brown for (PetscInt bc = 0, bc_match = 0; bc < 2 * dim; bc++) { 6773431e603SJed Brown if (bc_count[bc] == PetscPowInt(2, dim - 1)) { 678*6725e60dSJed Brown PetscCall(DMPlexOrientPoint(dm, f, face_orient_dim[dim][bc])); 6794e2e9504SJed Brown if (periodicity[bc / 2] == DM_BOUNDARY_PERIODIC) { 6804e2e9504SJed Brown PetscInt *put; 6814e2e9504SJed Brown if (bc % 2 == 0) { // donor face; no label 6824e2e9504SJed Brown PetscCall(PetscSegBufferGet(my_donor_faces, 1, &put)); 6834e2e9504SJed Brown *put = f; 6844e2e9504SJed Brown } else { // periodic face 6854e2e9504SJed Brown PetscCall(PetscSegBufferGet(per_faces, 1, &put)); 6864e2e9504SJed Brown *put = f; 6874e2e9504SJed Brown ZCode *zput; 6884e2e9504SJed Brown PetscCall(PetscSegBufferGet(donor_face_closure, num_fverts, &zput)); 6894e2e9504SJed Brown for (PetscInt i = 0; i < num_fverts; i++) { 6904e2e9504SJed Brown Ijk loc = ZCodeSplit(vert_z[fverts[i] - vStart]); 6914e2e9504SJed Brown switch (bc / 2) { 6924e2e9504SJed Brown case 0: 6934e2e9504SJed Brown loc.i = 0; 6944e2e9504SJed Brown break; 6954e2e9504SJed Brown case 1: 6964e2e9504SJed Brown loc.j = 0; 6974e2e9504SJed Brown break; 6984e2e9504SJed Brown case 2: 6994e2e9504SJed Brown loc.k = 0; 7004e2e9504SJed Brown break; 7014e2e9504SJed Brown } 7024e2e9504SJed Brown *zput++ = ZEncode(loc); 7034e2e9504SJed Brown } 7044e2e9504SJed Brown } 7054e2e9504SJed Brown continue; 7064e2e9504SJed Brown } 7073431e603SJed Brown PetscAssert(bc_match == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face matches multiple face sets"); 7083431e603SJed Brown PetscCall(DMLabelSetValue(label, f, face_marker_dim[dim][bc])); 7093431e603SJed Brown bc_match++; 7103431e603SJed Brown } 7113431e603SJed Brown } 7123431e603SJed Brown } 7133431e603SJed Brown // Ensure that the Coordinate DM has our new boundary labels 7143431e603SJed Brown DM cdm; 7153431e603SJed Brown PetscCall(DMGetCoordinateDM(dm, &cdm)); 7163431e603SJed Brown PetscCall(DMCopyLabels(dm, cdm, PETSC_COPY_VALUES, PETSC_FALSE, DM_COPY_LABELS_FAIL)); 717*6725e60dSJed Brown if (periodicity[0] == DM_BOUNDARY_PERIODIC || (dim > 1 && periodicity[1] == DM_BOUNDARY_PERIODIC) || (dim > 2 && periodicity[2] == DM_BOUNDARY_PERIODIC)) { 718*6725e60dSJed Brown PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Periodicity_Private(dm, &layout, vert_z, per_faces, periodicity, donor_face_closure, my_donor_faces)); 7194e2e9504SJed Brown PetscSF sfper; 7204e2e9504SJed Brown PetscCall(DMPlexGetPeriodicFaceSF(dm, &sfper)); 7214e2e9504SJed Brown PetscCall(DMPlexSetPeriodicFaceSF(cdm, sfper)); 722*6725e60dSJed Brown cdm->periodic.setup = DMPeriodicCoordinateSetUp_Internal; 723*6725e60dSJed Brown } 724*6725e60dSJed Brown PetscCall(PetscSegBufferDestroy(&per_faces)); 725*6725e60dSJed Brown PetscCall(PetscSegBufferDestroy(&donor_face_closure)); 726*6725e60dSJed Brown PetscCall(PetscSegBufferDestroy(&my_donor_faces)); 7273431e603SJed Brown } 7284e2e9504SJed Brown PetscCall(PetscFree(layout.zstarts)); 7293431e603SJed Brown PetscCall(PetscFree(vert_z)); 7303e72e933SJed Brown PetscFunctionReturn(0); 7313e72e933SJed Brown } 7324e2e9504SJed Brown 7334e2e9504SJed Brown /*@ 7344e2e9504SJed Brown DMPlexSetPeriodicFaceSF - Express periodicity from an existing mesh 7354e2e9504SJed Brown 7364e2e9504SJed Brown Logically collective 7374e2e9504SJed Brown 7384e2e9504SJed Brown Input Parameters: 7394e2e9504SJed Brown + dm - The `DMPLEX` on which to set periodicity 7404e2e9504SJed Brown - face_sf - SF in which roots are (owned) donor faces and leaves are faces that must be matched to a (possibly remote) donor face. 7414e2e9504SJed Brown 7424e2e9504SJed Brown Level: advanced 7434e2e9504SJed Brown 7444e2e9504SJed Brown Notes: 7454e2e9504SJed Brown 7464e2e9504SJed Brown One can use `-dm_plex_box_sfc` to use this mode of periodicity, wherein the periodic points are distinct both globally 7474e2e9504SJed Brown and locally, but are paired when creating a global dof space. 7484e2e9504SJed Brown 7494e2e9504SJed Brown .seealso: [](chapter_unstructured), `DMPLEX`, `DMGetGlobalSection()`, `DMPlexGetPeriodicFaceSF()` 7504e2e9504SJed Brown @*/ 7514e2e9504SJed Brown PetscErrorCode DMPlexSetPeriodicFaceSF(DM dm, PetscSF face_sf) 7524e2e9504SJed Brown { 7534e2e9504SJed Brown DM_Plex *plex = (DM_Plex *)dm->data; 7544e2e9504SJed Brown PetscFunctionBegin; 7554e2e9504SJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7564e2e9504SJed Brown PetscCall(PetscObjectReference((PetscObject)face_sf)); 7574e2e9504SJed Brown PetscCall(PetscSFDestroy(&plex->periodic.face_sf)); 7584e2e9504SJed Brown plex->periodic.face_sf = face_sf; 759*6725e60dSJed Brown PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetPointSFComposed_C", DMGetPointSFComposed_Plex)); 7604e2e9504SJed Brown PetscFunctionReturn(0); 7614e2e9504SJed Brown } 7624e2e9504SJed Brown 7634e2e9504SJed Brown /*@ 7644e2e9504SJed Brown DMPlexGetPeriodicFaceSF - Obtain periodicity for a mesh 7654e2e9504SJed Brown 7664e2e9504SJed Brown Logically collective 7674e2e9504SJed Brown 7684e2e9504SJed Brown Input Parameters: 7694e2e9504SJed Brown . dm - The `DMPLEX` for which to obtain periodic relation 7704e2e9504SJed Brown 7714e2e9504SJed Brown Output Parameters: 7724e2e9504SJed Brown . face_sf - SF in which roots are (owned) donor faces and leaves are faces that must be matched to a (possibly remote) donor face. 7734e2e9504SJed Brown 7744e2e9504SJed Brown Level: advanced 7754e2e9504SJed Brown 7764e2e9504SJed Brown .seealso: [](chapter_unstructured), `DMPLEX`, `DMGetGlobalSection()`, `DMPlexSetPeriodicFaceSF()` 7774e2e9504SJed Brown @*/ 7784e2e9504SJed Brown PetscErrorCode DMPlexGetPeriodicFaceSF(DM dm, PetscSF *face_sf) 7794e2e9504SJed Brown { 7804e2e9504SJed Brown DM_Plex *plex = (DM_Plex *)dm->data; 7814e2e9504SJed Brown PetscFunctionBegin; 7824e2e9504SJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7834e2e9504SJed Brown *face_sf = plex->periodic.face_sf; 7844e2e9504SJed Brown PetscFunctionReturn(0); 7854e2e9504SJed Brown } 786*6725e60dSJed Brown 787*6725e60dSJed Brown /*@ 788*6725e60dSJed Brown DMPlexSetPeriodicFaceTransform - set geometric transform from donor to periodic points 789*6725e60dSJed Brown 790*6725e60dSJed Brown Logically Collective 791*6725e60dSJed Brown 792*6725e60dSJed Brown Input Arguments: 793*6725e60dSJed Brown + dm - `DMPlex` that has been configured with `DMPlexSetPeriodicFaceSF()` 794*6725e60dSJed Brown - t - 4x4 affine transformation basis. 795*6725e60dSJed Brown 796*6725e60dSJed Brown @*/ 797*6725e60dSJed Brown PetscErrorCode DMPlexSetPeriodicFaceTransform(DM dm, const PetscScalar t[4][4]) 798*6725e60dSJed Brown { 799*6725e60dSJed Brown DM_Plex *plex = (DM_Plex *)dm->data; 800*6725e60dSJed Brown PetscFunctionBegin; 801*6725e60dSJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 802*6725e60dSJed Brown for (PetscInt i = 0; i < 4; i++) { 803*6725e60dSJed Brown for (PetscInt j = 0; j < 4; j++) { 804*6725e60dSJed Brown PetscCheck(i != j || t[i][j] == 1., PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Rotated transforms not supported"); 805*6725e60dSJed Brown plex->periodic.transform[i][j] = t[i][j]; 806*6725e60dSJed Brown } 807*6725e60dSJed Brown } 808*6725e60dSJed Brown PetscFunctionReturn(0); 809*6725e60dSJed Brown } 810