Rigid bodies with NVIDIA Newton¶
pinneapple_simulation.external_solvers.newton_physics runs rigid-body scenes with
Newton (Apache-2.0, built on NVIDIA Warp). Newton runs on CPU or GPU and
offers several rigid-body solvers; PINNeAPPle wraps them behind one scene description, records the trajectory in
SI units and checks a solver setting against closed-form results before it is used in a study.
pip install newton # core: XPBD, semi-implicit, Featherstone
pip install "newton[examples]" # adds the viewer, mesh/URDF/USD importers and MuJoCo-Warp
Scene, run, result¶
from pinneapple_simulation.external_solvers.newton_physics import RigidScene, simulate
scene = RigidScene(gravity=9.81).ground(mu=0.4)
scene.box("crate", (0.1, 0.1, 0.1), pos=(0, 0, 0.1), vel=(2.0, 0, 0), mu=0.4) # half extents [m]
bob = scene.sphere("bob", 0.05, pos=(0.17, 0, 1.0))
scene.revolute(-1, bob, anchor=(0, 0, 2.0), axis=(0, 1, 0)) # hinge to the world
traj = simulate(scene, duration=2.0, dt=1e-3, solver="xpbd", record_every=10)
traj.pos, traj.quat, traj.vel, traj.omega # (T, N, 3|4), quaternions (w, x, y, z)
traj.energy()["total"] # kinetic + potential [J]
traj.to_upd() # PhysicalSample for datasets and surrogates
traj.to_rigid_body_state() # torch state for the differentiable rigid_body module
- Shapes:
sphere,box,capsule,cylinderandmesh(closed triangle mesh, e.g. from an STL). Mass comes fromdensity(default 1000 kg/m³) or is set exactly withmass=. - Joints:
revolute(hinge through an anchor about an axis, both given in world coordinates at t = 0) andfixed. Joints form trees; a body that is the parent of a joint but has no parent itself gets a free joint to the world. scene.check()lists problems (non-positive sizes, a body with two parents, invalid friction) before any solver is touched; the description imports without Newton installed.- Solvers:
"xpbd"(default),"semi_implicit","featherstone"and"mujoco"(needsnewton[sim]). Initial body velocities are set for the maximal-coordinate solvers (XPBD, semi-implicit).
Check the solver before trusting it¶
validate(solver) runs six scenes with a closed-form answer and reports simulated value, reference, error and
pass/fail. Results on CPU, dt = 1 ms (bounce 0.1 ms), Newton 1.6.1:
| check | reference | XPBD | Featherstone | semi-implicit |
|---|---|---|---|---|
| free fall, max error / drop height | z0 − g t²/2 | 0.20 % ✓ | 0.20 % ✓ | 0.20 % ✓ |
| box sliding with friction μ = 0.4 | stops at v0²/(2μg) = 0.510 m | 0.509 m, 0.20 % ✓ | – | 0.282 m, 45 % ✗ |
| pendulum period, 5° | 2π√(I/(mgL)) = 2.007 s | 2.010 s, 0.17 % ✓ | 2.008 s, 0.05 % ✓ | unstable ✗ |
| rebound with restitution e = 0.5 | e² h = 0.250 m | 0.250 m, 0.05 % ✓ | – | 0.068 m ✗ |
| torque-free spin, angular momentum drift | 0 | 0.30 % ✓ | – | 0.29 % ✓ |
| box resting on the ground for 2 s | no sinking, no drift | 2 µm ✓ | 8.2 mm ✗ | 8.2 mm ✗ |
What the table says:
- XPBD passes all six and is the default for contact-rich scenes. It is slightly dissipative: a 10° pendulum
loses about 2.6 % of its swing energy in 2 s at
dt = 1 ms. - Featherstone is the most accurate for joint chains (pendulum period within 0.05 %), but with its default penalty contact a 0.2 m box sinks 8 mm into the ground; use it for articulated mechanisms, not stacking or impacts.
- Semi-implicit uses penalty contacts and needs a much smaller step and tuned contact stiffness (
ke,kd) for friction, restitution and hinges; with the defaults at 1 ms it fails four checks, andvalidatesays so.
Checks marked "–" need initial body velocities, which are set only for the maximal-coordinate solvers.
Files¶
scene.py:RigidScene, shapes, joints, the Newton model builder.runner.py:simulate(),RigidTrajectory(energy, UPD export,.npzsave).validation.py: the six analytic checks andvalidate().- Tests:
tests/test_newton_rigid.py(scene checks run without Newton; the solver tests are skipped when it is not installed).