jaxdem.forces.cundall_strack#

Cundall-Strack linear spring-dashpot contact force model.

Functions

arithmetic_mean_friction(mu_i, mu_j)

Mix sliding-friction coefficients with their arithmetic mean.

geometric_mean_friction(mu_i, mu_j)

Mix sliding-friction coefficients with their geometric mean.

get_cundall_strack_contacts(state, system)

Collect resolved Cundall-Strack forces for all active directed contacts.

maximum_friction(mu_i, mu_j)

Mix sliding-friction coefficients with their maximum.

minimum_friction(mu_i, mu_j)

Mix sliding-friction coefficients with their minimum.

Classes

CundallStrackContactData(pair_ids, ...)

Directed active contacts resolved into Cundall-Strack components.

CundallStrackForce(laws, ...] =, ...)

History-dependent linear spring/dashpot friction with rolling resistance.

class jaxdem.forces.cundall_strack.CundallStrackContactData(pair_ids: jax.Array, normal_forces: jax.Array, tangential_forces: jax.Array, torques: jax.Array, friction_coefficients: jax.Array, mobilized: jax.Array)[source]#

Bases: NamedTuple

Directed active contacts resolved into Cundall-Strack components.

Variables:
  • pair_ids (jax.Array) – Sphere indices (i, j), shape (M, 2). Each row describes the contact force and torque on i from j. Reciprocal contacts are represented by separate rows.

  • tangential_forces (normal_forces,) – Normal and Coulomb-limited tangential force vectors, shape (M, dim).

  • torques (jax.Array) – Force-law torques about the center of sphere i, shape (M, 1 | 3). These include tangential contact torque and rolling resistance, but not a clump-member offset moment.

  • friction_coefficients (jax.Array) – Effective sliding-friction coefficient mu_ij selected by the configured mixing rule, shape (M,).

  • mobilized (jax.Array) – Whether the tangential trial force is on or beyond the Coulomb surface, shape (M,).

pair_ids: Array#

Alias for field number 0

normal_forces: Array#

Alias for field number 1

tangential_forces: Array#

Alias for field number 2

torques: Array#

Alias for field number 3

friction_coefficients: Array#

Alias for field number 4

mobilized: Array#

Alias for field number 5

as_contact_data(state: State, system: System) → ContactData[source]#

Return the matching generic contact snapshot without reevaluation.

The resolved normal and tangential components are combined into total pair forces. Torques are shifted from each source sphere’s center to its clump center of mass, matching ContactData. Pair displacements use the configured domain’s image convention.

state and system must describe the unchanged configuration from which this snapshot was collected. Contact history is not read or advanced.

jaxdem.forces.cundall_strack.minimum_friction(mu_i: Array, mu_j: Array) → Array[source]#

Mix sliding-friction coefficients with their minimum.

jaxdem.forces.cundall_strack.maximum_friction(mu_i: Array, mu_j: Array) → Array[source]#

Mix sliding-friction coefficients with their maximum.

jaxdem.forces.cundall_strack.arithmetic_mean_friction(mu_i: Array, mu_j: Array) → Array[source]#

Mix sliding-friction coefficients with their arithmetic mean.

jaxdem.forces.cundall_strack.geometric_mean_friction(mu_i: Array, mu_j: Array) → Array[source]#

Mix sliding-friction coefficients with their geometric mean.

class jaxdem.forces.cundall_strack.CundallStrackForce(laws: tuple[~jaxdem.forces.ForceModel, ...] = (), parameterization: ~typing.Literal['elastic', 'coefficients'] = 'elastic', friction_mixing: ~typing.Callable[[~jax.Array, ~jax.Array], ~jax.Array] = <function minimum_friction>, rolling_friction_mixing: ~typing.Callable[[~jax.Array, ~jax.Array], ~jax.Array] = <function minimum_friction>)#

Bases: ForceModel

History-dependent linear spring/dashpot friction with rolling resistance.

The tangential spring displacement is accumulated per contact, transported with the changing contact frame, and return-mapped at the Coulomb limit. parameterization="elastic" derives contact coefficients from young, poisson, and e. parameterization="coefficients" reads k_n, k_t, b_n, and b_t directly from the material table and combines particle values with a zero-safe harmonic mean. friction_mixing and rolling_friction_mixing select the pair sliding- and rolling-friction coefficients.

Computes the interaction between two spheres with a linear elastic assumption, viscous damping, and Coulomb friction.

Elastic Parameterization The elastic parameterization computes the effective mass \(m_{eff}\) and restitution coefficient \(e_{eff}\) as:

\[m_{eff} = \left( \frac{1}{m_i} + \frac{1}{m_j} \right)^{-1}, \quad e_{eff} = \min(e_i, e_j)\]

