Skip to main content

Data types

The objects operators accept and return. Everything lives in src/warpSPHCore/dataTypes/ (the enums in src/warpSPHCore/enumTypes.py).

Precision and dimension are global, set once at import by the warpSPHCore_PRECISION / warpSPHCore_DIM environment variables (see Quickstart); scalar_t is the resolved Warp dtype, and every dimension-dependent struct exists once per dimension as …_1/…_2/…_3 variants.

Particle states​

ParticleState​

@dataclass
class ParticleState:
positions: torch.Tensor # [N, D]
supports: torch.Tensor # [N] per-particle smoothing length h_i
masses: torch.Tensor # [N]
kinds: torch.Tensor # [N] int32, REQUIRED
densities: Optional[torch.Tensor] = None # [N]
  • kinds is required, not optional. Every operator kernel indexes kinds[i] unconditionally (getParticleData); OperationDirection.AllToAll used to paper over a missing kinds tensor with an N-sized zero dummy — that path is gone. Pinned by tests/operations/test_particle_state_kinds.py.
  • Positions may be unwrapped in a periodic domain; the kernels apply the minimum-image distance from the DomainDescription themselves.
  • densities is optional so the Density operator can run without pre-computed densities; a None slot is filled with a shared null field in the flat layout.

ParticleTangentState​

@dataclass
class ParticleTangentState:
positions: torch.Tensor # [N, D]
supports: torch.Tensor # [N]
masses: torch.Tensor # [N]
densities: Optional[torch.Tensor] = None

The JVP tangent counterpart, minus kinds (categorical — no tangent). Supplied to warpOperationJVP as queryTangentState/referenceTangentState.

(There is also a legacy PointCloud(positions, supports) for callers that only carry geometry.)

Domain​

@dataclass(slots=True)
class DomainDescription:
min: torch.Tensor # [D]
max: torch.Tensor # [D]
periodic: torch.Tensor # [D] bool
dim: int

The Warp-side mirror is domainData (domainMin, domainMax, periodicity: wp.array(wp.bool), dim: wp.int32).

OperationProperties​

A frozen dataclass — the operator configuration, hashable and safe to share across calls:

