Free-body Sequential Impulse (PGS) solver with semi-implicit Euler
integration. Default rigid-body backend in NovaPhy. Suitable for real-time
simulation of free-floating bodies under contacts and friction; for
articulated systems use SolverFeatherstone
instead.
Pipeline
graph LR
A[CollisionPipeline<br/>explicit / SAP / NXN] --> B[Narrowphase<br/>analytic / contact core]
B --> C[Sequential Impulse<br/>PGS iterations]
C --> D[Semi-implicit Euler<br/>integrate]
Features:
- Explicit, SAP, or NXN broadphase through
CollisionPipeline.
- Specialized narrowphase pairs (sphere-sphere / sphere-plane / sphere-box /
box-plane / box-box, cylinders, convex hulls, and triangle meshes where
supported by the collision pipeline).
- Warm-started accumulated impulses across frames.
- Coulomb friction with
|tangent_impulse| ≤ μ * normal_impulse.
- Baumgarte stabilization for penetration correction.
- Optional body sleeping for static islands (toggle via
settings.sleep_enabled).
Constructor
novaphy.solvers.SolverSemiImplicit(model, config=None)
| Parameter |
Description |
model |
Required. Immutable Model from ModelBuilder.finalize(). |
config |
Optional SolverSettings, also exposed as SolverSemiImplicit.Config. |
Post-Construction Tuning
Pass a configuration object at construction or mutate solver.settings:
solver.settings.<field> |
Type |
Description |
velocity_iterations |
int |
PGS velocity-iteration count (default 30). Higher = stiffer contacts, slower step. |
warm_starting |
bool |
Reuse previous-frame accumulated impulses for stability. |
sleep_enabled |
bool |
Allow bodies in static islands to sleep. |
sleep_energy_threshold |
float |
Kinetic-energy threshold for sleeping. |
sleep_time_required |
float |
Time below threshold before sleeping. |
sleep_ema_alpha |
float |
Energy EMA smoothing factor. |
baumgarte |
float |
Penetration error reduction parameter. |
slop |
float |
Penetration tolerance below which corrections are skipped. |
config = novaphy.solvers.SolverSemiImplicit.Config()
config.velocity_iterations = 40
config.sleep_enabled = True
solver = novaphy.solvers.SolverSemiImplicit(model, config)
Example
import numpy as np
import novaphy
builder = novaphy.ModelBuilder()
builder.add_ground_plane(y=0.0)
body = builder.add_body(
novaphy.Transform.from_translation(
np.array([0.0, 5.0, 0.0], dtype=np.float32)
)
)
builder.add_shape_box(
body,
xform=novaphy.Transform.identity(),
hx=0.5,
hy=0.5,
hz=0.5,
cfg=novaphy.ShapeConfig(density=1.0, mu=0.5),
)
model = builder.finalize()
solver = novaphy.solvers.SolverSemiImplicit(model)
state = model.state()
control = model.control()
pipeline = novaphy.CollisionPipeline(model)
contacts = pipeline.contacts()
for _ in range(600):
state.clear_forces()
pipeline.collide(state, contacts)
solver.step(state, state, control, contacts, 1.0 / 120.0)
When To Use
| Scenario |
Recommendation |
| Free-floating rigid body piles, stacks, projectiles |
Default choice. |
| Articulated robots / multibody systems |
Use SolverFeatherstone. |
| Position-level constraints with compliance |
Use SolverXPBD. |
| Guaranteed no penetration (tight tolerances) |
Use SolverIPC when CUDA available. |
Demos
| Demo |
What it shows |
python/demos/demo_pyramid_ball.py |
4-3-2-1 pyramid with sphere projectile. |
python/demos/demo_friction_ramp.py |
Boxes on a 30° ramp with varied friction coefficients. |
python/demos/demo_dominoes.py |
20-domino chain reaction (warm-starting helpful here). |
python/demos/demo_wall_break.py |
5×5 wall hit by sphere. |
See Also