Skip to content

Sim

Wraps the engine simulation (sim.engine) and the built scene (sim.built) behind names.

dt property

dt: float

Control period in seconds (one step()). Example: sim.dt == 0.01.

t property

t: float

Simulated time in seconds. Example: sim.t.

worlds property

worlds: int

Number of parallel worlds. Example: sim.worlds.

physics_steps property

physics_steps: int

Physics steps taken so far, per world (for world-steps/s: worlds * physics_steps / wall_s).

plugins property writable

plugins: Any

The plug-ins running in this simulation (heat, and alloy.build(plugins=[...])): sim.plugins.read() gives each one's read-outs by label, sim.plugins["<label>"] the plug-in; None without plug-ins.

Example: sim.plugins.read()["particle_thermal"]["heater_area_m2"].

names

names() -> dict[str, list[str]]

Every name by kind: bodies, joints, particles (cloth / liquid), static objects and actuators.

Example: {"bodies": ["cube"], "joints": [], "particles": [], "static": ["ground"], "actuators": []}.

step

step(n: int = 1) -> Sim

Advance n control periods (n * sim.dt seconds). Example: sim.step(100).

run

run(seconds: float, record: Iterable[str] | str | None = None, every: int = 1, *, targets: Mapping[str, Any] | None = None) -> Trajectory

Step seconds of simulated time, recording state every every periods (frame 0 = before stepping).

  • record: names to record (default: every body, joint and particle object); [] records only time;
  • targets: joint position targets during the run: {"joint": value} holds a value, and {"joint": (start, end)} ramps linearly over the run (a smooth move instead of a jump; a large jump makes a stiff servo kick hard enough to shake a grasped object loose).

Returns an alloy.Trajectory; its meta has wall time, physics steps, a health summary and mpm_grid (the grid each MPM solver used: "sparse" or "dense", and any fallback to sparse; [] without MPM). Example: traj = sim.run(1.0, record=["cube"], targets={"lift": (0.0, 0.12)}).

settle

settle(seconds: float) -> Sim

Run seconds with no new commands, then make the settled state the start that reset() returns to (piles, drapes and soft parts start a few mm off rest), also in a scene with scene.randomize (each world settles from its own draws). Example: sim.settle(0.5).

set_pose

set_pose(name: str, pos: Any = None, quat_wxyz: Any = None, *, world: int | None = None) -> Sim

Teleport a free or kinematic body now (zero velocity): pos (3,) or (worlds, 3), quat_wxyz (4,) or (worlds, 4). A robot with a free base (MJCF <freejoint/>) moves with all its links, joint angles kept. pos is what "<name>.pos" reads: a library object placed by its anchor gets that anchor there (and turns about it when only quat_wxyz is given). It removes the object's drive, which would write over the pose at the next step: an ended one, or a running one when every world is teleported (one world under a running drive raises SimulationError).

Example: sim.set_pose("tray", pos=(0, 0, 0.3)).

drive

drive(name: str, *, velocity: Any = (0.0, 0.0, 0.0), angular_velocity: Any = (0.0, 0.0, 0.0), pivot: Any = None, duration: float = float('inf')) -> Sim

Move a kinematic object (or a kinematic fixture's parts together) from now on with a constant linear velocity (m/s) and angular_velocity (rad/s, world axes) about pivot (a world point; default its current .pos, or the fixture's centre) for duration s, then hold. Contacts and liquids see the moving walls every physics step. A new drive of an object replaces its earlier one (it starts from where the object is now). Example (tilt a cup about its lip at 40 deg/s for 2 s)::

sim.drive("cup", angular_velocity=(0, math.radians(40), 0), pivot=(0.044, 0, 0.104), duration=2.0)

stop_drives

stop_drives() -> Sim

Remove every drive; kinematic objects hold where they are, at rest. Example: sim.stop_drives().

randomized

randomized() -> dict[str, np.ndarray]

What Scene.randomize drew for robots and gravity: {"<target>.<field>": (worlds,) values}, as each world holds them now. Example: sim.randomized()["go2.mass_scale"].

pushes

pushes() -> dict[str, np.ndarray]

The scene.add_push force held on each pushed body now: {"go2/base": (worlds, 3) N} (zeros between pushes). Example: sim.pushes()["go2/base"].

reset

reset() -> Sim

Back to the start state of every world (randomized values are redrawn the same way, except robot and gravity rows added with when="reset", which get a new draw; drives and apply_wrench loads are removed).

Example: sim.reset().

state

state(names: Iterable[str] | str | None = None, *, world: int | None = None) -> dict[str, Any]

Current state: {"t": s, "<body>.pos": (W, 3), "<body>.quat_wxyz": ..., "<joint>.q": (W,), ...}. "<body>.pos" is the body origin, except for a library object placed by its anchor (Scene.add_object(..., anchor=)): there it is that anchor point, where you put it, and "<body>.body_pos" is the body origin.

