24#include <unordered_map>
25#include <unordered_set>
30 template <
class TPair>
31 struct AdjPairTracked;
66 return (dim == 2) ? 1 : 1;
157 auto h =
static_cast<std::size_t
>(k.from) * 31 +
158 static_cast<std::size_t
>(k.to);
159 if (k.isIntraLevel())
160 h = h * 31 +
static_cast<std::size_t
>(k.via);
202 struct MeshConnectivity;
285 std::vector<std::vector<LevelEntry>>
levels;
293 [[nodiscard]] std::unordered_set<AdjKind, AdjKindHash>
requiredAdjs()
const;
300 [[nodiscard]] std::unordered_set<EntityKind>
collectedKinds()
const;
303 [[nodiscard]] std::string
dump()
const;
333 total +=
static_cast<index>(
v.size());
356 template <
class TPair>
359 return make_ssp<AdjVariant>(std::forward<TPair>(pair));
363 template <
class TPair>
366 return make_ssp<AdjVariant>(TPair{});
384 template <rowsize target_rs, rowsize source_rs = NonUniformSize>
385 static void narrowAdjToFixed(
386 const ArrayAdjacencyPair<source_rs> &source,
387 ArrayAdjacencyPair<target_rs> &target,
391 static_assert(target_rs > 0,
"narrowAdjToFixed: target must be fixed-width");
394 auto row = source.father->operator[](
i);
397 (
j <
static_cast<rowsize>(row.size())) ? row[
j] : fill;
433 template <
class TPair>
434 TPair &
as() {
return std::get<TPair>(*
adj); }
435 template <
class TPair>
436 [[nodiscard]]
const TPair &
as()
const {
return std::get<TPair>(*
adj); }
443 return std::visit([](
const auto &
p) ->
index
444 {
return p.father ?
p.father->Size() : 0; }, *
adj);
452 return std::visit([](
const auto &
p) ->
bool
453 {
return bool(
p.father); }, *
adj);
488 template <
class TPair>
489 TPair &
as() {
return std::get<TPair>(*
adj); }
490 template <
class TPair>
491 [[nodiscard]]
const TPair &
as()
const {
return std::get<TPair>(*
adj); }
497 return std::visit([](
const auto &
p) ->
index
498 {
return p.father ?
p.father->Size() : 0; }, *
adj);
505 return std::visit([](
const auto &
p) ->
bool
506 {
return bool(
p.father); }, *
adj);
565 std::function<void(
index iParent,
int iSub,
566 const std::function<
index(
int)> &parentNodes,
582 std::function<bool(
index iParent,
int iSub,
584 index candidateParent,
int candidateSub)>
606 std::function<void(
index iParent,
int iSub,
635 const std::vector<index> &parents,
636 const std::vector<MPI_int> &parentRanks,
637 index nLocalParents)>;
693 template <rowsize e2p_rs = NonUniformSize>
864 template <
class TPair>
867 auto adjVar = makeAdjVariant<TPair>();
868 auto &stored = std::get<TPair>(*adjVar);
869 stored.father = pair.father;
877 template <
class TPair>
880 auto adjVar = makeAdjVariant<TPair>();
881 auto &stored = std::get<TPair>(*adjVar);
882 stored.father = pair.father;
887 template <
class TPair>
894 template <
class TPair>
897 registerAdj(kind,
static_cast<const TPair &
>(pair));
925 bool hasCone(
int fromDepth,
int toDepth)
const;
938 bool hasSupport(
int fromDepth,
int toDepth)
const;
966 template <rowsize cone_rs = NonUniformSize>
971 const std::function<
index(
index)> &fromLocal2Global,
972 const std::function<
index(
index)> &toLocal2Global,
987 const std::unordered_map<index, index> &bGlobal2Local,
988 const std::function<
index(
index)> &aLocal2Global,
989 bool removeSelf =
false);
1035 const std::unordered_map<index, index> &bGlobal2Local,
1036 const std::function<
index(
index)> &aLocal2Global,
1038 const std::function<
bool(
index aLocal,
index cGlobal,
1039 const std::vector<index> &sharedBGlobals)>
1091 template <rowsize p2n_rs = NonUniformSize>
1132 template <rowsize p2n_rs = NonUniformSize>
1137 index nLocalParents,
1138 index nTotalParents,
1209 template <rowsize p2n_rs = NonUniformSize, rowsize e2p_rs = NonUniformSize>
1217 index nLocalParents,
1218 index nTotalParents,
1251 template <rowsize rs_AB, rowsize rs_BC, rowsize out_rs,
class Predicate>
1256 const std::unordered_map<index, index> &bGlobal2Local,
1257 const std::function<
index(
index)> &aLocal2Global,
1259 const std::function<
bool(
index aLocal,
index cGlobal,
1260 const std::vector<index> &sharedBGlobals)>
1263 const auto &mpi = AB.
father->getMPI();
1269 for (
index iA = 0; iA < nALocal; iA++)
1271 index aGlobal = aLocal2Global(iA);
1275 std::unordered_map<index, int> candidateSharedCount;
1276 std::unordered_map<index, std::vector<index>> candidateSharedBs;
1277 for (
auto iB : AB.
father->operator[](iA))
1280 if constexpr (rs_AB > 0)
1286 auto it = bGlobal2Local.find(iB);
1288 fmt::format(
"ComposeFiltered: B-entity global {} (referenced by A-entity "
1289 "local {} / global {}) not found in bGlobal2Local. "
1290 "Ghost pull of B→C is incomplete — the caller must "
1291 "pull BC for all B-globals referenced by AB rows.",
1293 index bLocal = it->second;
1294 for (
auto iC : BC[bLocal])
1297 if constexpr (rs_BC > 0)
1303 candidateSharedCount[iC]++;
1305 candidateSharedBs[iC].push_back(iB);
1310 std::vector<index> accepted;
1311 for (
auto &[cGlobal,
nShared] : candidateSharedCount)
1313 if (!pred(aGlobal, cGlobal,
nShared))
1317 if (!
matchExtra(iA, cGlobal, candidateSharedBs[cGlobal]))
1320 accepted.push_back(cGlobal);
1324 std::sort(accepted.begin(), accepted.end());
1328 result.father->ResizeRow(iA, accepted.size());
1329 for (
rowsize j = 0; j < static_cast<rowsize>(accepted.size());
j++)
1330 result.father->operator()(iA,
j) = accepted[
j];
1336 fmt::format(
"ComposeFiltered: row {} has {} entries but out_rs={}",
1337 iA, accepted.size(), out_rs));
1339 result.father->operator()(iA,
j) =
1351 template <rowsize rs_AB, rowsize rs_BC, rowsize out_rs>
1356 const std::unordered_map<index, index> &bGlobal2Local,
1357 const std::function<
index(
index)> &aLocal2Global,
1360 return ComposeFiltered<rs_AB, rs_BC, out_rs>(
1361 AB, BC, nALocal, bGlobal2Local, aLocal2Global,
1369 template <rowsize cone_rs>
1374 const std::function<
index(
index)> &fromLocal2Global,
1375 const std::function<
index(
index)> &toLocal2Global,
1379 std::unordered_map<index, std::unordered_set<index>> to2fromRecord;
1380 std::vector<index> ghostToIndices;
1381 std::unordered_set<index> ghostToSet;
1384 for (
index iFrom = 0; iFrom < nFromLocal; iFrom++)
1386 index fromGlobal = fromLocal2Global(iFrom);
1387 for (
auto iTo : cone.
father->operator[](iFrom))
1390 if constexpr (cone_rs > 0)
1396 to2fromRecord[iTo].insert(fromGlobal);
1398 auto [ret, rank, val] = toGlobalMapping->search(iTo);
1399 DNDS_assert_info(ret, fmt::format(
"Inverse: to-entity {} not found in global mapping", iTo));
1400 if (rank != mpi.rank && ghostToSet.find(iTo) == ghostToSet.end())
1402 ghostToIndices.push_back(iTo);
1403 ghostToSet.insert(iTo);
1410 support.
InitPair(
"Inverse_support", mpi);
1411 support.
father->Resize(nToLocal);
1413 for (
index iTo = 0; iTo < nToLocal; iTo++)
1415 index toGlobal = toLocal2Global(iTo);
1416 auto it = to2fromRecord.find(toGlobal);
1417 if (it != to2fromRecord.end())
1419 support.
father->ResizeRow(iTo, it->second.size());
1421 for (
auto fromG : it->second)
1422 support.
father->operator()(iTo,
j++) = fromG;
1428 support.
trans.createFatherGlobalMapping();
1429 support.
trans.createGhostMapping(ghostToIndices);
1431 support.
son->Resize(support.
trans.pLGhostMapping->ghostIndex.size());
1432 for (
auto &[toGlobal, fromSet] : to2fromRecord)
1436 if (!support.
trans.pLGhostMapping->search(toGlobal, rank, val))
1440 support.
son->ResizeRow(val, fromSet.size());
1442 for (
auto fromG : fromSet)
1443 support.
son->operator()(val,
j++) = fromG;
1448 using tSupportArr =
typename decltype(support.
son)::element_type;
1453 supportPastTrans.createFatherGlobalMapping();
1455 std::vector<index> pushSonSeries(support.
son->
Size());
1457 pushSonSeries[
i] =
i;
1458 supportPastTrans.createGhostMapping(pushSonSeries, support.
trans.pLGhostMapping->ghostStart);
1459 supportPastTrans.createMPITypes();
1460 supportPastTrans.pullOnce();
1466 for (
index i = 0;
i < supportPast->Size();
i++)
1468 index toGlobal = support.
trans.pLGhostMapping->pushingIndexGlobal[
i];
1469 for (
auto fromG : (*supportPast)[
i])
1470 to2fromRecord[toGlobal].insert(fromG);
1478 for (
index iTo = 0; iTo < nToLocal; iTo++)
1480 index toGlobal = toLocal2Global(iTo);
1481 auto it = to2fromRecord.find(toGlobal);
1482 if (it != to2fromRecord.end())
1484 std::vector<index> fromVec(it->second.begin(), it->second.end());
1485 std::sort(fromVec.begin(), fromVec.end());
1486 result.father->ResizeRow(iTo, fromVec.size());
1487 for (
rowsize j = 0; j < static_cast<rowsize>(fromVec.size());
j++)
1488 result.father->operator()(iTo,
j) = fromVec[
j];
Adjacency array (CSR-like index storage) built on ParArray.
Father-son array pairs with device views and ghost communication.
#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.
Table mapping rank-local row indices to the global index space.
Mapping between a rank's main data and its ghost copies.
constexpr AdjKind Bnd2Node
constexpr AdjKind Cell2Node
constexpr AdjKind Node2Cell
constexpr AdjKind Cell2Edge
constexpr AdjKind Face2Cell
constexpr AdjKind Edge2Node
constexpr AdjKind Cell2Face
constexpr AdjKind Cell2CellFace
constexpr AdjKind Node2Edge
constexpr AdjKind Node2Bnd
constexpr AdjKind Face2Edge
constexpr AdjKind Edge2Cell
constexpr AdjKind Bnd2Bnd
constexpr AdjKind Bnd2Face
constexpr AdjKind Cell2Cell
constexpr AdjKind Edge2Face
constexpr AdjKind Face2Node
constexpr AdjKind Node2Face
constexpr AdjKind Face2Bnd
constexpr AdjKind Face2Face
constexpr AdjKind Bnd2Cell
DNDS::ArrayAdjacencyPair< 2 > tAdj2Pair
std::function< OwnershipDecision(index parentL, index parentR, index nLocalParents)> OwnershipResolver2
Legacy 2-parent ownership resolver (used by InterpolateDistributed).
std::function< OwnershipDecision(const std::vector< index > &parents, const std::vector< MPI_int > &parentRanks, index nLocalParents)> OwnershipResolverMulti
DNDS::ArrayAdjacencyPair< 1 > tAdj1Pair
DNDS::ArrayAdjacencyPair< 4 > tAdj4Pair
const char * entityKindName(EntityKind kind)
String name for an EntityKind (for diagnostics).
int entityDepth(EntityKind kind, int dim)
DNDS::ArrayAdjacencyPair< DNDS::NonUniformSize > tAdjPair
DNDS::ArrayAdjacencyPair< 3 > tAdj3Pair
std::string adjKindName(const AdjKind &kind)
Format an AdjKind as a diagnostic string, e.g. "Cell2Node", "Cell2Cell(Node)".
std::variant< tAdjPair, tAdj1Pair, tAdj2Pair, tAdj3Pair, tAdj4Pair, tAdj8Pair > AdjVariant
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).
DNDS_CONSTANT const rowsize NonUniformSize
Template parameter flag: "each row has an independent width".
index size_to_index(size_t v)
Range-checked conversion from size_t to DNDS::index.
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.
DNDS_DEVICE_CALLABLE index Size() const
Combined father + son row count.
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.
Hash for AdjKind (for use in unordered containers).
std::size_t operator()(const AdjKind &k) const noexcept
constexpr bool operator==(const AdjKind &o) const
Equality comparison (for use in hash maps).
constexpr AdjKind()=default
constexpr AdjKind(EntityKind from_, EntityKind to_)
Direct adjacency: from != to. via is ignored.
constexpr AdjKind(EntityKind from_, EntityKind to_, EntityKind via_)
Intra-level adjacency: from == to, with explicit intermediary.
constexpr bool isIntraLevel() const
Whether this is an intra-level (composed) adjacency.
constexpr bool operator!=(const AdjKind &o) const
constexpr bool isDirect() const
Whether this is a direct (inter-level) adjacency.
Flattened wrapper: inherits from TPair and adds AdjIndexInfo.
int maxLevel
Maximum BFS depth across all nodes.
int totalNodes
Total number of nodes (for flat array sizing).
std::string dump() const
Pretty-print the tree (for diagnostics).
std::vector< AdjKind > checkAvailable(const MeshConnectivity &dag) const
static CompiledGhostTree compile(const GhostSpec &spec)
std::vector< std::vector< LevelEntry > > levels
std::vector< GhostTreeNode > roots
std::unordered_set< EntityKind > collectedKinds() const
Collect all EntityKind values that appear at COLLECT nodes.
std::unordered_set< AdjKind, AdjKindHash > requiredAdjs() const
Collect all distinct AdjKind values used by any hop in the tree.
TPair & as()
Typed access: as<tAdj2Pair>() etc.
tAdjPair & asAdj()
Access as variable-width tAdjPair. Throws if adj holds a fixed-width type.
const tAdjPair & asAdj() const
bool initialized() const
Check if the adjacency pair is initialized (father is non-null).
tAdj2Pair & asAdj2()
Access as fixed-width tAdj2Pair (e.g., for cell2face with 2 entries).
int toDepth
Target stratum (e.g., 0 for nodes, dim-1 for faces)
int fromDepth
Source stratum (e.g., dim for cells, dim-1 for faces)
index fatherSize() const
Number of local (father) rows.
tPbiPair pbi
Periodic bits per entry (only for toDepth==0, optional)
const tAdj2Pair & asAdj2() const
const tAdj1Pair & asAdj1() const
ssp< AdjVariant > adj
Shared adjacency pair (typed by row width)
bool hasPbi() const
Check if pbi is attached (only valid for toDepth==0).
EntityKind target
Entity kind to ghost (must == hops.back().to).
EntityKind anchor
Owned entities to start from.
std::vector< AdjKind > hops
Sequence of adjacency lookups.
bool hasGhosts(EntityKind kind) const
std::unordered_map< EntityKind, std::vector< index > > ghostIndices
Per EntityKind: sorted, deduplicated global indices to ghost.
std::unordered_set< EntityKind > activeKinds
index totalGhosts() const
Total number of ghost entities on THIS rank.
static GhostSpec defaultPrimary()
std::vector< GhostChain > chains
One node in the compiled ghost tree.
int level
BFS depth (root = 0).
int parentId
Parent node ID (-1 for roots).
EntityKind kind
Entity kind at this node.
std::vector< GhostTreeNode > children
bool collect
If true, non-owned entities here become ghosts.
ArrayAdjacencyPair< e2n_rs > entity2node
entity → nodes. Father = owned, son = ghost.
ArrayAdjacencyPair< p2e_rs > parent2entity
tElemInfoArrayPair entityElemInfo
Per-entity element info. Father = owned, son = ghost.
index nOwnedEntities
Number of owned entities (father size).
ArrayAdjacencyPair< e2p_rs > entity2parent
tElemInfoArrayPair entityElemInfo
Per-B elem info. Father-only (owned B).
ArrayAdjacencyPair< e2p_rs > entity2parent
tPbiPair parent2entityPbi
index nOwnedEntities
Number of owned B entities (father size).
ArrayAdjacencyPair< e2p_rs > entity2parent
ArrayAdjacencyPair< p2e_rs > parent2entity
parent → entities. Father-only. Slot j = sub-entity j.
ArrayAdjacencyPair< e2n_rs > entity2node
entity → nodes. Father-only. First-parent extraction order.
index nEntities
Total number of unique entities created.
std::vector< std::vector< NodePeriodicBits > > parent2entityPbi
std::vector< ElemInfo > entityElemInfo
Per-entity element info (zone=0, type from SubEntityDesc::typeTag).
int nodeId
ID of the tree node.
bool collect
Whether to collect at this node.
EntityKind kind
Entity kind of this node.
int parentId
ID of the parent node (-1 for roots).
bool hasChildren
Whether this node has children (needs pull).
AdjKind hop
Hop used to reach this node.
ConeAdj & addCone(int fromDepth, int toDepth)
ssp< AdjVariant > resolveAdj(AdjKind kind) const
void registerAdj(AdjKind kind, const AdjPairTracked< TPair > &pair)
Const overload for AdjPairTracked<TPair>.
std::unordered_map< EntityKind, ssp< GlobalOffsetsMapping > > globalMappings
std::vector< SupportAdj > supports
ConeAdj * findCone(int fromDepth, int toDepth)
Find a cone by (fromDepth, toDepth). Returns nullptr if not found.
static tAdjPair Inverse(const ArrayAdjacencyPair< cone_rs > &cone, index nToLocal, const MPIInfo &mpi, const std::function< index(index)> &fromLocal2Global, const std::function< index(index)> &toLocal2Global, const ssp< GlobalOffsetsMapping > &toGlobalMapping)
std::vector< ConeAdj > cones
static InterpolateResult Interpolate(const ArrayAdjacencyPair< p2n_rs > &parent2node, const SubEntityQuery &query, index nParent, index nNode, const MPIInfo &mpi)
std::unordered_map< AdjKind, ssp< AdjVariant >, AdjKindHash > adjRegistry
bool hasSupport(int fromDepth, int toDepth) const
void registerAdj(AdjKind kind, AdjPairTracked< TPair > &pair)
Overload for AdjPairTracked<TPair>: unwrap to base TPair.
static ArrayAdjacencyPair< out_rs > Compose(const ArrayAdjacencyPair< rs_AB > &AB, const ArrayAdjacencyPair< rs_BC > &BC, index nALocal, const std::unordered_map< index, index > &bGlobal2Local, const std::function< index(index)> &aLocal2Global, bool removeSelf=false)
SupportAdj & addSupport(int fromDepth, int toDepth)
static ArrayAdjacencyPair< out_rs > ComposeFiltered(const ArrayAdjacencyPair< rs_AB > &AB, const ArrayAdjacencyPair< rs_BC > &BC, index nALocal, const std::unordered_map< index, index > &bGlobal2Local, const std::function< index(index)> &aLocal2Global, Predicate &&pred, const std::function< bool(index aLocal, index cGlobal, const std::vector< index > &sharedBGlobals)> &matchExtra=nullptr)
const ssp< GlobalOffsetsMapping > & getGlobalMapping(EntityKind kind) const
GhostResult evaluateGhostTree(const CompiledGhostTree &tree, const MPIInfo &mpi) const
void registerAdj(AdjKind kind, const TPair &pair)
bool hasCone(int fromDepth, int toDepth) const
bool hasAdj(AdjKind kind) const
Check whether an AdjKind is registered.
void registerGlobalMapping(EntityKind kind, const ssp< GlobalOffsetsMapping > &gm)
Register a GlobalOffsetsMapping for an EntityKind.
static InterpolateGlobalResultT< e2p_rs > InterpolateGlobal(const ArrayAdjacencyPair< p2n_rs > &parent2node, const tPbiPair &parent2nodePbi, const OffsetAscendIndexMapping &parentGhostMapping, const GlobalOffsetsMapping &parentGlobalMapping, const OffsetAscendIndexMapping &nodeGhostMapping, const SubEntityQueryPbi &query, index nLocalParents, index nTotalParents, index nNode, const OwnershipResolverMulti &resolver, const MPIInfo &mpi)
static InterpolateDistributedResult InterpolateDistributed(const ArrayAdjacencyPair< p2n_rs > &parent2node, const OffsetAscendIndexMapping &parentGhostMapping, const SubEntityQuery &query, index nLocalParents, index nTotalParents, index nNode, const OwnershipResolver2 &resolver, const OffsetAscendIndexMapping &nodeGhostMapping, const MPIInfo &mpi)
SupportAdj * findSupport(int fromDepth, int toDepth)
Find a support by (fromDepth, toDepth). Returns nullptr if not found.
void registerAdj(AdjKind kind, TPair &pair)
void registerAdj(AdjKind kind, ssp< AdjVariant > adjPtr)
std::vector< MPI_int > peerRanks
bool operator()(index a, index c, int nShared) const
int nNodes
Total number of nodes (vertices + mid-edge + ...).
int nVertices
Number of corner vertices (used for deduplication).
std::function< void(index iParent, int iSub, const std::function< NodePeriodicBits(int)> &parentPbi, NodePeriodicBits *out)> extractPbi
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.
std::function< bool(index iParent, int iSub, index iCandEntity, index candidateParent, int candidateSub)> matchExtra
TPair & as()
Typed access: as<tAdj2Pair>() etc.
const tAdj2Pair & asAdj2() const
int toDepth
Target stratum (e.g., dim for cells)
const tAdjPair & asAdj() const
int fromDepth
Source stratum (e.g., 0 for nodes)
tAdjPair & asAdj()
Access as variable-width tAdjPair.
const tAdj1Pair & asAdj1() const
ssp< AdjVariant > adj
Shared adjacency pair (typed by row width)
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Tag type for naming objects created via make_ssp.
Eigen::Matrix< real, 5, 1 > v
OwnershipResolverMulti resolver
const tPoint const tPoint const tPoint & p