phyz 0.4.0

Multi-physics differentiable simulation engine
Documentation

phyz

The differentiable rigid-body core of phyz.

phyz re-exports the focused phyz-* crates that make up the rigid-body stack, so cargo add phyz gets you all of them behind one dependency and phyz::collision is literally phyz_collision. The one thing it adds is sim — the time loop, which none of the focused crates own.

It does not cover the whole workspace — phyz-gpu, phyz-particle, phyz-lbm and friends are separate crates you add explicitly.

Features

collision, contact and diff are on by default; math, model and rigid are always present.

cargo add phyz                                  # everything below
cargo add phyz --no-default-features            # math + model + rigid only
cargo add phyz --no-default-features -F diff    # ...plus gradients

Modules

Module Contents
math phyz-math: Vec3, Mat3, Quat, SpatialVec, SpatialTransform, SpatialInertia
model phyz-model: Model, ModelBuilder, Body, Joint, JointType, Actuator, State
rigid phyz-rigid: aba, rnea, crba, forward_kinematics, body_wrenches
collision phyz-collision: gjk_distance, epa_penetration, ray_cast, sweep_and_prune, AABB
contact phyz-contact: find_contacts, find_ground_contacts, contact_forces, ContactMaterial
diff phyz-diff: adjoint_rollout_gradient, plus the per-step Jacobians
sim Simulator, Solver, SemiImplicitEulerSolver, Rk4Solver — this crate's only original code

Forward dynamics

use phyz::{Mat3, ModelBuilder, SpatialInertia, SpatialTransform, Vec3};
use phyz::rigid::aba;

let model = ModelBuilder::new()
    .gravity(Vec3::new(0.0, -9.81, 0.0))
    .dt(0.002)
    .add_revolute_body(
        "pendulum",
        -1,
        SpatialTransform::identity(),
        SpatialInertia::new(
            1.0,
            Vec3::new(0.0, -0.5, 0.0),
            Mat3::from_diagonal(&Vec3::new(0.083, 0.0, 0.083)),
        ),
    )
    .build();

let mut state = model.default_state();
state.q[0] = 0.3;

let qdd = aba(&model, &state);   // joint accelerations, O(n)
assert_eq!(qdd.len(), model.nv);

Gradients

diff::adjoint_rollout_gradient runs one forward rollout and one backward adjoint pass, returning:

  • d_inertia[i] — dJ/dπ for body i's ten spatial-inertia scalars [m, cx, cy, cz, Ixx, Iyy, Izz, Ixy, Ixz, Iyz]
  • d_vertices[i] — ∂J/∂x per collision-mesh vertex, when ground contact is configured

Both are exact: the per-step Jacobians come from dual numbers through a scalar-generic ABA, not finite differences. See the repository README for a worked example.

For per-step Jacobians with respect to (q, v, ctrl), use phyz-diff instead.

Naming

Each sub-crate is reachable under both names: phyz::rigid::aba and phyz::phyz_rigid::aba are the same function, and both are phyz_rigid::aba. Types cross crate boundaries freely because there is only ever one of them.

Part of phyz

phyz is an open-source differentiable multi-physics simulation workspace in pure Rust. Each crate is independent — adding this one does not pull in the rest.

Licensed under MIT.