peclet-dem 1.1.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
solver_multilevel.hpp File Reference

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
 

Detailed Description

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.