world: one world's values without the world axis. Example: sim.state(world=0)["cube.pos"].

set_targets

set_targets(targets: Mapping[str, Any], kind: str = 'position') -> Sim

Joint targets for actuated joints: {"joint": value} (all worlds) or {"joint": (worlds,) array}.

kind: "position" (MJCF <position> actuators, metres or radians) or "velocity". Kept until changed. A position target outside the joint's range is held at the limit, each world's target on its own (also the ramps of run(targets=); the first one warns). A servo whose file gives it a ctrlrange wider than the joint's range keeps that one (a gripper that squeezes by aiming past its closed stop). A joint that no actuator drives raises SimulationError. Example: sim.set_targets({"gripper/lift": 0.15}).

apply_wrench

apply_wrench(name: str, force: Any = (0.0, 0.0, 0.0), torque: Any = (0.0, 0.0, 0.0), *, at: str | None = None) -> Sim

Hold a force (N) and a torque (N m) on a body, in world coordinates about its centre of mass, until changed; zeros remove it. at: "start" or "end" picks a rod's end segment. A (worlds, 3) array sets one per world. Example: sim.apply_wrench("cable", torque=(0.002, 0, 0), at="end").

set_controls

set_controls(controls: Mapping[str, Any]) -> Sim

Raw MuJoCo ctrl values by actuator name (sim.names()["actuators"]): motors take a force or torque, servos a position or velocity (an MJCF <position> actuator: the joint position it holds, not clamped to the joint's range). Kept until changed. Example: sim.set_controls({"arm/actuator1": 0.5}).

faces

faces(name: str) -> np.ndarray

Triangles (F, 3) of a cloth, as indices into its "<name>.points". Example: sim.faces("towel").

particle_volume

particle_volume(name: str) -> float

Rest volume (m^3) one particle of a liquid stands for: (2 r)^3 for particle radius r, so particles x volume is the liquid volume the engine simulates (see liquid_volume).

Example: sim.particle_volume("water") * len(sim.state(world=0)["water.points"]).

liquid_volume

liquid_volume(name: str) -> float

Volume (m^3) of a liquid as simulated: whole particles fill the shape you asked for, so this can be a few percent below the box volume; enlarge the box if you need an exact amount.

Example: sim.liquid_volume("water") * 1e6 -> millilitres.

temperature

temperature(name: str) -> np.ndarray

Temperatures (K) of a heated object's particles, (worlds, particles) in the order of "<name>.points" (also in sim.state() and recordings as "<name>.temperature").

Example: sim.temperature("water").mean() - 273.15 -> mean °C.

heat

heat(name: str) -> dict[str, np.ndarray]

Per world, over the particles that take heat: mean_K, min_K, max_K, melted (mean liquid share, 0-1), done (mean doneness of food, 0-1), evaporated (share of the mass boiled off) and particles. Not-yet-poured and boiled-off particles are left out.

Example: sim.heat("water")["mean_K"][0].

set_heater

set_heater(name: str, *, temperature: Any = None, power: Any = None) -> Sim

Change a heater while running: temperature K or power W (as it was built), one value or one per world. Example: sim.set_heater("pan_floor", temperature=373.15).

routes

routes() -> dict[str, dict[str, Any]]

Where each object went: route, solver and the reasons. Example: sim.routes()["towel"]["route"]. With the opt-in contact gate on (ClockPolicy.contact_gate), each object in a gated coupled pair also has "exchange_clock": what the gate does and its known gap. A solver may add notes to its objects' rows (alloy_route_notes(), e.g. a film's "contact_skin").

health

health() -> dict[str, Any]

Per-world health: severity OK / DEGRADED / INVALID, flags, a fix for each problem, retired_particles (liquid particles per world that left the scene; None without a liquid) and refined_periods (periods re-run at a finer coupling step for that world since the build; None without coupling); a world whose cloth stretched over 50 % past its rest size has cloth_stretch ({"percent", "cloth", "level": "warn" | "fail"}, the run's peak; fail is over 500 %, INVALID). JSON-ready. Example: h = sim.health(); h["invalid_worlds"].

check

check() -> dict[str, Any]

Physics checks on the current run: {"ok": bool, "problems": [...], ...}. Uses alloy.check when it is installed, else the engine's health monitor. Example: assert sim.check()["ok"].

render

render(camera: Any = None, **kwargs: Any) -> Any

An image of world 0 (or world=) from camera via alloy.camera. Example: img = sim.render().

report

report() -> dict[str, Any]

The engine's report (steps, time, coupling, health objects). Example: sim.report()["steps"].

close

close() -> None

Free the scene's temporary card directory (and the rerun_worlds simulation). Example: sim.close().