11#include <unordered_set>
12#include <unordered_map>
23static inline std::string meshPath(
const std::string &name)
25 std::string f(__FILE__);
26 for (
int i = 0;
i < 4;
i++)
28 auto pos = f.rfind(
'/');
29 if (pos == std::string::npos)
31 if (pos != std::string::npos)
34 return f +
"/data/mesh/" + name;
81 else if (
mpi.size == 2)
126 else if (
mpi.rank == 1)
175 auto gm = std::make_shared<GlobalOffsetsMapping>();
176 gm->setMPIAlignBcast(mpi, nodeLocalCount4Quad(mpi));
197static inline std::vector<std::set<DNDS::index>> gatherInverseGlobal(
204 std::vector<DNDS::index> localPacked;
208 auto row = support.
father->operator[](
i);
209 localPacked.push_back(toG);
210 localPacked.push_back(row.size());
216 int localSize =
static_cast<int>(localPacked.size());
217 std::vector<int> sizes(
mpi.size);
218 MPI_Allgather(&localSize, 1, MPI_INT, sizes.data(), 1, MPI_INT,
mpi.comm);
220 std::vector<int> disps(
mpi.size + 1, 0);
221 for (
int r = 0;
r <
mpi.size;
r++)
222 disps[
r + 1] = disps[
r] + sizes[
r];
224 std::vector<DNDS::index> allPacked(disps[
mpi.size]);
230 std::vector<std::set<DNDS::index>>
result(nToGlobal);
232 while (pos <
static_cast<DNDS::index>(allPacked.size()))
237 result[toG].insert(allPacked[pos++]);
261 auto e =
Elem::Element{parentElemInfo[iParent]->getElemType()};
262 return e.GetNumFaces();
266 auto eParent =
Elem::Element{parentElemInfo[iParent]->getElemType()};
267 auto eFace = eParent.ObtainFace(iSub);
268 return SubEntityDesc{eFace.GetNumVertices(), eFace.GetNumNodes(),
269 static_cast<t_index>(eFace.type)};
272 const std::function<
DNDS::index(
int)> &parentNodes,
275 auto eParent =
Elem::Element{parentElemInfo[iParent]->getElemType()};
276 auto eFace = eParent.ObtainFace(iSub);
278 std::vector<DNDS::index> pNodes(eParent.GetNumNodes());
279 for (
int i = 0;
i < eParent.GetNumNodes();
i++)
280 pNodes[
i] = parentNodes(
i);
281 std::vector<DNDS::index> fNodes(eFace.GetNumNodes());
282 eParent.ExtractFaceNodes(iSub, pNodes, fNodes);
283 for (
int i = 0;
i < eFace.GetNumNodes();
i++)
296 auto e =
Elem::Element{parentElemInfo[iParent]->getElemType()};
297 return e.GetNumEdges();
301 auto eParent =
Elem::Element{parentElemInfo[iParent]->getElemType()};
302 auto eEdge = eParent.ObtainEdge(iSub);
303 return SubEntityDesc{eEdge.GetNumVertices(), eEdge.GetNumNodes(),
304 static_cast<t_index>(eEdge.type)};
307 const std::function<
DNDS::index(
int)> &parentNodes,
310 auto eParent =
Elem::Element{parentElemInfo[iParent]->getElemType()};
311 auto eEdge = eParent.ObtainEdge(iSub);
312 std::vector<DNDS::index> pNodes(eParent.GetNumNodes());
313 for (
int i = 0;
i < eParent.GetNumNodes();
i++)
314 pNodes[
i] = parentNodes(
i);
315 std::vector<DNDS::index> eNodes(eEdge.GetNumNodes());
316 eParent.ExtractEdgeNodes(iSub, pNodes, eNodes);
317 for (
int i = 0;
i < eEdge.GetNumNodes();
i++)
339 const std::vector<std::pair<
Elem::ElemType, std::vector<DNDS::index>>> &cells,
345 m.cell2node.InitPair(
"test_c2n", mpi);
346 m.cellElemInfo.InitPair(
"test_cei", mpi);
349 m.cell2node.father->Resize(nCells);
350 m.cellElemInfo.father->Resize(nCells);
354 auto &[et, nodes] = cells[
i];
355 m.cell2node.father->ResizeRow(
i, nodes.size());
356 for (
DNDS::rowsize j = 0; j < static_cast<DNDS::rowsize>(nodes.size());
j++)
357 m.cell2node.father->operator()(
i,
j) = nodes[
j];
362 m.cellElemInfo(
i, 0) = ei;
369static inline std::set<DNDS::index> getEntityVertexSet(
376 std::set<DNDS::index> verts;
377 for (
int j = 0;
j < nVerts;
j++)
378 verts.insert(entity2node.
father->operator()(iEntity,
j));
409 m.cellElemInfo.InitPair(
"p2x2_cei", mpi);
410 m.cell2nodePbi.InitPair(
"p2x2_pbi", mpi);
413 m.cellElemInfo.father->Resize(4);
414 m.cell2nodePbi.father->Resize(4);
423 uint8_t pbi[4][4] = {
427 {0, 0x01, 0x01 | 0x02, 0x02},
436 m.cell2node.father->ResizeRow(
i, 4);
437 m.cell2nodePbi.father->ResizeRow(
i, 4);
438 m.cellElemInfo(
i, 0) = qi;
441 m.cell2node.father->operator()(
i,
j) = c2n[
i][
j];
471 m.cellElemInfo.InitPair(
"p2x2x2_cei", mpi);
472 m.cell2nodePbi.InitPair(
"p2x2x2_pbi", mpi);
475 m.cellElemInfo.father->Resize(8);
476 m.cell2nodePbi.father->Resize(8);
483 {0, 1, 3, 2, 4, 5, 7, 6},
484 {1, 0, 2, 3, 5, 4, 6, 7},
485 {2, 3, 1, 0, 6, 7, 5, 4},
486 {3, 2, 0, 1, 7, 6, 4, 5},
487 {4, 5, 7, 6, 0, 1, 3, 2},
488 {5, 4, 6, 7, 1, 0, 2, 3},
489 {6, 7, 5, 4, 2, 3, 1, 0},
490 {7, 6, 4, 5, 3, 2, 0, 1},
492 uint8_t pbi[8][8] = {
493 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
494 {0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00},
495 {0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02},
496 {0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x03, 0x02},
497 {0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04},
498 {0x00, 0x01, 0x01, 0x00, 0x04, 0x05, 0x05, 0x04},
499 {0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06},
500 {0x00, 0x01, 0x03, 0x02, 0x04, 0x05, 0x07, 0x06},
509 m.cell2node.father->ResizeRow(
i, 8);
510 m.cell2nodePbi.father->ResizeRow(
i, 8);
511 m.cellElemInfo(
i, 0) = hi;
514 m.cell2node.father->operator()(
i,
j) = c2n[
i][
j];
539 std::vector<DNDS::index> nodesA, nodesB;
540 std::vector<NodePeriodicBits> pbiA, pbiB;
544 auto eEdge = eParentA.ObtainEdge(iSub);
545 nFN = eEdge.GetNumNodes();
546 nodesA.resize(nFN); nodesB.resize(nFN);
547 pbiA.resize(nFN); pbiB.resize(nFN);
548 eParentA.ExtractEdgeNodes(iSub,
cell2node[iParent], nodesA);
549 eParentA.ExtractEdgeNodes(iSub,
cell2nodePbi[iParent], pbiA);
550 eParentB.ExtractEdgeNodes(candidateSub,
cell2node[candidateParent], nodesB);
551 eParentB.ExtractEdgeNodes(candidateSub,
cell2nodePbi[candidateParent], pbiB);
555 auto eFace = eParentA.ObtainFace(iSub);
556 nFN = eFace.GetNumNodes();
557 nodesA.resize(nFN); nodesB.resize(nFN);
558 pbiA.resize(nFN); pbiB.resize(nFN);
559 eParentA.ExtractFaceNodes(iSub,
cell2node[iParent], nodesA);
560 eParentA.ExtractFaceNodes(iSub,
cell2nodePbi[iParent], pbiA);
561 eParentB.ExtractFaceNodes(candidateSub,
cell2node[candidateParent], nodesB);
562 eParentB.ExtractFaceNodes(candidateSub,
cell2nodePbi[candidateParent], pbiB);
565 using P = std::pair<DNDS::index, NodePeriodicBits>;
566 auto cmp = [](
const P &L,
const P &R)
567 {
return L.first == R.first ? uint8_t(L.second) < uint8_t(R.second)
568 : L.first < R.first; };
569 std::vector<P> pA(nFN), pB(nFN);
570 for (
int i = 0;
i < nFN;
i++)
572 pA[
i] = {nodesA[
i], pbiA[
i]};
573 pB[
i] = {nodesB[
i], pbiB[
i]};
575 std::sort(pA.begin(), pA.end(), cmp);
576 std::sort(pB.begin(), pB.end(), cmp);
578 auto v0 = pA[0].second ^ pB[0].second;
579 for (
int i = 1;
i < nFN;
i++)
580 if ((pA[
i].second ^ pB[
i].second) != v0)
625 return ix *
N *
N + iy *
N + iz;
631 return ix * (
N + 1) * (
N + 1) + iy * (
N + 1) + iz;
644 if (!
periodic && mpi.rank == mpi.size - 1)
649 cellGM = std::make_shared<GlobalOffsetsMapping>();
651 nodeGM = std::make_shared<GlobalOffsetsMapping>();
664 gx = ((gx % totalNx) + totalNx) % totalNx;
672 ownerRank = mpi.size - 1;
673 localIx = gx - (mpi.size - 1) *
N;
678 localIx = gx - ownerRank *
N;
684 if (ownerRank >= mpi.size)
685 ownerRank = mpi.size - 1;
686 localIx = gx - ownerRank *
N;
688 DNDS::index localIdx = localIx * (
N + 1) * (
N + 1) + gy * (
N + 1) + gz;
689 return (*
nodeGM)(ownerRank, 0) + localIdx;
702 std::vector<DNDS::index> ghostCellGlobals;
703 std::vector<std::vector<DNDS::index>> ghostCellNodes;
708 leftRank = (mpi.rank - 1 + mpi.size) % mpi.size;
719 srcIx *
N *
N + iy *
N + iz;
720 ghostCellGlobals.push_back(gcGlobal);
722 std::vector<DNDS::index> nodes(8);
726 nodes[0] = nodeGlobalPhys(gx, iy, iz);
727 nodes[1] = nodeGlobalPhys(gx + 1, iy, iz);
728 nodes[2] = nodeGlobalPhys(gx + 1, iy + 1, iz);
729 nodes[3] = nodeGlobalPhys(gx, iy + 1, iz);
730 nodes[4] = nodeGlobalPhys(gx, iy, iz + 1);
731 nodes[5] = nodeGlobalPhys(gx + 1, iy, iz + 1);
732 nodes[6] = nodeGlobalPhys(gx + 1, iy + 1, iz + 1);
733 nodes[7] = nodeGlobalPhys(gx, iy + 1, iz + 1);
734 ghostCellNodes.push_back(std::move(nodes));
747 if (
periodic || mpi.rank < mpi.size - 1)
760 auto n = std::array<DNDS::index, 8>{
761 nodeGlobalPhys(gx, iy, iz),
762 nodeGlobalPhys(gx + 1, iy, iz),
763 nodeGlobalPhys(gx + 1, iy + 1, iz),
764 nodeGlobalPhys(gx, iy + 1, iz),
765 nodeGlobalPhys(gx, iy, iz + 1),
766 nodeGlobalPhys(gx + 1, iy, iz + 1),
767 nodeGlobalPhys(gx + 1, iy + 1, iz + 1),
768 nodeGlobalPhys(gx, iy + 1, iz + 1),
773 for (
int k = 0; k < 8; k++)
779 for (
auto &gc : ghostCellNodes)
785 std::vector<size_t> sortOrder(ghostCellGlobals.size());
786 std::iota(sortOrder.begin(), sortOrder.end(), 0);
787 std::sort(sortOrder.begin(), sortOrder.end(),
788 [&](
size_t a,
size_t b)
789 { return ghostCellGlobals[a] < ghostCellGlobals[b]; });
790 std::vector<DNDS::index> sortedGlobals(ghostCellGlobals.size());
791 std::vector<std::vector<DNDS::index>> sortedNodes(ghostCellNodes.size());
792 for (
size_t i = 0;
i < sortOrder.size();
i++)
794 sortedGlobals[
i] = ghostCellGlobals[sortOrder[
i]];
795 sortedNodes[
i] = ghostCellNodes[sortOrder[
i]];
797 ghostCellGlobals = std::move(sortedGlobals);
798 ghostCellNodes = std::move(sortedNodes);
820 for (
DNDS::index ig = 0; ig < static_cast<DNDS::index>(ghostCellGlobals.size()); ig++)
822 for (
int k = 0; k < 8; k++)
823 cell2node.
son->operator()(ig, k) = ghostCellNodes[ig][k];
831 std::vector<DNDS::index> ghostNodeGlobals;
837 ghostNodeGlobals.push_back(
ng);
841 dummyNode.
InitPair(
"dummyNode", mpi);
844 dummyNode.
trans.createFatherGlobalMapping();
845 dummyNode.
trans.createGhostMapping(ghostNodeGlobals);
846 dummyNode.
trans.createMPITypes();
853 for (
rowsize k = 0; k < 8; k++)
860 for (
DNDS::index ig = 0; ig < static_cast<DNDS::index>(ghostCellGlobals.size()); ig++)
861 for (
int k = 0; k < 8; k++)
865 DNDS_assert_info(found, fmt::format(
"ghost cell {} (global {}) node {} global {} not found "
866 "(rank {}, nNodeOwned {}, nNodeGhost {}, expected from ghostCellNodes {})",
868 ghostCellNodes[ig][k]));
889 auto f = e.ObtainFace(iSub);
897 auto f = e.ObtainFace(iSub);
898 std::vector<DNDS::index> pNodes(e.GetNumNodes());
899 for (
int i = 0;
i < e.GetNumNodes();
i++)
901 std::vector<DNDS::index> fNodes(f.GetNumNodes());
902 e.ExtractFaceNodes(iSub, pNodes, fNodes);
903 for (
int i = 0;
i < f.GetNumNodes();
i++)
921 auto ed = e.ObtainEdge(iSub);
929 auto ed = e.ObtainEdge(iSub);
930 std::vector<DNDS::index> pNodes(e.GetNumNodes());
931 for (
int i = 0;
i < e.GetNumNodes();
i++)
933 std::vector<DNDS::index> eNodes(ed.GetNumNodes());
934 e.ExtractEdgeNodes(iSub, pNodes, eNodes);
935 for (
int i = 0;
i < ed.GetNumNodes();
i++)
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Layered DAG of mesh adjacency relations with composable DSL operations.
Eigen::Matrix< real, 3, 3 > m
the host side operators are provided as implemented
const MPI_Datatype DNDS_MPI_INDEX
MPI datatype matching index (= MPI_INT64_T).
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
std::shared_ptr< T > ssp
Shortened alias for std::shared_ptr used pervasively in DNDSR.
int MPI_int
MPI counterpart type for MPI_int (= C int). Used for counts and ranks in MPI calls.
Convenience bundle of a father, son, and attached ArrayTransformer.
void TransAttach()
Bind the transformer to the current father / son pointers.
ssp< TArray > father
Owned-side array (must be resized before ghost setup).
void InitPair(const std::string &name, Args &&...args)
Allocate both father and son arrays, forwarding all args to TArray constructor.
ssp< TArray > son
Ghost-side array (sized automatically by createMPITypes / BorrowAndPull).
TTrans trans
Ghost-communication engine bound to father and son.
t_index zone
positive for BVnum, 0 for internal Elems, Negative for ?
DNDS_DEVICE_CALLABLE void setElemType(Elem::ElemType t)
DNDS_DEVICE_CALLABLE constexpr t_index GetNumVertices() const
std::function< void(index iParent, int iSub, const std::function< index(int)> &parentNodes, index *out)> extractNodes
std::function< SubEntityDesc(index iParent, int iSub)> describe
Describe sub-entity iSub of parent iParent.
std::function< int(index iParent)> numSubEntities
Number of sub-entities for parent iParent.
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Tag type for naming objects created via make_ssp.
void build(DNDS::index tileN, bool isPeriodic, const MPIInfo &mpi)
tElemInfoArrayPair cellElemInfo
ssp< OffsetAscendIndexMapping > nodeGhostMapping
DNDS::index cellLocal(DNDS::index ix, DNDS::index iy, DNDS::index iz) const
DNDS::index nodeLocal(DNDS::index ix, DNDS::index iy, DNDS::index iz) const
ssp< GlobalOffsetsMapping > cellGM
ssp< GlobalOffsetsMapping > nodeGM
ssp< OffsetAscendIndexMapping > cellGhostMapping
tElemInfoArrayPair cellElemInfo
tElemInfoArrayPair cellElemInfo
tElemInfoArrayPair cellElemInfo
Eigen::Matrix< real, 5, 1 > v
std::set< DNDS::index > allNodeGlobals
tElemInfoArrayPair cellElemInfo
input explicitMaps push_back(EntityReorderMap{EntityKind::Cell, cellPartition})
Eigen::Vector3d n(1.0, 0.0, 0.0)