Bathtub Fill and Drain

Simple stock and flow model of water volume in a bathtub.

Level:Beginner

stocksflowsstoragecapacity

  • Stocks:water_volume
  • Flows:inflow, outflow
  • Probes:water_volume, inflow, outflow

Stocks and Flows

Learn about the foundational concepts of Stocks and Flows in systems thinking and how they interact to create system behavior.

Explore Stocks and Flows
simulation.py

Filling and emptying a bathtub

This pared‑down example highlights the essence of stocks and flows. Water pours in from the tap while some trickles down the drain. By keeping things simple we can watch how the water level changes from one minute to the next.


from tys import probe, progress

Simulate water level in a tub with inflow and drain.

def simulate(cfg: dict):

    import simpy
    env = simpy.Environment()

    volume = cfg["initial_volume"]  # water in tub (liters)
    inflow = cfg["inflow_rate"]     # liters per minute entering
    drain = cfg["drain_rate"]      # liters per minute leaving
    minutes = cfg["minutes"]

    done = env.event()

Update the water volume each minute.

    def run():
        nonlocal volume
        for m in range(minutes):
            volume += inflow - drain
            volume = max(0, volume)
            probe("water_volume", env.now, volume)
            probe("inflow", env.now, inflow)
            probe("outflow", env.now, drain)
            progress(int(100 * (m + 1) / minutes))
            yield env.timeout(1)
        done.succeed({"final_volume": volume})

    env.process(run())
    env.run(until=done)
    return done.value


def requirements():
    return {
        "builtin": ["micropip", "pyyaml"],
        "external": ["simpy==4.1.1"],
    }
config.yaml
initial_volume: 0
inflow_rate: 8
drain_rate: 3
minutes: 20