Skip to content

novaphy.Model

Immutable simulation model produced by ModelBuilder.finalize(). A Model owns the baked scene topology — bodies, shapes, joints, articulations, particles — plus per-world gravity. The same Model can be shared across multiple solvers and rollout states.

import novaphy

model = builder.finalize()
state    = model.state()
control  = model.control()
pipeline = novaphy.CollisionPipeline(model)
contacts = pipeline.contacts()

Runtime Buffer Allocation

Method Purpose
state(requires_grad=None) -> SimState Allocate a fresh runtime state buffer.
control(requires_grad=None, clone_variables=True) -> Control Allocate a fresh control buffer.
contacts() -> Contacts Allocate an empty contacts aggregate. Use CollisionPipeline.contacts() for collision-sized buffers.

Collision Pipeline

Method Purpose
collide(state, contacts) -> None Run broadphase + narrowphase against state, populating a pre-sized contacts aggregate. Newton-aligned: collision lives outside the solver.

Solvers consume the contact buffers they are given; they do not run broadphase or narrowphase internally. Allocate contact storage with collision_pipeline.contacts() and call collision_pipeline.collide(state, contacts) before solver.step(...) when the step should enforce contacts. Passing contacts=None to a solver step runs that step without contact constraints.

Model Properties

Property Description
num_bodies Number of bodies.
num_shapes Number of collision shapes.
articulation_count / joint_count Newton-style flat articulation and joint counts.
bodies Per-body inertial properties.
shapes Collision shape definitions.
gravity Per-world gravity vectors ((num_worlds, 3) float32).

Mutating Per-World Gravity

Model is otherwise immutable, but per-world gravity can be updated:

model.set_gravity(np.array([0.0, -3.71, 0.0], dtype=np.float32), world=0)
g0 = model.gravity_for_world(0)

After mutating, notify the solver:

solver.notify_model_changed(novaphy.solvers.SolverNotifyFlags.ModelProperties)

See Also