12#define DOCTEST_CONFIG_IMPLEMENT
26int main(
int argc,
char **argv)
28 MPI_Init(&argc, &argv);
30 ctx.applyCommandLine(argc, argv);
49 std::unordered_set<EntityKind> reordered;
51 SUBCASE(
"empty reordered set")
57 SUBCASE(
"cell only reordered")
59 reordered = {EntityKind::Cell};
70 SUBCASE(
"node only reordered")
72 reordered = {EntityKind::Node};
80 SUBCASE(
"cell + node reordered")
82 reordered = {EntityKind::Cell, EntityKind::Node};
90 SUBCASE(
"cell + node + bnd reordered")
92 reordered = {EntityKind::Cell, EntityKind::Node, EntityKind::Bnd};
108 auto mpi = worldMPI();
112 auto gm = make_ssp<GlobalOffsetsMapping>();
113 gm->setMPIAlignBcast(mpi, 10);
114 reg.registerGlobalMapping(EntityKind::Cell, gm);
116 CHECK(
reg.getGlobalMapping(EntityKind::Cell) == gm);
117 CHECK(
reg.getGlobalMapping(EntityKind::Node) ==
nullptr);
120 bool remapCalled =
false;
121 bool relocateCalled =
false;
125 { remapCalled =
true; },
127 { relocateCalled =
true; },
132 CHECK(
reg.adjs[0].name ==
"cell2node");
135 bool compCalled =
false;
136 reg.registerCompanion(
139 { compCalled =
true; },
143 CHECK(
reg.companions[0].kind == EntityKind::Cell);
150TEST_CASE(
"ReorderPlan::apply cell-only local permutation")
152 auto mpi = worldMPI();
168 nodeArr.father->createGlobalMapping();
189 reg.registerGlobalMapping(EntityKind::Node,
nodeArr.father->pLGlobalMapping);
198 reg.registerCompanion(
211 CHECK(
plan.reorderedKinds.count(EntityKind::Cell));
212 CHECK_FALSE(
plan.reorderedKinds.count(EntityKind::Node));
233 auto mpi = worldMPI();
246 nodeArr.father->createGlobalMapping();
259 coords.InitPair(
"coords", mpi);
260 coords.father->Resize(
nNode);
267 reg.registerGlobalMapping(EntityKind::Node,
nodeArr.father->pLGlobalMapping);
284 reg.registerCompanion(
297 CHECK(
plan.reorderedKinds.count(EntityKind::Node));
298 CHECK_FALSE(
plan.reorderedKinds.count(EntityKind::Cell));
325static std::string meshPath(
const std::string &name)
327 std::string f(__FILE__);
328 for (
int i = 0;
i < 4;
i++)
330 auto pos = f.rfind(
'/');
331 if (pos == std::string::npos)
333 if (pos != std::string::npos)
334 f = f.substr(0, pos);
336 return f +
"/data/mesh/" + name;
342 const MPIInfo &mpi,
const std::string &file,
int dim,
343 bool withFaces =
false)
345 auto mesh = make_ssp<UnstructuredMesh>(mpi, dim);
347 reader.ReadFromCGNSSerial(meshPath(file));
348 reader.BuildCell2Cell();
355 reader.MeshPartitionCell2Cell(pOpt);
356 reader.PartitionReorderToMeshCell2Cell();
358 mesh->RecoverNode2CellAndNode2Bnd();
359 mesh->RecoverCell2CellAndBnd2Cell();
360 mesh->BuildGhostPrimary();
361 mesh->AdjGlobal2LocalPrimary();
365 mesh->InterpolateFace();
366 mesh->AdjLocal2GlobalN2CB();
367 mesh->BuildGhostN2CB();
368 mesh->AdjGlobal2LocalN2CB();
375static std::set<DNDS::index> collectOwnedGlobals(
378 std::set<DNDS::index>
result;
389 return gm->globalSize();
394static bool checkAdjEntriesValid(
403 if (v < 0 || v >= targetGlobalSize)
413TEST_CASE(
"ReorderEntities cell-only local on UniformSquare_10")
415 auto mpi = worldMPI();
416 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
422 DNDS::index nCellGlobal =
mesh->cell2node.father->pLGlobalMapping->globalSize();
423 DNDS::index nNodeGlobal =
mesh->coords.father->pLGlobalMapping->globalSize();
426 mesh->AdjLocal2GlobalPrimary();
443 CHECK(
mesh->cell2node.father->pLGlobalMapping->globalSize() == nCellGlobal);
444 CHECK(
mesh->coords.father->pLGlobalMapping->globalSize() == nNodeGlobal);
449 CHECK(checkAdjEntriesValid(
mesh->bnd2cell, nBndBefore, nCellGlobal));
452 CHECK(checkAdjEntriesValid(
mesh->node2cell, nNodeBefore, nCellGlobal));
455 mesh->RecoverNode2CellAndNode2Bnd();
456 mesh->RecoverCell2CellAndBnd2Cell();
457 mesh->BuildGhostPrimary();
458 mesh->AdjGlobal2LocalPrimary();
466 CHECK(iN < mesh->NumNodeProc());
474TEST_CASE(
"ReorderEntities cell-only with face destruction on UniformSquare_10")
476 auto mpi = worldMPI();
478 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
481 mesh->InterpolateFace();
486 mesh->AdjLocal2GlobalPrimary();
487 mesh->AdjLocal2GlobalFacial();
488 mesh->AdjLocal2GlobalC2F();
501 CHECK_FALSE(
mesh->face2node.father);
502 CHECK_FALSE(
mesh->face2cell.father);
503 CHECK_FALSE(
mesh->cell2face.father);
511 mesh->RecoverNode2CellAndNode2Bnd();
512 mesh->RecoverCell2CellAndBnd2Cell();
513 mesh->BuildGhostPrimary();
514 mesh->AdjGlobal2LocalPrimary();
515 mesh->InterpolateFace();
516 mesh->AssertOnFaces();
523TEST_CASE(
"ReorderEntities cell distributed round-robin with follow")
525 auto mpi = worldMPI();
529 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
531 DNDS::index nCellGlobal =
mesh->cell2node.father->pLGlobalMapping->globalSize();
532 DNDS::index nNodeGlobal =
mesh->coords.father->pLGlobalMapping->globalSize();
533 DNDS::index nBndGlobal =
mesh->bnd2node.father->pLGlobalMapping->globalSize();
536 mesh->AdjLocal2GlobalPrimary();
553 DNDS::index newCellGlobal =
mesh->cell2node.father->pLGlobalMapping->globalSize();
554 DNDS::index newNodeGlobal =
mesh->coords.father->pLGlobalMapping->globalSize();
555 DNDS::index newBndGlobal =
mesh->bnd2node.father->pLGlobalMapping->globalSize();
556 CHECK(newCellGlobal == nCellGlobal);
557 CHECK(newNodeGlobal == nNodeGlobal);
558 CHECK(newBndGlobal == nBndGlobal);
561 CHECK(checkAdjEntriesValid(
mesh->cell2node,
mesh->NumCell(), newNodeGlobal));
562 CHECK(checkAdjEntriesValid(
mesh->cell2cell,
mesh->NumCell(), newCellGlobal));
563 CHECK(checkAdjEntriesValid(
mesh->bnd2node,
mesh->NumBnd(), newNodeGlobal));
564 CHECK(checkAdjEntriesValid(
mesh->bnd2cell,
mesh->NumBnd(), newCellGlobal));
568 DNDS::index myOffset = (*
mesh->cell2node.father->pLGlobalMapping)(mpi.rank, 0);
574 CHECK(g < newCellGlobal);
578 mesh->RecoverNode2CellAndNode2Bnd();
579 mesh->RecoverCell2CellAndBnd2Cell();
580 mesh->BuildGhostPrimary();
581 mesh->AdjGlobal2LocalPrimary();
589 CHECK(iN < mesh->NumNodeProc());
597TEST_CASE(
"ReorderEntities node-only local on UniformSquare_10")
599 auto mpi = worldMPI();
600 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
604 DNDS::index nNodeGlobal =
mesh->coords.father->pLGlobalMapping->globalSize();
607 std::vector<tPoint> coordsBefore(nNodeBefore);
609 coordsBefore[
i] =
mesh->coords[
i];
612 mesh->AdjLocal2GlobalPrimary();
629 CHECK(
mesh->coords.father->pLGlobalMapping->globalSize() == nNodeGlobal);
639 mesh->RecoverNode2CellAndNode2Bnd();
640 mesh->RecoverCell2CellAndBnd2Cell();
641 mesh->BuildGhostPrimary();
642 mesh->AdjGlobal2LocalPrimary();
643 mesh->InterpolateFace();
644 mesh->AssertOnFaces();
652TEST_CASE(
"PermutationTransfer + buildLookup: reverse permutation value tracking")
654 auto mpi = worldMPI();
673 std::vector<DNDS::index> origCol0(
nLocal), origCol1(
nLocal);
681 std::vector<DNDS::index> old2new(
nLocal);
686 old2new,
cell2node.father->pLGlobalMapping, mpi);
687 CHECK(pt.isLocalOnly);
704 auto lookup = pt.buildLookup({}, mpi);
710 CHECK(lookup.resolve(oldGlobal) == expectedNewGlobal);
718TEST_CASE(
"PermutationTransfer distributed value tracking cross-rank")
720 auto mpi = worldMPI();
727 arr.InitPair(
"arr", mpi);
728 arr.father->Resize(
nLocal);
729 arr.father->createGlobalMapping();
731 DNDS::index myOffset = (*arr.father->pLGlobalMapping)(mpi.rank, 0);
737 arr(
i, 0) = TAG_BASE + myOffset +
i;
740 std::vector<MPI_int> partition(
nLocal);
742 partition[
i] =
static_cast<MPI_int>(
i % mpi.size);
745 partition, arr.father->pLGlobalMapping, mpi);
746 CHECK_FALSE(pt.isLocalOnly);
748 pt.transferRows(arr, mpi);
752 std::set<DNDS::index> receivedTags;
758 receivedTags.insert(
v);
761 CHECK(receivedTags.size() ==
static_cast<size_t>(
nAfter));
773TEST_CASE(
"PermutationTransfer::buildLookup cross-rank resolve with pullSet")
775 auto mpi = worldMPI();
781 auto gm = make_ssp<GlobalOffsetsMapping>();
782 gm->setMPIAlignBcast(mpi,
nLocal);
787 std::vector<MPI_int> partition(
nLocal);
789 partition[
i] =
static_cast<MPI_int>((mpi.rank +
i) % mpi.size);
794 int nextRank = (mpi.rank + 1) % mpi.size;
796 std::vector<DNDS::index> pullSet;
798 pullSet.push_back(nextOffset +
i);
799 std::sort(pullSet.begin(), pullSet.end());
801 auto lookup = pt.buildLookup(pullSet, mpi);
806 for (
auto oldG : pullSet)
831TEST_CASE(
"ReorderEntities with external companion array (solver-like)")
833 auto mpi = worldMPI();
834 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
844 solverDOF.father->pLGlobalMapping =
mesh->cell2node.father->pLGlobalMapping;
846 mesh->AdjLocal2GlobalPrimary();
913 CHECK(v0 / 10 == v1 / 10);
914 CHECK(v0 / 10 == v2 / 10);
923TEST_CASE(
"ReorderPlan::apply RELOCATE_REMAP (both source and target reordered)")
925 auto mpi = worldMPI();
938 nodeArr.father->createGlobalMapping();
958 reg.registerGlobalMapping(EntityKind::Node,
nodeArr.father->pLGlobalMapping);
1003TEST_CASE(
"buildReorderRegistry populates pullSets for off-rank references")
1005 auto mpi = worldMPI();
1009 auto mesh = buildMeshPrimary(mpi,
"UniformSquare_10.cgns", 2,
false);
1010 mesh->AdjLocal2GlobalPrimary();
1012 auto reg =
mesh->buildReorderRegistry({});
1016 auto cellGMIt =
reg.globalMappings.find(EntityKind::Cell);
1017 REQUIRE(cellGMIt !=
reg.globalMappings.end());
1018 auto cellGM = cellGMIt->second;
1019 DNDS::index myCellOffset = (*cellGM)(mpi.rank, 0);
1022 auto psIt =
reg.pullSets.find(EntityKind::Cell);
1023 if (psIt !=
reg.pullSets.end())
1025 const auto &ps = psIt->second;
1029 bool isOffRank = !(g >= myCellOffset && g < myCellOffset + myCellCount);
1036 for (
size_t i = 1;
i < ps.size();
i++)
1043 auto nodeGMIt =
reg.globalMappings.find(EntityKind::Node);
1044 REQUIRE(nodeGMIt !=
reg.globalMappings.end());
1045 auto nodeGM = nodeGMIt->second;
1046 DNDS::index myNodeOffset = (*nodeGM)(mpi.rank, 0);
1049 auto nodePsIt =
reg.pullSets.find(EntityKind::Node);
1050 if (nodePsIt !=
reg.pullSets.end())
1052 const auto &ps = nodePsIt->second;
1055 bool isOffRank = !(g >= myNodeOffset && g < myNodeOffset + myNodeCount);
1060 for (
size_t i = 1;
i < ps.size();
i++)
1069 for (
auto &
adj :
reg.adjs)
1080 std::set<std::string> compNames;
1081 for (
auto &c :
reg.companions)
1082 compNames.insert(c.name);
1083 CHECK(compNames.count(
"coords"));
1084 CHECK(compNames.count(
"cellElemInfo"));
1085 CHECK(compNames.count(
"bndElemInfo"));
Eigen::Matrix< real, 3, 3 > m
Distributed entity reordering framework: ReorderRegistry, ReorderPlan, ReorderInput.
constexpr AdjKind Bnd2Node
constexpr AdjKind Cell2Node
constexpr AdjKind Node2Cell
constexpr AdjKind Face2Cell
constexpr AdjKind Cell2Face
constexpr AdjKind Node2Bnd
constexpr AdjKind Cell2Cell
constexpr AdjKind Face2Node
constexpr AdjKind Bnd2Cell
AdjAction classifyAdj(AdjKind adj, const std::unordered_set< EntityKind > &reorderedKinds)
Classify an adjacency given the set of reordered entity kinds.
the host side operators are provided as implemented
const MPI_Datatype DNDS_MPI_INDEX
MPI datatype matching index (= MPI_INT64_T).
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
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.
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.
Per-entity reorder specification: where each owned entity goes.
static ReorderPlan build(const ReorderInput &input, const ReorderRegistry ®istry, const MPIInfo &mpi)
void registerGlobalMapping(EntityKind kind, ssp< GlobalOffsetsMapping > gm)
Register a GlobalOffsetsMapping for an entity kind.
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Result of buildLookup: ghost-pullable old-global -> new-global map.
index resolve(index oldGlobal) const
static PermutationTransfer fromPartition(const std::vector< MPI_int > &partition, const ssp< GlobalOffsetsMapping > &oldGlobalMapping, const MPIInfo &mpi)
void transferRows(TPair &pair, const MPIInfo &mpi) const
static PermutationTransfer fromLocalPermutation(const std::vector< index > &old2new, const ssp< GlobalOffsetsMapping > &oldGlobalMapping, const MPIInfo &mpi)
Eigen::Matrix< real, 5, 1 > v
REQUIRE(bool(result.parent2entityPbi.father))
CHECK(plan.reorderedKinds.count(EntityKind::Cell))
std::vector< MPI_int > nodePartition(nNode, mpi.rank)
ArrayAdjacencyPair< 1 > nodeArr
ArrayAdjacencyPair< 3 > solverDOF
std::vector< MPI_int > cellPartition(nCellBefore)
std::map< DNDS::index, std::array< DNDS::index, 3 > > expectedByOldGlobal
std::map< DNDS::index, std::array< DNDS::index, 2 > > oldCell2NodeByGlobal
ArrayAdjacencyPair< 2 > cell2node
TEST_CASE("3D: VFV P2 HQM error < P1 on sinCos3D")