Quickstart#

A 30-second end-to-end example using the bundled b01 TwinTank benchmark.

Single-objective RTC#

import gymnasium as gym
import openswmm_gymnasium  # triggers env registration

env = gym.make("OpenSWMM/TwinTank-RTC-v0")
obs, info = env.reset(seed=0)

terminated = False
cumulative_reward = 0.0
while not terminated:
    action = env.action_space.sample()
    obs, reward, terminated, truncated, info = env.step(action)
    cumulative_reward += reward

print(f"Final reward: {cumulative_reward:.3f}")
print(f"Per-component breakdown: {info['reward_components']}")
env.close()

Multi-objective with HV scoring#

import gymnasium as gym
import openswmm_gymnasium

env = gym.make("OpenSWMM/TwinTank-MORTC-v0")
obs, info = env.reset(seed=0)

terminated = False
while not terminated:
    action = env.action_space.sample()
    obs, reward_vec, terminated, truncated, info = env.step(action)

print(f"Normalised HV: {info['mo_score']:.3f}")  # in [0, 1]
print(f"Cumulative cost vector: {info['cumulative_cost']}")
env.close()

Recording trajectories for visualisation#

import gymnasium as gym
import openswmm_gymnasium
from openswmm_gymnasium.wrappers import RecordTrajectory
from openswmm_gymnasium.viz import TrajectoryRun
from openswmm_gymnasium.viz.figures import pareto_front

# Wrap the env so each episode lands in artifacts/run-001/episode_*.jsonl
env = RecordTrajectory(gym.make("OpenSWMM/TwinTank-MORTC-v0"), "artifacts/run-001/")

for ep in range(20):
    env.reset(seed=ep)
    terminated = False
    while not terminated:
        _, _, terminated, _, _ = env.step(env.action_space.sample())
env.close()

# Visualise the run
run = TrajectoryRun.from_dir("artifacts/run-001/")
fig = pareto_front(run)
fig.write_html("pareto.html")

Joint CIP + RTC#

For envs that optimise both design (pre-simulation) and runtime control:

import gymnasium as gym
import openswmm_gymnasium

env = gym.make("OpenSWMM/TwinTank-Joint-v0")

# Pass a specific design at reset; runtime is the per-step action.
import numpy as np
design = {"node_max_depth": np.array([10.0, 14.0], dtype=np.float32)}
obs, info = env.reset(seed=0, options={"design_action": design})

while True:
    action = env.action_space.sample()  # design is ignored after reset
    obs, reward, terminated, truncated, info = env.step(action)
    if terminated or truncated:
        break
env.close()