fielddefaultmeaning
kernel: KernelFunctions— (required)which kernel
operation: WarpOperationInterpolatewhich operator
gradientMode: GradientSchemeNaivethe Gradient scheme (and the Laplacian's qijq_{ij})
laplacianMode: LaplacianSchemeBrookshawthe Laplacian scheme
positiveDivergence: boolFalsethe Laplacian's +max⁡(G⋅n,0)+\max(\mathbf{G}\cdot\mathbf{n}, 0) term
supportMode: SupportSchemeGatherthe pairwise support scheme
operationMode: OperationDirectionAllToAllwhich kinds participate (see OperationDirection)
divergenceDotMode: boolFalsethe Divergence dot-mode contraction
n_h: Optional[float]Nonenominal support-to-spacing ratio, for the lattice calibration
calibrateNormalization: boolFalseenable the 1/L1/L kernel scaling

__post_init__ raises unless n_h is positive whenever calibrateNormalization is set — deliberately loud, so "calibration requested, never computed" can never be silently confused with "calibration off".

Neighbor-search structures​

AdjacencyList​

@dataclass(slots=True)
class AdjacencyList:
i: torch.Tensor # int64, COO row (query) indices
j: torch.Tensor # int64, COO column (reference) indices
numNeighbors: torch.Tensor # int32, per query particle
edgeOffsets: torch.Tensor # int32, CSR offsets
numRows: int; numCols: int
# Verlet-list bookkeeping (the positions the list was BUILT from,
# not the current ones):
queryPositions: torch.Tensor = None
referencePositions: torch.Tensor = None
querySupports: torch.Tensor = None
referenceSupports: torch.Tensor = None
hashMap: CompactHashMap = None

COO and CSR at once (neighbors are sorted by query particle, so it cannot serve as CSC; i is redundant with edgeOffsets + numNeighbors but kept to avoid reconstructing it). int64 is required: torch does not index with int32 tensors. See Neighbor search.

CompactHashMap​

@dataclass
class CompactHashMap:
sortedPositions: torch.Tensor # reference particles in Z-order
sortedSupports: torch.Tensor
sortIndex: torch.Tensor # original -> sorted permutation
hashTable: torch.Tensor # [hashMapLength, 2] (start, count); empty = (-1, 0)
sortedCellTable: torch.Tensor # occupied cells sorted by hash: [cellIndex, start, count]
qMin: torch.Tensor; qMax: torch.Tensor
hCell: float # cell size (>= global support)
numCells: torch.Tensor
mode_uint: int # the support scheme, as its uint
D: int
searchRadius: int # stencil radius in cells
numOffsets: int
cellOffsets: torch.Tensor # [numOffsets, 3] stencil offsets

Built by buildCompactHashMap; usable both as the input to a neighbor collection (into an AdjacencyList) and directly as an operator's adjacency= for grid traversal.

Correction states​

statefieldsproduced byconsumed by
CRKStateA [N], B [N,D], gradA [N,D], gradB [N,D,D]computeCRKFactorsGradient/Divergence/Curl/Laplacian (Brookshaw/Dot/Default only)
CRKTangentStatesame four, no Optional fieldscomputeCRKFactorsJVPwarpOperationJVP (the JVP bridge substitutes primal-shaped zeros for any of the four that has no live tangent of its own)
GradHStatequeryOmegas [N], referenceOmegas [N] (optional — defaults to the query's)callerthe gradient-h terms of Gradient/Divergence/Curl/Laplacian; no JVP wiring — warpOperationJVP rejects gradHState outright
RenormalizationStaterenormalizationMatrices [N,D,D]computeRenormalizationMatricesGradient (and the other corrected ops)
RenormalizationTangentStaterenormalizationMatrices [N,D,D]computeRenormalizationMatricesJVPwarpOperationJVP

The Warp-side mirror is correctionData_{dim} — a canonical, unconditionally-present struct with a useVolume/useGradHTerms/ useGradientRenormalization/useCRK boolean per section (the booleans are what guard against Warp's zero-initialization of the array fields), plus a field-for-field correctionTangentData_{dim} tangent mirror (deliberately a separate struct: adding tangent fields to the primal struct would grow every non-JVP kernel's ABI for no reason). Per-query-particle forms are ParticleCorrectionData_{dim} / ParticleCorrectionTangentData_{dim}.

Kernel configuration​

@wp.struct
class kernelState:
kernelFunction: wp.int32 # KernelFunctions value
supportMode: wp.uint32 # SupportScheme value (11..16)
gradientMode: wp.int32
laplacianMode: wp.int32
positiveDivergenceMode: wp.bool
divergenceMode: wp.bool # the Divergence dot-mode
operationMode: wp.int32 # OperationDirection value
calibrateNormalization: wp.bool # guards the coefficient below
normalizationCoefficient: scalar_t # 1 / L, see lattice calibration

The boolean flag exists so the pair is safe under Warp's zero-initialization of struct fields: several call sites build kernelState() and set only the fields they know about — a bare coefficient would default to 0.0 and silently zero the kernel. False is "off"; the coefficient is read only when the flag is set, and the host raises on flag set + coefficient ≤ 0.

The other per-dimension Warp structs: particleDataSoA_{dim} (positions/supports/masses/densities/kinds as wp.arrays), WarpParticle_{dim} (the SoA struct's AoS per-particle form), domainData, adjacencyData (neighborList int64, neighborOffsets/numNeighbors int32), gridData (the CompactHashMap's arrays + D/numOffsets scalars).

The Field abstraction​

util/fieldRegistry.py + dataTypes/field_t.py: a cached dual torch/Warp view of a tensor's storage, the identity layer the caching machinery is built on.

  • Two ownership modes. Attached fields (caller-owned tensors) live on the tensor as t._wsc_field (via acquireView); the Field holds no strong reference back, so the tensor dies by refcount alone — no cycle for the GC to break on its own schedule. Standalone fields (core-owned: null fields, adjacency) hold the tensor themselves, since the point is that the Field outlives any particular call.
  • Provenance check. Field.matches(t) re-validates data_ptr/shape/strides/dtype before a cached view is reused — catching resize_, .data reassignment, and storage swaps.
  • Copy/pickle safety. a Field wraps a wp.array with a live device pointer; __copy__/__deepcopy__/__reduce__ all degrade to None, so a copied or pickled tensor arrives with a missing field and acquireView treats it as a miss and rebuilds cleanly — no cross-process device pointers.
  • Role has a single member (PRIMAL): forward-mode AD landed via StateAwareWarpFunction.jvp()'s flat-tensor tangents, not via a second field role. FieldKind (SCALAR/VECTOR/MATRIX/INT32/INT64/ VEC2I/VEC3I/VEC3L/BOOL) keys the null-field registry — the permanent placeholders the flat layout fills disabled correction slots with.

ExecutionMode (NONE / REVERSE / FORWARD / AUTO) is the execution mode carried on an execution context and folded into the StateBundle cache key: FORWARD is declared and deliberately unimplemented (rejected at the boundary), and AUTO is a caller-facing default that resolves to the same struct rows as NONE/REVERSE — it is a placeholder, not a fourth variant.

Enums​

enumTypes.py. Integer values are part of the ABI (they cross into wp.int32 fields and the mode_uint of the hash map).

SupportScheme​

membervalueeffective support
Gather11hih_i
Scatter12hjh_j
MeanSymmetric13(hi+hj)/2(h_i + h_j)/2
KernelMeanSymmetric1412(k(q,hi)+k(q,hj))\tfrac12(k(q, h_i) + k(q, h_j))
SuperSymmetric1512(k(q,hi)+k(q,hj))\tfrac12(k(q, h_i) + k(q, h_j)) — identical value to KernelMeanSymmetric, the CRK-SPH formulation (gradient differs)
PartialSymmetric16fif_i-weighted hih_i + fjf_j-weighted hjh_j — the PESPH formulation

KernelFunctions​

membervaluemembervalue
Wendland20Poly620
Wendland41Spiky21
Wendland62CubicSpline30
QuarticSpline31QuinticSpline32
B734B833
HOCT435Gaussian36
ViscosityKernel40CohesionKernel41
AdhesionKernel42

(the formulas are on the Kernel library page)

GradientScheme / LaplacianScheme / WarpOperation​

GradientSchemevalueLaplacianSchemevalueWarpOperationvalue
Naive1Naive1Interpolate1
Symmetric2Brookshaw2Gradient2
Difference3Dot3Divergence3
Summation4Default4Curl4
Laplacian5
Density6
Covariance7
Custom8

OperationDirection​

membervaluemembervalue
TrueAllToToAll0AllToAll9
FluidToFluid1AllToGhost10
FluidToBoundary2AllToFluid11
BoundaryToFluid3AllToBoundary12
BoundaryToBoundary4FluidToAll13
FluidToGhost5BoundaryToAll14
GhostToFluid6
BoundaryToGhost7
GhostToBoundary8

with ParticleType: Fluid=0, Boundary=1, Ghost=2, Other=3 — the direction selects which kinds act as query vs. reference.

HashMapLengthMode​

Fixed (0 — a fixed table length, default 4096), NumberOfParticles (1 — made odd), NextPrime (2 — the default; the table is the next prime above the particle count).

ViscosityTerms​

Default=0, MonaghanGingold1983=1, Cleary1998=2, Monaghan1992=3, Monaghan1997a=4, Monaghan1997b=5, Dukowicz=6, Price2012_98=7, Price2012=8, Price2008=9, Wadsley2008=10, DeltaSPH=11 — viscosity-term selectors for the integrator layer; the core operators here do not branch on them.

See also​

API reference (every public function) · Autodiff machinery (the flat layout these objects flatten into) · warpier_fields.md (the state-object design record: ownership, caching, the declared ABI)