|
peclet-dem 1.1.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
|
dem — multilevel (GraphMG-style) momentum-conserving contact stabilization. More...
#include <Kokkos_Core.hpp>#include <stdexcept>#include <utility>#include <vector>#include "contact_preprocessing.hpp"#include "solver_fused.hpp"#include "solver_velocity.hpp"Go to the source code of this file.
Classes | |
| struct | peclet::dem::ContactHierarchy |
| Host-side description of one built hierarchy (offsets into the packed group pools). More... | |
| struct | peclet::dem::MlScratch |
| Device scratch for the multilevel pass, sized once (see Particles::allocate). More... | |
| struct | peclet::dem::MlBodyViews |
| The per-body inputs of the rigid coarse space (§2.3-§2.5): the predicted positions (the member offsets d_q), the predicted angular velocities (restricted and prolonged), the orientations of the fine PGS and the coarse vertices' inverse inertia invIc = invInertia k / max(1, a). More... | |
| struct | peclet::dem::mldetail::D3 |
| Double-precision copy of dem_portable's rotateVector (the same formula), for the build. More... | |
| struct | peclet::dem::MlCoarseSweep |
| The per-manifold coarse-PGS body (e = 0, shared fine accumulator) lives in MlCoarseSweep so the per-colour launch loop and the fused whole-cycle kernel share it verbatim. More... | |
| struct | peclet::dem::MlCoarseSweep::Row |
| One coarse row, evaluated up to its effective mass (the part solveOne shares with the oracle test's singleton check). More... | |
| struct | peclet::dem::MlFusedMeta |
| Host-POD description of a built hierarchy for the fused coarse-cycle kernel (fixed-size arrays: kernel argument by value). More... | |
| struct | peclet::dem::MlFusedCtx |
| Fused-coarse-cycle context: flat per-level colour offsets on device + barrier + meta. More... | |
Namespaces | |
| namespace | peclet |
| namespace | peclet::dem |
| namespace | peclet::dem::mldetail |
Functions | |
| float | peclet::dem::mldetail::effMass (float invMass) |
| Effective mass with fixed bodies (invMass == 0) mapped to a huge-but-finite mass so the momentum-weighted restriction stays finite and the group's inverse mass underflows to ~0. | |
| bool | peclet::dem::mldetail::eligible (const ManifoldC &m, int idx, Kokkos::View< const int *, CpMem > mColor, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *[3], CpMem > vt0, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, float qsThr, int gateMask) |
| Coarse-eligibility of a manifold: active + base-coloured (non-dup) + quasi-static approach (|vn0| <= qsThr: a ballistic pair is never aggregated, so an impactor keeps its fine-level momentum-conserving physics), plus the gates selected in gateMask. | |
| bool | peclet::dem::mldetail::canonical (const Kokkos::View< const float *[3], CpMem > &posPred, const Kokkos::View< const int *, CpMem > &realIdx, int slot) |
| A slot sits at its canonical body's position, bitwise (false for a periodic image). | |
| template<class VX > | |
| F3 | peclet::dem::mldetail::memberOffset (const VX &posPred, int i, const Kokkos::View< const float *[3], CpMem > &originG, const Kokkos::View< const float *[3], CpMem > &comOffG, int gi) |
| Member offset from its group's centre of mass, d_q = fl(fl(x_q - O_g) - c_g) (§2.3 step 2): recomputed wherever it is used, never stored, so the build, the restriction, the coarse rows and the prolongation all see the same float value. | |
| F3 | peclet::dem::mldetail::spinInertiaTimes (F4 q, F3 invIc, F3 w) |
| J_q w: the member's world-frame spin inertia R diag(1 / max(invIc, 1e-30)) R^T applied to w (§2.3 step 3). | |
| template<class V6 > | |
| F3 | peclet::dem::mldetail::symMul (const V6 &S, int g, F3 v) |
| Symmetric 3x3 (xx, yy, zz, xy, xz, yz) times v. | |
| D3 | peclet::dem::mldetail::crossD (D3 a, D3 b) |
| D3 | peclet::dem::mldetail::rotateD (double qx, double qy, double qz, double qw, D3 v) |
| int | peclet::dem::buildMlLevelGeometryKokkos (const MlScratch &S, int off, int ng, int numReal, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > invIc) |
| The per-level geometry of the rigid coarse space (docs/contact_physics_followups.md §2.3), over the composed body -> group map S.grp of the level just built (groups [off, off + ng)): | |
| ContactHierarchy | peclet::dem::buildContactHierarchyKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > mColor, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *[3], CpMem > vt0, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, Kokkos::View< const float *, CpMem > invMass, float qsThr, int gateMask, int numReal, MlScratch &S, Kokkos::View< long long *, CpMem > winner, Kokkos::View< std::uint64_t *, CpMem > colorMask, bool excludeImmovable=false, Kokkos::View< const unsigned char *, CpMem > asleep={}, const MlBodyViews &body={}) |
| Build the aggregation hierarchy + per-level crossing-manifold colorings. | |
| void | peclet::dem::buildCoarseBucketsKokkos (const ContactHierarchy &H, MlScratch &S, int numManifolds, Kokkos::View< int *, CpMem > colorScratch, Kokkos::View< int *, CpMem > perm, Kokkos::View< int *, CpMem > cursor, std::vector< std::vector< int > > &offs) |
| One multilevel stabilization cycle over an already-built hierarchy: fine colored smoothing is the caller's business; this runs the coarse leg (fine -> coarse), updating velPred in place. | |
| MlCoarseSweep | peclet::dem::makeMlCoarseSweep (Kokkos::View< const ManifoldC *, CpMem > manifolds, Kokkos::View< const int *, CpMem > realIdx, const MlScratch &S, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< const float *, CpMem > restRel, const MlBodyViews &body) |
| The coarse sweep over the multilevel scratch + the body views (the rigid views stay empty when the lazy pools are). | |
| MlFusedCtx | peclet::dem::demMakeMlFusedCtx (CpExec &space, const ContactHierarchy &H, const std::vector< std::vector< int > > &bkOffs, int numManifolds, int numReal, int coarseSweeps, Kokkos::View< int *, CpMem > offsDev, Kokkos::View< unsigned *, CpMem > bar) |
| Build the fused-coarse-cycle context from an already-built hierarchy + its dense buckets: flatten the per-level colour offsets into the pooled device view (async upload) and record the grid-sizing work bound. | |
| void | peclet::dem::multilevelCoarseCycleKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< float, CpMem > maxApproach, int numReal, const ContactHierarchy &H, MlScratch &S, int coarseSweeps, const MlBodyViews &body, Kokkos::View< const float *, CpMem > restRel={}, const std::vector< std::vector< int > > *bkOffs=nullptr, Kokkos::View< const int *, CpMem > bkPerm={}, const MlFusedCtx *fused=nullptr) |
Variables | |
| constexpr int | peclet::dem::kMlMaxLevels = 10 |
| 6-bit colour slots per level in the packed word; slot value 63 = not crossing / not eligible at that level (skipped by the coarse sweeps). | |
| constexpr int | peclet::dem::kMlSlotSkip = 63 |
| constexpr long long | peclet::dem::kMlPendingSkipBit = 1ll << 62 |
| Transient mark of the coarse colouring (docs/contact_solve_framework.md §4.4, "the multilevel
coarse colouring"): an edge that won its groups but found no free colour keeps slot 63 and is skipped at this level. | |
| constexpr int | peclet::dem::mldetail::kGatePersistent = 1 |
| Optional eligibility gates beyond the quasi-static approach test (a SELECTION, not a sink – impulses stay symmetric; gating only decides which contacts join the coarse problem): kGatePersistent – contact must have existed last substep (a fresh contact is an event). | |
| constexpr int | peclet::dem::mldetail::kGateCone = 2 |
| constexpr int | peclet::dem::mldetail::kGateSlip = 4 |
dem — multilevel (GraphMG-style) momentum-conserving contact stabilization.
The principled replacement for the one-sided grounded pass: a collapsing column cannot be arrested by plain symmetric PGS (momentum moves ~one layer per sweep) and the one-sided pass arrests it by DELETING momentum (measured cost: it kills a ballistic impactor's rebound). The multilevel pass instead accelerates momentum TRANSPORT: greedy pairwise aggregation over the quasi-static contact graph builds super-bodies (rigid 6-DOF aggregates: summed mass and inertia, the fine state's projection onto rigid motions), and the fine manifolds crossing aggregate boundaries are re-solved with the AGGREGATE masses and inertias – the coarse analogue of the held lower side is the genuinely huge inertia of the supported chain, so a wall contact drains a whole column's momentum in one coarse impulse while every impulse stays symmetric (exact momentum conservation; the floor/walls are the only sink).
Structure per trigger (residual above the resting threshold after the main sweeps): build: L levels of matching (ballistic pairs |vn0| > qsThr, walls and periodic images never merge; stop when matching stalls or the group count is small), per-level group masses, the rigid geometry (centre of mass, inertia, docs/contact_physics_followups.md §2.3), and a per-level graph coloring of the crossing manifolds (6 bits/level packed into one word per manifold; the coloring guarantees group-disjointness within a launch). cycle: per iteration, one fine colored-PGS smoothing sweep, then levels fine -> coarse: restrict (V_g = sum m v / sum m, Omega_g = invI_g sum [m d x v + J w] – the M-orthogonal projection onto rigid motions), a few colored coarse PGS sweeps (rigid rows with the contact-point arms, e = 0, lambda >= 0 on the SHARED fine accumulator so the force-network ledger stays consistent for warm start + the friction cone's Coulomb bound), prolongate (the rigid motion v_i += dV + dOmega x d_i, w_i += dOmega). Every coarse impulse is the fine manifold's own, so P and L are exact (§2.6).
The inequality constraint is respected on every level (Kornhuber-style truncation reduces to: only compressed/quasi-static contacts aggregate or restrict; lambda >= 0 projection is the same accumulator projection as the fine sweep). Friction stays fine-level only.
Definition in file solver_multilevel.hpp.