DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
ReorderPlan.hpp
Go to the documentation of this file.
1#pragma once
2/// @file ReorderPlan.hpp
3/// @brief Distributed entity reordering framework: ReorderRegistry, ReorderPlan, ReorderInput.
4///
5/// Two-layer architecture:
6/// - ReorderRegistry: dynamic set of callbacks (adj remap/relocate + companion relocate)
7/// - ReorderPlan: standalone computed transfers + lookups, applies via callbacks
8///
9/// UnstructuredMesh provides buildReorderRegistry() and ReorderEntities() convenience methods.
10
12#include "MeshConnectivity.hpp"
13
14#include <functional>
15#include <string>
16#include <unordered_map>
17#include <unordered_set>
18
19namespace DNDS::Geom
20{
21 // =================================================================
22 // EntityReorderMap: per-entity target rank assignment
23 // =================================================================
24
25 /// Per-entity reorder specification: where each owned entity goes.
27 {
29 /// Per father slot: target rank after reorder. Size == father size.
30 std::vector<MPI_int> targetRanks;
31 };
32
33 // =================================================================
34 // FollowSpec: how one entity kind derives its placement from another
35 // =================================================================
36
37 /// Specification for follow-placement: entity `follower` derives its
38 /// target rank from entity `leader` via the support adjacency
39 /// `follower2leader` (e.g., Node follows Cell via node2cell).
40 ///
41 /// Assignment rule: follower entity goes to min(leader.targetRank)
42 /// over all leaders referencing it.
44 {
45 EntityKind follower{}; ///< Entity kind to derive map for.
46 EntityKind leader{}; ///< Explicit-map entity kind to follow.
47 AdjKind follower2leader; ///< Support adj: follower -> leader.
48 };
49
50 // =================================================================
51 // ReorderInput: what the caller provides
52 // =================================================================
53
54 /// Input to the reorder framework.
56 {
57 /// Explicit reorder maps (caller-provided).
58 std::vector<EntityReorderMap> explicitMaps;
59
60 /// Follow specifications (framework computes follow maps from these).
61 ///
62 /// When empty (default), the mesh wrapper applies the default policy:
63 /// all non-explicit entity kinds with a support adjacency to an
64 /// explicit kind follow it (currently: Node and Bnd follow Cell).
65 ///
66 /// When non-empty, only the listed follows are computed (overrides
67 /// the default policy — allows selective follow or custom adj routes).
68 std::vector<FollowSpec> follows;
69
70 /// Entity kinds whose adjacencies should be destroyed before reorder
71 /// (not reordered, not remapped -- just wiped). Typically {Face}.
72 std::unordered_set<EntityKind> destroyKinds;
73 };
74
75 // =================================================================
76 // Adjacency action classification
77 // =================================================================
78
79 /// Action to take on an adjacency during reorder.
80 enum class AdjAction
81 {
82 SKIP, ///< Neither source nor target reordered.
83 RELOCATE, ///< Source reordered, target not: move rows.
84 REMAP, ///< Target reordered, source not: update entries.
85 RELOCATE_REMAP, ///< Both reordered: update entries then move rows.
86 SELF, ///< Intra-level (A==A): update entries then move rows.
87 };
88
89 /// Classify an adjacency given the set of reordered entity kinds.
90 inline AdjAction classifyAdj(AdjKind adj, const std::unordered_set<EntityKind> &reorderedKinds)
91 {
92 if (adj.isIntraLevel())
93 return reorderedKinds.count(adj.from) ? AdjAction::SELF : AdjAction::SKIP;
94
95 bool fromReordered = reorderedKinds.count(adj.from) > 0;
96 bool toReordered = reorderedKinds.count(adj.to) > 0;
97
98 if (!fromReordered && !toReordered)
99 return AdjAction::SKIP;
100 if (fromReordered && !toReordered)
101 return AdjAction::RELOCATE;
102 if (!fromReordered && toReordered)
103 return AdjAction::REMAP;
105 }
106
107 // =================================================================
108 // ReorderRegistry: dynamic set of arrays participating in reorder
109 // =================================================================
110
111 /// Callback invoked during REMAP phase for an adjacency array.
112 using AdjRemapFn = std::function<void(const PermutationTransfer::LookupResult &lookup)>;
113
114 /// Callback invoked during RELOCATE phase for an adjacency or companion array.
115 using AdjRelocateFn = std::function<void(const PermutationTransfer &transfer, const MPIInfo &mpi)>;
116
117 /// One registered adjacency entry.
118 struct AdjEntry
119 {
121 AdjRemapFn remapFn; ///< Remap entries (null if not needed).
122 AdjRelocateFn relocateFn; ///< Relocate rows (null if not needed).
123 std::string name;
124 };
125
126 /// One registered companion entry.
128 {
129 EntityKind kind; ///< Entity kind this array is parallel to.
130 AdjRelocateFn fn; ///< Callback to relocate the array.
131 std::string name;
132 };
133
134 /// Dynamic set of arrays that participate in a reorder operation.
135 /// Built by UnstructuredMesh::buildReorderRegistry() for mesh members,
136 /// extended by external code (solver, evaluator) before plan application.
138 {
139 /// All adjacency entries (mesh members + external).
140 std::vector<AdjEntry> adjs;
141
142 /// All companion entries (mesh members + external).
143 std::vector<CompanionEntry> companions;
144
145 /// Global offsets mappings per entity kind (for PermutationTransfer).
146 std::unordered_map<EntityKind, ssp<GlobalOffsetsMapping>> globalMappings;
147
148 /// Pre-collected pull sets per entity kind: off-rank globals that adj
149 /// entries reference as targets. Populated by buildReorderRegistry or
150 /// by the caller before ReorderPlan::build.
151 std::unordered_map<EntityKind, std::vector<index>> pullSets;
152
153 /// Register an adjacency with type-erased callbacks.
154 void registerAdj(AdjKind kind, AdjRemapFn remap, AdjRelocateFn relocate,
155 std::string name = {})
156 {
157 adjs.push_back(AdjEntry{kind, std::move(remap), std::move(relocate), std::move(name)});
158 }
159
160 /// Register a companion with a type-erased relocate callback.
161 void registerCompanion(EntityKind kind, AdjRelocateFn fn, std::string name = {})
162 {
163 companions.push_back(CompanionEntry{kind, std::move(fn), std::move(name)});
164 }
165
166 /// Register a GlobalOffsetsMapping for an entity kind.
168 {
169 globalMappings[kind] = std::move(gm);
170 }
171
172 /// Get a registered global mapping (nullptr if not registered).
174 {
175 auto it = globalMappings.find(kind);
176 return (it != globalMappings.end()) ? it->second : nullptr;
177 }
178 };
179
180 // =================================================================
181 // ReorderPlan: computed transfers + lookups, applies via callbacks
182 // =================================================================
183
184 /// Standalone plan object containing all computed PermutationTransfers
185 /// and LookupResults for a set of entity kinds.
186 ///
187 /// After construction (via `build`), this object has no dependency on
188 /// UnstructuredMesh. It can apply to any ReorderRegistry.
190 {
191 /// Per reordered entity kind: the computed transfer.
192 std::unordered_map<EntityKind, PermutationTransfer> transfers;
193
194 /// Per reordered entity kind: the old->new global lookup.
195 std::unordered_map<EntityKind, PermutationTransfer::LookupResult> lookups;
196
197 /// Set of entity kinds being reordered.
198 std::unordered_set<EntityKind> reorderedKinds;
199
200 /// Whether all transfers are local-only (collective agreement).
201 bool isLocalOnly{false};
202
203 // -------------------------------------------------------------
204 // Factory
205 // -------------------------------------------------------------
206
207 /// Build a ReorderPlan from input + registry + MPI.
208 ///
209 /// Steps:
210 /// 1. Compute follow maps (ghost-pull leader targetRanks, min-rank rule).
211 /// 2. Build PermutationTransfer per entity kind.
212 /// 3. Collect pull sets per entity kind from registry adj entries.
213 /// 4. Build lookups (ghost-pullable old->new global).
214 ///
215 /// @warning Collective.
216 static ReorderPlan build(
217 const ReorderInput &input,
218 const ReorderRegistry &registry,
219 const MPIInfo &mpi);
220
221 // -------------------------------------------------------------
222 // Application
223 // -------------------------------------------------------------
224
225 /// Apply the plan to all entries in a registry.
226 ///
227 /// Phase 1: REMAP all adj entries (target kind's lookup).
228 /// Phase 2: RELOCATE all adj rows (source kind's transfer).
229 /// Phase 3: RELOCATE all companions of reordered kinds.
230 ///
231 /// @warning Collective (when !isLocalOnly).
232 void apply(ReorderRegistry &registry, const MPIInfo &mpi) const;
233
234 // -------------------------------------------------------------
235 // Standalone operations for external arrays
236 // -------------------------------------------------------------
237
238 /// Remap entries of an adjacency array whose target kind is `targetKind`.
239 template <class TPair>
240 void remapEntries(TPair &pair, EntityKind targetKind) const
241 {
242 auto it = lookups.find(targetKind);
243 DNDS_assert_info(it != lookups.end(),
244 "remapEntries: no lookup for target kind");
245 const auto &lookup = it->second;
246 for (index i = 0; i < pair.father->Size(); i++)
247 for (rowsize j = 0; j < pair.RowSize(i); j++)
248 {
249 index &v = pair(i, j);
250 if (v == UnInitIndex)
251 continue;
252 v = lookup.resolve(v);
253 }
254 }
255
256 /// Relocate rows of an array pair whose source kind is `sourceKind`.
257 template <class TPair>
258 void relocateRows(TPair &pair, EntityKind sourceKind, const MPIInfo &mpi) const
259 {
260 auto it = transfers.find(sourceKind);
261 DNDS_assert_info(it != transfers.end(),
262 "relocateRows: no transfer for source kind");
263 it->second.transferRows(pair, mpi);
264 }
265 };
266
267} // namespace DNDS::Geom
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:117
Layered DAG of mesh adjacency relations with composable DSL operations.
Utility for distributed or local row permutation/transfer of arrays.
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.
AdjAction
Action to take on an adjacency during reorder.
@ RELOCATE
Source reordered, target not: move rows.
@ REMAP
Target reordered, source not: update entries.
@ RELOCATE_REMAP
Both reordered: update entries then move rows.
@ SKIP
Neither source nor target reordered.
@ 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.
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
Definition Defines.hpp:181
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
Definition Defines.hpp:114
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
std::shared_ptr< T > ssp
Shortened alias for std::shared_ptr used pervasively in DNDSR.
Definition Defines.hpp:143
One registered adjacency entry.
AdjRelocateFn relocateFn
Relocate rows (null if not needed).
AdjRemapFn remapFn
Remap entries (null if not needed).
One registered companion entry.
EntityKind kind
Entity kind this array is parallel to.
AdjRelocateFn fn
Callback to relocate the array.
Per-entity reorder specification: where each owned entity goes.
std::vector< MPI_int > targetRanks
Per father slot: target rank after reorder. Size == father size.
AdjKind follower2leader
Support adj: follower -> leader.
EntityKind follower
Entity kind to derive map for.
EntityKind leader
Explicit-map entity kind to follow.
Input to the reorder framework.
std::vector< FollowSpec > follows
std::vector< EntityReorderMap > explicitMaps
Explicit reorder maps (caller-provided).
std::unordered_set< EntityKind > destroyKinds
void remapEntries(TPair &pair, EntityKind targetKind) const
Remap entries of an adjacency array whose target kind is targetKind.
void apply(ReorderRegistry &registry, const MPIInfo &mpi) const
bool isLocalOnly
Whether all transfers are local-only (collective agreement).
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 &registry, const MPIInfo &mpi)
void relocateRows(TPair &pair, EntityKind sourceKind, const MPIInfo &mpi) const
Relocate rows of an array pair whose source kind is sourceKind.
std::unordered_set< EntityKind > reorderedKinds
Set of entity kinds being reordered.
void registerGlobalMapping(EntityKind kind, ssp< GlobalOffsetsMapping > gm)
Register a GlobalOffsetsMapping for an entity kind.
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).
std::unordered_map< EntityKind, ssp< GlobalOffsetsMapping > > globalMappings
Global offsets mappings per entity kind (for PermutationTransfer).
void registerCompanion(EntityKind kind, AdjRelocateFn fn, std::string name={})
Register a companion with a type-erased relocate callback.
void registerAdj(AdjKind kind, AdjRemapFn remap, AdjRelocateFn relocate, std::string name={})
Register an adjacency with type-erased callbacks.
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Definition MPI.hpp:231
Result of buildLookup: ghost-pullable old-global -> new-global map.
Eigen::Matrix< real, 5, 1 > v
auto adj
const auto & transfer
ReorderInput input