jaxdem.forces.spring#

Linear spring force model.

Classes

FacetFacetSpringForce([laws])

Linear spring contact between facets.

SphereFacetSpringForce([laws])

Linear spring contact between spheres and facets.

SpringForce([laws])

Linear spring-like interaction between particles.

class jaxdem.forces.spring.SpringForce(laws: tuple[ForceModel, ...] = ())#

Bases: ForceModel

Linear spring-like interaction between particles.

Notes

  • The model reads the ‘effective Young’s modulus’ (\(k_{eff,\; ij}\)) from the jaxdem.System.mat_table using the material IDs of the interacting particles.

  • The force is zero if \(i == j\).

  • The model computes distances and normals with the zero-safe double-where helpers in jaxdem.utils.linalg. The force and its gradients stay finite when particles are perfectly co-located.

The penetration \(\delta\) (overlap) between two particles \(i\) and \(j\) is:

\[\delta = \max\left(0, (R_i + R_j) - r\right)\]

where \(R_i\) and \(R_j\) are the radii of particles \(i\) and \(j\) respectively, and \(r = ||r_{ij}||\) is the distance between their centers.

The force \(F_{ij}\) acting on particle \(i\) due to particle \(j\) is:

\[F_{ij} = k_{eff,\; ij}\, \delta\, \hat{n}_{ij}\]

where \(\hat{n}_{ij} = \vec{r}_{ij} / r\) is the unit vector from particle \(j\) to particle \(i\).

The potential energy \(E_{ij}\) of the interaction is:

\[E_{ij} = \frac{1}{2} k_{eff,\; ij} \delta^2\]

where \(k_{eff,\; ij}\) is the effective Young’s modulus for the particle pair.

static force(i: int, j: int, pos: jax.Array, state: State, system: System) tuple[jax.Array, jax.Array][source]#

Compute the linear spring force on particle \(i\) from particle \(j\).

Returns zero when \(i = j\).

Parameters:
  • i (int) – Index of the first particle.

  • j (int) – Index of the second particle.

  • pos (jax.Array) – Particle positions.

  • state (State) – Current state of the simulation.

  • system (System) – Simulation system configuration.

Returns:

(force, torque) with shapes (dim,) and (ang_dim,). The torque is always zero for this model.

Return type:

tuple[jax.Array, jax.Array]

static energy(i: int, j: int, pos: jax.Array, state: State, system: System) jax.Array[source]#

Compute the linear spring potential energy between particle \(i\) and particle \(j\).

Returns zero when \(i = j\).

Parameters:
  • i (int) – Index of the first particle.

  • j (int) – Index of the second particle.

  • pos (jax.Array) – Particle positions.

  • state (State) – Current state of the simulation.

  • system (System) – Simulation system configuration.

Returns:

Scalar potential energy of the interaction between particles \(i\) and \(j\).

Return type:

jax.Array

property required_material_properties: tuple[str, ...][source]#

Names of the material properties this force model needs.

Each name (for example ‘young_eff’ or ‘restitution’) must be present in System.mat_table. Used for validation.

class jaxdem.forces.spring.SphereFacetSpringForce(laws: tuple[ForceModel, ...] = ())#

Bases: ForceModel

Linear spring contact between spheres and facets.

Warning

The model detects facet contacts through the facet’s vertex spheres, in particular the facet’s primary vertex. The collider’s neighbor cutoff must cover the facet circumradius (the largest vertex-to-contact-point distance) plus the contact thickness (state.rad). If the primary vertex lies outside the cutoff while the contact point is in range, the model misses the contact or applies it asymmetrically. Cell-list based colliders must use cutoff >= max facet circumradius + thickness.

The contact thickness comes from the facet vertices’ state.rad (set through State.add_facet(thickness=...)). The force model itself has no thickness parameter.

static force(i: int, j: int, pos: jax.Array, state: State, system: System) tuple[jax.Array, jax.Array][source]#
static energy(i: int, j: int, pos: jax.Array, state: State, system: System) jax.Array[source]#
class jaxdem.forces.spring.FacetFacetSpringForce(laws: tuple[ForceModel, ...] = ())#

Bases: ForceModel

Linear spring contact between facets.

Warning

The model detects facet contacts through the facets’ vertex spheres, in particular each facet’s primary vertex. The collider’s neighbor cutoff must cover the facet circumradius (the largest vertex-to-contact-point distance) plus the contact thickness (state.rad). If a primary vertex lies outside the cutoff while the contact point is in range, the model misses the contact or applies it asymmetrically. Cell-list based colliders must use cutoff >= max facet circumradius + thickness.

The contact thickness comes from the facet vertices’ state.rad (set through State.add_facet(thickness=...)). The force model itself has no thickness parameter.

static force(i: int, j: int, pos: jax.Array, state: State, system: System) tuple[jax.Array, jax.Array][source]#
static energy(i: int, j: int, pos: jax.Array, state: State, system: System) jax.Array[source]#