The model computes the shear modulus \(G\) per particle from Young’s modulus \(E\) and Poisson’s ratio \(\nu\):

\[G = \frac{E}{2(1 + \nu)}\]

The model treats the effective stiffnesses for the normal (\(k_n\)) and tangential (\(k_t\)) directions as springs in series:

\[k_n = \frac{2 E_i R_i E_j R_j}{E_i R_i + E_j R_j}, \quad k_t = \frac{2 G_i R_i G_j R_j}{G_i R_i + G_j R_j}\]

The viscous damping coefficient \(\beta\) and the directional damping coefficients are:

\[\beta = \frac{-\ln(e_{eff})}{\sqrt{\pi^2 + \ln^2(e_{eff})}}\]
\[\gamma_n = 2 \beta \sqrt{k_n m_{eff}}, \quad \gamma_t = 2 \beta \sqrt{k_t m_{eff}}\]

Forces The normal force \(F_n\) includes spring repulsion and viscous damping, limited to repulsive values:

\[F_n = \max(0, k_n \delta_n - \gamma_n v_n)\]

The tangential force combines the history spring and viscous dashpot and is capped by the Coulomb sliding friction limit:

\[\mathbf{F}_{t, trial} = -k_t\boldsymbol{\xi}_t-\gamma_t \mathbf{v}_t\]
\[\mathbf{F}_t = \min\!\left(1,\frac{\mu F_n}{\|\mathbf{F}_{t,trial}\|}\right) \mathbf{F}_{t,trial}\]

Rolling Friction The rolling friction torque resists the relative angular velocity at the contact:

\[\boldsymbol{\tau}_{\text{roll}} = -\mu_r \, R_{\text{eff}} \, F_n \, \hat{\omega}_{\text{rel}}\]

The configured rolling_friction_mixing callable determines \(\mu_r\); its default is \(\min(\mu_{r,i}, \mu_{r,j})\). The effective radius is \(R_{\text{eff}} = R_i R_j / (R_i + R_j)\), and \(\hat{\omega}_{\text{rel}}\) is the unit relative angular velocity.

References

parameterization: Literal['elastic', 'coefficients']#
friction_mixing: Callable[[Array, Array], Array]#
rolling_friction_mixing: Callable[[Array, Array], Array]#
property supports_analytical_energy_gradient: bool[source]#

Whether force is the negative analytical gradient of energy.

Translational components use body-center positions and rotational components use world angular increments. Force laws are assumed to satisfy this contract by default. Laws that do not must override this property with False; value-based minimizers then differentiate energy directly, with stored pair history held fixed.

history_shape(dim: int) → tuple[int, ...][source]#

Store tangential displacement and the previous contact normal.

search_radii(state: State, system: System) → jax.Array[source]#

Conservative search extent for this law’s finite interaction range.

static force(i: int, j: int, pos: jax.Array, state: State, system: System, history: jax.Array, *, advance_history: bool = True, quasistatic: bool = False) → tuple[jax.Array, jax.Array, jax.Array][source]#

Compute Cundall-Strack normal and tangential forces and torque.

Parameters:
  • i (int) – Particle indices.

  • j (int) – Particle indices.

  • pos (jax.Array) – Particle positions.

  • state (State) – Current simulation state.

  • system (System) – System configuration.

  • history (jax.Array) – Stored tangential spring and previous contact normal.

  • advance_history (bool, optional) – Advance the stored spring with this step’s relative motion.

  • quasistatic (bool, optional) – Evaluate with no time passing: the normal and tangential dashpots and rolling friction are switched off and the Coulomb cap uses the elastic normal force only.

Returns:

(force, torque, history) with dimension-agnostic shapes. When advance_history is false the returned history is exactly the input, while force uses its contact-frame-transported spring.

Return type:

tuple[jax.Array, jax.Array, jax.Array]

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

Return normal plus stored tangential spring energy.

The stored spring is transported to the current contact normal but not advanced or return-mapped. Dissipated work is not part of the energy.

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.

jaxdem.forces.cundall_strack.get_cundall_strack_contacts(state: State, system: System) → tuple[State, System, CundallStrackContactData][source]#

Collect resolved Cundall-Strack forces for all active directed contacts.

The configured collider supplies pair candidates and stored tangential history. Neighbor-list caches are rebuilt when necessary, but contact history is never advanced. The returned system retains any refreshed cache. Results are sorted by source and destination sphere index.

This is a host-side operation because it returns variable-length arrays.

Raises:
  • TypeError – The system does not use CundallStrackForce directly.

  • ValueError – Pair search results are incomplete or a reported value is nonfinite.