SimPy basic concepts
SimPy is a process-based discrete-event simulation (DES) framework for Python.
Process-based: Each entity (machine, vehicle, worker) is represented as a process that can wait, operate, or interact with other entities.
Discrete-event: Time advances from event to event, NOT continuously.
Below are the key concepts:
1. Environment
The central “world” for simulation.
Keeps track of simulation time and all scheduled events.
Simply consider it as a container for the whole simulation.
import simpy
env = simpy.Environment()
2. Processes
Processes are Python generator functions (yield) that represent the lifecycle of an entity.
They can wait for events, perform actions, and interact with resources.
The use of YIELD enables it to pause and wait as in python.
yield env.timeout(t) # wait t time units.
yield conveyor_out.put(amount) # perform an action to put amount onto conveyor output
3. Events
Events are things that happen at a certain time.
Examples: timeout, resource availability, arrival of items.
Processes yield events to pause and resume automatically.
yield some_event # wait until event occurs
4. Resources
SimPy provides built-in resources to model shared capacities:
Resource General capacity-limited resource (workers, machines)
Container Continuous quantity (water, ore, raw material)
Store Discrete items queue (parts, packages, products)\
Example of resource below. Another example later for container.
machine = simpy.Resource(env, capacity=2) # 2 machines available
with machine.request() as req:
yield req # wait until a machine is free
yield env.timeout(3) # work 3 hours
How model the stochastic behavior
use random function to generate the time units for wait / event.
Example:
import random
yield env.timeout(random.expovariate(1/5)) # mean 5 hours
An example of simulating two trucks loading onto a stockpile.
The stockpile is considered as a Container resource.
import simpy
import random
# ---------------------------
# Truck Process
# ---------------------------
def truck(env, name, stockpile, load_amount, interval_mean):
"""
Simulates a truck that arrives repeatedly to deliver ore.
env: SimPy environment
name: Truck name
stockpile: SimPy Container (the stockpile)
load_amount: tonnes delivered each trip
interval_mean: mean travel/arrival time between deliveries
"""
while True:
# Simulate travel time (randomized)
travel_time = random.expovariate(1/interval_mean)
yield env.timeout(travel_time)
print(f"{env.now:.1f} h: {name} arrives with {load_amount} t")
# Deposit ore into stockpile
yield stockpile.put(load_amount)
print(f"{env.now:.1f} h: {name} deposited ore, stockpile level: {stockpile.level:.0f} t")
# ---------------------------
# Main Simulation
# ---------------------------
def main():
random.seed(42)
env = simpy.Environment()
# Stockpile: capacity 50,000 t, initial 0 t
stockpile = simpy.Container(env, capacity=50000, init=0)
# Trucks
env.process(truck(env, "Truck A", stockpile, load_amount=5000, interval_mean=2))
env.process(truck(env, "Truck B", stockpile, load_amount=7000, interval_mean=3))
# Run simulation for 20 hours
env.run(until=20)
print(f"\nSimulation finished. Final stockpile level: {stockpile.level:.0f} t")
if __name__ == "__main__":
main()
Results:
0.1 h: Truck B arrives with 7000 t
0.1 h: Truck B deposited ore, stockpile level: 7000 t
1.0 h: Truck B arrives with 7000 t
1.0 h: Truck B deposited ore, stockpile level: 14000 t
1.8 h: Truck B arrives with 7000 t
1.8 h: Truck B deposited ore, stockpile level: 21000 t
2.0 h: Truck A arrives with 5000 t
2.0 h: Truck A deposited ore, stockpile level: 26000 t
4.3 h: Truck A arrives with 5000 t
4.3 h: Truck A deposited ore, stockpile level: 31000 t
5.8 h: Truck B arrives with 7000 t
5.8 h: Truck B deposited ore, stockpile level: 38000 t
6.1 h: Truck B arrives with 7000 t
6.1 h: Truck B deposited ore, stockpile level: 45000 t
7.7 h: Truck B arrives with 7000 t
8.8 h: Truck A arrives with 5000 t
Simulation finished. Final stockpile level: 45000 t