novaphy.solvers.SolverBase¶
Newton-aligned base class for every NovaPhy SolverBase subclass. Defines
the canonical 5-argument forward-dynamics contract plus notification and
introspection hooks.
class SolverBase:
def __init__(self, model: Model): ...
def step(self, state_in: SimState, state_out: SimState,
control: Control | None, contacts: Contacts | None,
dt: float) -> None: ...
def notify_model_changed(self, flags: SolverNotifyFlags) -> None: ...
def joint_support(self) -> JointSupportMatrix: ...
def backend_info(self) -> SolverBackendInfo: ...
Construction¶
The model argument is mandatory and positional. There is no
settings= kwarg — solver-specific configuration objects (PBFConfig,
IPCConfig, …) are passed where they apply, and shared settings are tuned
post-construction via solver.settings.
Step Contract¶
| Argument | Description |
|---|---|
state_in |
Input SimState. May alias state_out for in-place stepping. |
state_out |
Output SimState. After return, holds the integrated state. |
control |
Control (or None to use the defaults baked into Model). |
contacts |
Contacts aggregate produced by CollisionPipeline.collide or Model.collide. Passing None runs without contact constraints. |
dt |
Time step in seconds. Some backends (e.g. SolverIPC) require a fixed dt matching their config. |
Collision detection is explicit. Populate contacts before stepping when the solver should enforce rigid / soft-point contacts:
pipeline = novaphy.CollisionPipeline(model, broad_phase="sap")
contacts = pipeline.contacts()
pipeline.collide(state, contacts)
solver.step(state, state, control, contacts, dt)
Aliasing state_in and state_out lets the same buffer be advanced
in-place. Pass distinct buffers when the input must be preserved:
state_a = model.state()
state_b = model.state()
pipeline = novaphy.CollisionPipeline(model)
contacts = pipeline.contacts()
for _ in range(steps):
pipeline.collide(state_a, contacts)
solver.step(state_a, state_b, control, contacts, dt)
state_a, state_b = state_b, state_a
Other Methods¶
| Method | Purpose |
|---|---|
notify_model_changed(flags) |
Invalidate cached data after mutating Model properties (gravity, drives, filters). Pass an SolverNotifyFlags bitmask. |
joint_support() |
Returns a JointSupportMatrix describing which joint types and joint properties this solver actually enforces. |
backend_info() |
Returns a SolverBackendInfo describing device, fixed-dt requirement, and state ownership. |
Properties¶
| Property | Description |
|---|---|
model |
The constructor-bound Model. Read-only Newton-aligned attribute. |
settings |
Mutable per-solver settings struct exposed for post-construction tuning. |
Multi-instance / Multi-Env Sharding¶
Solvers carry no per-instance state of their own; model.state() returns a
fresh buffer per call. Multi-env rollouts are therefore N independent
(SimState, SolverBase) pairs constructed from the same Model:
solver_per_env = [novaphy.solvers.SolverSemiImplicit(model) for _ in range(n_envs)]
state_per_env = [model.state() for _ in range(n_envs)]
ctrl_per_env = [model.control() for _ in range(n_envs)]
pipe_per_env = [novaphy.CollisionPipeline(model, broad_phase="sap") for _ in range(n_envs)]
cont_per_env = [pipe.contacts() for pipe in pipe_per_env]
for solver, s, c, pipe, k in zip(solver_per_env, state_per_env,
ctrl_per_env, pipe_per_env, cont_per_env):
pipe.collide(s, k)
solver.step(s, s, c, k, dt)
Subclasses¶
See novaphy.solvers for the full list of solver classes. NovaPhy currently ships:
SolverSemiImplicit, SolverFeatherstone, SolverXPBD, SolverPBF,
SolverSPH, SolverIPC (real implementations) plus SolverMPM,
SolverLBM (scaffolds).