31 template <rowsize f2l_rs>
32 static std::vector<MPI_int> ComputeFollowMapFromAdj(
33 const ArrayAdjacencyPair<f2l_rs> &follower2leader,
35 const ssp<GlobalOffsetsMapping> &leaderGM,
36 const std::vector<MPI_int> &leaderTargetRanks,
43 ArrayAdjacencyPair<1> leaderLookup;
44 leaderLookup.InitPair(
"followMap_leaderLookup", mpi);
45 auto nLeader =
static_cast<index>(leaderTargetRanks.size());
46 leaderLookup.father->Resize(nLeader);
48 leaderLookup(
i, 0) =
static_cast<index>(leaderTargetRanks[
i]);
49 leaderLookup.TransAttach();
50 leaderLookup.trans.createFatherGlobalMapping();
53 std::set<index> offRankLeaderGlobals;
54 for (
index i = 0;
i < nFollower;
i++)
55 for (
rowsize j = 0;
j < follower2leader.RowSize(
i);
j++)
57 index leaderGlobal = follower2leader(
i,
j);
60 auto [found, rank, val] = leaderGM->search(leaderGlobal);
61 if (found && rank !=
mpi.rank)
62 offRankLeaderGlobals.insert(leaderGlobal);
66 std::vector<index> pullSet(offRankLeaderGlobals.begin(), offRankLeaderGlobals.end());
67 leaderLookup.trans.createGhostMapping(pullSet);
68 leaderLookup.trans.createMPITypes();
69 leaderLookup.trans.pullOnce();
72 std::vector<MPI_int> followMap(nFollower,
mpi.size);
73 for (
index i = 0;
i < nFollower;
i++)
76 for (
rowsize j = 0;
j < follower2leader.RowSize(
i);
j++)
78 index leaderGlobal = follower2leader(
i,
j);
84 bool found = leaderLookup.trans.pLGhostMapping->search_indexAppend(
85 leaderGlobal, rank, val);
87 auto leaderTarget =
static_cast<MPI_int>(leaderLookup(val, 0));
88 minRank = std::min(minRank, leaderTarget);
91 followMap[
i] = (minRank <
mpi.size) ? minRank :
mpi.rank;
109 std::unordered_map<EntityKind, std::vector<MPI_int>> allMaps;
110 for (
const auto &em :
input.explicitMaps)
111 allMaps[em.kind] = em.targetRanks;
119 "ReorderPlan::build: input.follows must be empty; "
120 "use UnstructuredMesh::resolveFollows to compute follow maps "
121 "before calling build");
124 plan.reorderedKinds.clear();
125 for (
auto &[kind, ranks] : allMaps)
127 plan.reorderedKinds.insert(kind);
129 DNDS_assert_info(gm, fmt::format(
"ReorderPlan::build: no global mapping for kind {}",
135 plan.isLocalOnly =
true;
139 plan.isLocalOnly =
false;
143 int localFlag =
plan.isLocalOnly ? 1 : 0;
144 MPI_Allreduce(&localFlag, &globalFlag, 1, MPI_INT, MPI_LAND, mpi.comm);
145 plan.isLocalOnly = (globalFlag != 0);
148 for (
auto kind :
plan.reorderedKinds)
150 std::set<index> pullSetCollector;
154 std::vector<index> pullSet;
155 auto psIt = registry.
pullSets.find(kind);
156 if (psIt != registry.
pullSets.end())
157 pullSet = psIt->second;
159 plan.lookups[kind] =
plan.transfers.at(kind).buildLookup(pullSet, mpi);
172 for (
auto &
adj : registry.
adjs)
182 auto it =
lookups.find(targetKind);
184 fmt::format(
"ReorderPlan::apply REMAP: no lookup for target kind {}",
187 adj.remapFn(it->second);
192 for (
auto &
adj : registry.
adjs)
202 fmt::format(
"ReorderPlan::apply RELOCATE: no transfer for source kind {}",
205 adj.relocateFn(it->second, mpi);
216 fmt::format(
"ReorderPlan::apply COMPANION: no transfer for kind {}",
218 comp.fn(it->second, mpi);
228 const std::unordered_set<EntityKind> &destroyKinds)
234 return destroyKinds.count(kind.from) || destroyKinds.count(kind.to);
282 if (!pair.father || destroyKinds.count(kind))
285 {
t.transferRows(pair,
m); }, name);
313 if (pair.father && pair.father->pLGlobalMapping)
314 return pair.father->pLGlobalMapping;
378 for (
auto &[kind, ps] :
reg.pullSets)
380 std::sort(ps.begin(), ps.end());
381 ps.erase(std::unique(ps.begin(), ps.end()), ps.end());
417 std::unordered_map<EntityKind, std::vector<MPI_int>> allMaps;
418 for (
auto &em : augmented.explicitMaps)
419 allMaps[em.kind] = em.targetRanks;
421 for (
auto &spec : augmented.follows)
423 if (allMaps.count(spec.follower))
426 auto leaderIt = allMaps.find(spec.leader);
428 fmt::format(
"resolveFollows: follow spec references leader {} "
430 entityKindName(spec.leader)));
432 auto followerGM =
reg.getGlobalMapping(spec.follower);
434 fmt::format(
"resolveFollows: no global mapping for follower {}",
435 entityKindName(spec.follower)));
436 index nFollower = followerGM->RLengths()[mpi.rank];
438 std::vector<MPI_int> followMap;
439 if (spec.follower2leader == Adj::Node2Cell && node2cell.father)
441 followMap = ComputeFollowMapFromAdj(
442 static_cast<const tAdjPair &
>(node2cell),
443 nFollower,
reg.getGlobalMapping(spec.leader),
444 leaderIt->second, mpi);
446 else if (spec.follower2leader == Adj::Bnd2Cell && bnd2cell.father)
448 followMap = ComputeFollowMapFromAdj(
449 static_cast<const tAdj2Pair &
>(bnd2cell),
450 nFollower,
reg.getGlobalMapping(spec.leader),
451 leaderIt->second, mpi);
453 else if (spec.follower2leader == Adj::Node2Bnd && node2bnd.father)
455 followMap = ComputeFollowMapFromAdj(
456 static_cast<const tAdjPair &
>(node2bnd),
457 nFollower,
reg.getGlobalMapping(spec.leader),
458 leaderIt->second, mpi);
463 fmt::format(
"resolveFollows: unsupported follow adj {}",
467 allMaps[spec.follower] = std::move(followMap);
471 ReorderInput finalInput;
472 for (
auto &[kind, ranks] : allMaps)
473 finalInput.explicitMaps.
push_back(EntityReorderMap{kind, ranks});
474 finalInput.destroyKinds =
input.destroyKinds;
484 auto reg = buildReorderRegistry(
input.destroyKinds);
497 "ReorderEntities: adjPrimaryState must be Adj_PointToGlobal");
500 auto reg = buildReorderRegistry(
input.destroyKinds);
513 for (
auto kind :
input.destroyKinds)
515 if (kind == EntityKind::Face)
523 faceElemInfo.father.reset();
524 faceElemInfo.son.reset();
527 face2nodePbi.father.reset();
528 face2nodePbi.son.reset();
540 for (
auto kind :
plan.reorderedKinds)
542 if (kind == EntityKind::Cell &&
cell2node.father)
546 if (cell2cell.father)
547 cell2cell.father->pLGlobalMapping =
cell2node.father->pLGlobalMapping;
550 if (cell2cellOrig.father)
551 cell2cellOrig.father->pLGlobalMapping =
cell2node.father->pLGlobalMapping;
553 else if (kind == EntityKind::Node && coords.father)
555 coords.father->createGlobalMapping();
556 if (node2nodeOrig.father)
557 node2nodeOrig.father->pLGlobalMapping = coords.father->pLGlobalMapping;
559 else if (kind == EntityKind::Bnd && bnd2node.father)
561 bnd2node.father->createGlobalMapping();
562 if (bndElemInfo.father)
563 bndElemInfo.father->pLGlobalMapping = bnd2node.father->pLGlobalMapping;
564 if (bnd2bndOrig.father)
565 bnd2bndOrig.father->pLGlobalMapping = bnd2node.father->pLGlobalMapping;
567 else if (kind == EntityKind::Face && face2node.father)
569 face2node.father->createGlobalMapping();
570 if (faceElemInfo.father)
571 faceElemInfo.father->pLGlobalMapping = face2node.father->pLGlobalMapping;
582 using TArr =
typename std::remove_reference_t<
decltype(pair)>::t_arr;
588 for (
auto kind :
plan.reorderedKinds)
590 if (kind == EntityKind::Cell)
599 else if (kind == EntityKind::Node)
604 else if (kind == EntityKind::Bnd)
615 if (node2cell.father)
631 if (cell2cell.father)
632 cell2cell.idx.markGlobal();
634 bnd2node.idx.markGlobal();
636 bnd2cell.idx.markGlobal();
637 if (node2cell.father)
638 node2cell.idx.markGlobal();
640 node2bnd.idx.markGlobal();
644 if (node2cell.father)
648 cell2parentCell.clear();
649 node2parentNode.clear();
650 node2bndNode.clear();
651 vtkCell2nodeOffsets.clear();
653 vtkCell2node.clear();
654 nodeRecreated2nodeLocal.clear();
655 localPartitionStarts.clear();
666 cell2cell.isLocal() && bnd2cell.isLocal());
678 auto perm = detail::ComputeCellPermutation(
680 this->localPartitionStarts = std::move(
perm.localPartitionStarts);
684 if (mpi.rank == mRank)
685 log() << fmt::format(
"UnstructuredMesh === ReorderLocalCells, nPart0 [{}], "
686 "got reordering, bw [{}] to [{}]",
692 this->AdjLocal2GlobalFacial();
694 this->AdjLocal2GlobalC2F();
696 this->AdjLocal2GlobalC2CFace();
698 this->AdjLocal2GlobalN2CB();
736 if (
found && rank != mpi.rank)
742 if (node2cell.father)
744 if (face2cell.father)
746 if (cell2cellFace.father)
766 if (node2cell.father)
768 if (face2cell.father)
770 if (cell2cellFace.father)
778 if (cell2face.father)
780 if (cell2cellFace.father)
787 if (cell2cell.father)
788 cell2cell.father->pLGlobalMapping =
cell2node.father->pLGlobalMapping;
791 if (cell2cellOrig.father)
792 cell2cellOrig.father->pLGlobalMapping =
cell2node.father->pLGlobalMapping;
808 cell2node.trans.createFatherGlobalMapping();
821 using TArr =
typename std::remove_reference_t<
decltype(pair)>::t_arr;
825 pair.trans.BorrowGGIndexing(
cell2node.trans);
826 pair.trans.createMPITypes();
827 pair.trans.pullOnce();
832 if (cell2face.father)
834 if (cell2cellFace.father)
845 if (cell2cellFace.father && cell2cellFace.idx.isWired())
847 if (node2cell.father && node2cell.idx.isWired())
849 if (face2cell.father && face2cell.idx.isWired())
854 if (face2cell.father && face2cell.trans.pLGhostMapping)
855 face2cell.trans.pullOnce();
856 if (node2cell.father && node2cell.trans.pLGhostMapping)
857 node2cell.trans.pullOnce();
859 "ReorderLocalCells: bnd2cell must have ghost mapping for pull");
860 bnd2cell.trans.pullOnce();
864 this->AdjGlobal2LocalFacial();
866 this->AdjGlobal2LocalC2F();
868 this->AdjGlobal2LocalC2CFace();
870 this->AdjGlobal2LocalN2CB();
871 this->AdjGlobal2LocalPrimary();
873 if (mpi.rank == mRank)
874 log() << fmt::format(
"UnstructuredMesh === ReorderLocalCells finished") << std::endl;
#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 + ...
#define DNDS_check_throw_info(expr, info)
Same as DNDS_check_throw but attaches a user-supplied info message to the thrown std::runtime_error.
Helper for computing cell reordering permutations via Metis.
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 Cell2CellFace
constexpr AdjKind Node2Bnd
constexpr AdjKind Bnd2Face
constexpr AdjKind Cell2Cell
constexpr AdjKind Face2Node
constexpr AdjKind Face2Bnd
constexpr AdjKind Bnd2Cell
AdjAction classifyAdj(AdjKind adj, const std::unordered_set< EntityKind > &reorderedKinds)
Classify an adjacency given the set of reordered entity kinds.
std::function< void(const PermutationTransfer::LookupResult &lookup)> AdjRemapFn
Callback invoked during REMAP phase for an adjacency array.
@ RELOCATE
Source reordered, target not: move rows.
@ REMAP
Target reordered, source not: update entries.
@ RELOCATE_REMAP
Both reordered: update entries then move rows.
@ SELF
Intra-level (A==A): update entries then move rows.
std::function< void(const PermutationTransfer &transfer, const MPIInfo &mpi)> AdjRelocateFn
Callback invoked during RELOCATE phase for an adjacency or companion array.
const char * entityKindName(EntityKind kind)
String name for an EntityKind (for diagnostics).
DNDS::ArrayAdjacencyPair< DNDS::NonUniformSize > tAdjPair
std::string adjKindName(const AdjKind &kind)
Format an AdjKind as a diagnostic string, e.g. "Cell2Node", "Cell2Cell(Node)".
void AllreduceOneIndex(index &v, MPI_Op op, const MPIInfo &mpi)
Single-scalar Allreduce helper for indices (in-place, count = 1).
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::ostream & log()
Return the current DNDSR log stream (either std::cout or the installed file).
int MPI_int
MPI counterpart type for MPI_int (= C int). Used for counts and ranks in MPI calls.
ssp< TArray > father
Owned-side array (must be resized before ghost setup).
Per-adjacency index state tracking.
void apply(ReorderRegistry ®istry, const MPIInfo &mpi) const
std::unordered_map< EntityKind, PermutationTransfer > transfers
Per reordered entity kind: the computed transfer.
std::unordered_map< EntityKind, PermutationTransfer::LookupResult > lookups
Per reordered entity kind: the old->new global lookup.
static ReorderPlan build(const ReorderInput &input, const ReorderRegistry ®istry, const MPIInfo &mpi)
std::unordered_set< EntityKind > reorderedKinds
Set of entity kinds being reordered.
ssp< GlobalOffsetsMapping > getGlobalMapping(EntityKind kind) const
Get a registered global mapping (nullptr if not registered).
std::unordered_map< EntityKind, std::vector< index > > pullSets
std::vector< AdjEntry > adjs
All adjacency entries (mesh members + external).
std::vector< CompanionEntry > companions
All companion entries (mesh members + external).
tCoordPair nodeWallDist
wall dist:
UnstructuredMeshDeviceView< B > t_deviceView
tPbiPair cell2nodePbi
periodic only, after reader
AdjPairTracked< tAdjPair > cell2cellFace
constructed on demand
tCoordPair coordsElevDisp
only elevation
tPbiPair face2nodePbi
periodic only, after interpolated
AdjPairTracked< tAdj1Pair > face2bnd
AdjPairTracked< tAdj2Pair > face2cell
ReorderInput resolveFollows(const ReorderInput &input, const ReorderRegistry ®)
Augment a ReorderInput with default follows and compute follow maps.
AdjPairTracked< tAdjPair > cell2face
interpolated
ReorderRegistry buildReorderRegistry(const std::unordered_set< EntityKind > &destroyKinds={})
Build a ReorderRegistry containing all mesh members.
AdjPairTracked< tAdjPair > cell2cell
AdjPairTracked< tAdjPair > face2node
AdjPairTracked< tAdj1Pair > bnd2face
tElemInfoArrayPair faceElemInfo
AdjPairTracked< tAdjPair > cell2node
tElemInfoArrayPair cellElemInfo
AdjPairTracked< tAdjPair > node2bnd
AdjPairTracked< tAdjPair > bnd2node
AdjPairTracked< tAdjPair > node2cell
inverse relations
tElemInfoArrayPair bndElemInfo
AdjPairTracked< tAdj2Pair > bnd2cell
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
int rank
This rank's 0-based index within comm (-1 until initialised).
Tag type for naming objects created via make_ssp.
Result of buildLookup: ghost-pullable old-global -> new-global map.
static PermutationTransfer fromPartition(const std::vector< MPI_int > &partition, const ssp< GlobalOffsetsMapping > &oldGlobalMapping, const MPIInfo &mpi)
static PermutationTransfer fromLocalPermutation(const std::vector< index > &old2new, const ssp< GlobalOffsetsMapping > &oldGlobalMapping, const MPIInfo &mpi)
Eigen::Matrix< real, 5, 1 > v
tElemInfoArrayPair cellElemInfo
std::vector< MPI_int > cellPartition(nCellBefore)
mesh AdjLocal2GlobalPrimary()
input explicitMaps push_back(EntityReorderMap{EntityKind::Cell, cellPartition})