Simulation in Python With SimPy
Simulation in Python With SimPy
Dear Reader,
● Clear explanations of key SimPy components like events, processes, and resources
● Step-by-step examples to help you simulate real-world systems
● Best practices for writing clean, scalable simulations
● Tips for managing queues, resources, and handling time in your models
Use this guide as a quick reference guide when building simulations, whether you're tackling
a simple task or a complex system. If you're ready to dive deeper, this is just the beginning -
there’s much more to explore in the world of simulation…!
Yours sincerely,
Harry Munro
Founder, School of Simulation
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
2
Table of Contents
Chapter 1 - Introduction 8
Problems on the London Underground 8
Introducing Discrete-Event Simulation (DES) 9
The Importance of Learning from Simulation 10
The Problem with Proprietary Simulation Software 10
High Licensing Costs and Constraints 10
Vendor Lock-In 11
Limited Flexibility for Niche or Evolving Applications 11
Opaque, Black-Box Models 11
Reduced Collaboration and Reproducibility 11
Why Simulations in Python Are a Game-Changer 12
Complete Flexibility and Control 12
Clean, Intuitive Code with SimPy 12
Leverage the Entire Python Ecosystem 12
Low Barriers to Entry and No Licensing Fees 12
Transparent and Reproducible Models 13
Rapid Iteration and Innovation 13
Transferable Skills and Lasting Value 13
Why I Love Simulation Engineering 13
Flexibility and Remote Work 13
Interesting, Valued Work 13
Great Financial Rewards 14
You’re Looking to Add Simulation to Your Toolkit 14
You’re at a Career Crossroads and Dreaming of Something New 14
You’re Already Using Simulation Software but Want to Make the Switch to Python 15
Exercises 15
Chapter 2 - What is Discrete-Event Simulation (DES)? 15
Key Characteristics of DES 16
Applications of DES 16
Advantages of DES 17
Limitations of DES 17
SimPy’s Role in DES 17
Chapter 3 - SimPy Basics 18
Installation 18
Core Concepts 18
Generator Functions - What Are They? 18
How SimPy Uses Generator Functions 19
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
3
Why Generators Make SimPy So Powerful 21
The SimPy Environment 22
SimPy Processes 22
SimPy Events 22
SimPy Resources 22
Using with [Link]() as req: 23
Using [Link]() and [Link]() Explicitly 23
Explanation 24
When to Use Explicit Resource Management 24
Summary 24
Simulation Flow 25
Summary of Key Functions 25
Chapter 4 - Writing a Simple SimPy Program 26
Step 1: Define the Environment 26
Step 2: Define the Process 26
Step 3: Add the Process to the Environment 26
Step 4: Run the Simulation 27
Complete Simple Example 27
Explanation of Output 27
What’s Happening Under the Hood 28
Customising the Simulation 28
Chapter 5 - Key Components in SimPy 29
Events and Processes 29
Timeouts (Pausing Processes) 29
Resources 30
Scheduling Events 31
Combining Resources and Processes 31
Chapter 6 - Simulating a Queue System 33
The Basics of Queuing Systems 33
Defining the Customer Process 33
Defining the Resource (Service Counter) 34
Adding Multiple Customers 34
Introducing Stochastic Delays Between Customer Arrivals 35
Key Differences 36
Understanding the Output 36
Key Observations: 37
Visualising the Queue 37
Why Visualise the Queue? 37
Example: Plotting the Number of Customers in the Queue Over Time 38
Explanation of the Code 41
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
4
Customising the Plot 41
Interpreting the Results 45
Practical Applications 45
Modelling Multiple Entities Competing for Resources with Traceability 46
Adding Resources with Increased Capacity 46
Explanation of the Code 50
Visualising the Results 51
Analysing the System's Performance 51
Practical Insights 52
Chapter 7 - Advanced Resources 53
Priority Resources 53
Preemptive Resources 54
Containers 54
Refilling the Container 55
Best Practices and Common Pitfalls 55
Monitor Resource Utilisation 56
Avoid Over-Complicating Resource Management 56
Balance Resource Capacity 56
Test Different Scenarios 56
Be Mindful of Deadlocks 56
Use Priority and Preemptive Resources When Necessary 57
Chapter 8 - Tips for Efficient Simulations 58
Write Modular Code 58
Use Meaningful Variable Names 58
Manage Time Properly 59
Control Simulation Length 59
Avoid Overloading Resources 59
Track Statistics and Performance 59
Visualise Your Simulation 60
Debugging and Validation 61
Plan for Scalability 61
Chapter 9 - Analysing and Visualising Simulation Data 62
Collecting Simulation Data 62
What Data Should You Collect? 62
Example: Data Collection in a Factory Simulation 62
Analysis 64
Visualising Simulation Data 65
Interpreting the Results 67
Instrumenting Simulations and Logging 67
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
5
Using Custom Logging 68
Using Simulation Data for Decision Support 69
Identifying Bottlenecks 69
How to Resolve Bottlenecks 70
Advanced Data Collection Techniques 70
Custom Data Structures 70
Organising Hierarchical Data 71
Event Tracing 71
Recording Event Timestamps and Types 72
Data Storage Options 72
In-Memory Storage 72
File-Based Storage 73
Database Storage 73
Leveraging Pandas for Data Handling 74
Statistical Analysis of Simulation Data 75
Descriptive Statistics 75
Measures of Central Tendency 75
Measures of Variability 76
Percentiles 76
Probability Distributions 76
Common Distributions in Simulations 76
Fitting Data to a Distribution 77
Generating New Samples from the Fitted Model 77
Applications of Drawing New Samples 78
Confidence Intervals 78
Hypothesis Testing 79
Comparing Simulation Results Under Different Scenarios 79
Advanced Data Visualisation 80
Seaborn for Sophisticated Data Visualisations 80
Plotly for Interactive Visualisations 82
Time-Series Analysis 84
Interactive Dashboards 85
Benefits of Interactive Visualisations 86
Conclusion 87
Chapter 10 - Monte Carlo Simulation and Full Factorial Analysis 88
Introduction to Monte Carlo Simulations 88
How Monte Carlo Simulations Work 88
Example: A Monte Carlo Simulation in SimPy 89
Interpreting the Results 90
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
6
Benefits of Monte Carlo Simulations 90
Implementing Monte Carlo Simulations in SimPy 90
Full Factorial Analysis 91
Example: Full Factorial Analysis in a Factory Simulation 91
Correlation Matrix 95
How to interpret a correlation coefficient 96
Why it is useful 96
Caveats 96
Visualising the Correlation Matrix 97
Analysing the Results 98
Benefits of Full Factorial Analysis 98
Chapter 11 - Simulation Architecture and Patterns in SimPy 99
Why does this matter so much? 99
Primary Simulation Architectures 100
1. Basic SimPy Processes (Functional Approach) 100
2. Object-Oriented Architecture (OOA) 101
3. Entity Component System (ECS) 102
A Helpful Pattern: Finite State Machines (FSM) 104
Final Words on Architecture 107
Chapter 12 - Final Thoughts and Next Steps 108
What’s Next? 108
Taking Simulation to the Real World 109
Final Thoughts 109
About Harry Munro 111
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
7
Chapter 1 - Introduction
A few years into my engineering career, I was handed a challenge that would redefine my
approach to simulation and set the course for my professional journey. The project involved
building probabilistic simulations for the London Underground – a complex, high-stakes task
that required predicting the capacity of various sites and enabling the network to forecast
how future projects would perform.
At the time, there was an off-the-shelf simulation tool available. It was the obvious choice –
expensive, proprietary, and limited. It worked well enough for standard problems but
struggled with the nuances of the Underground’s unique systems. The costs and constraints
didn’t sit well with me, so I began exploring alternatives.
That’s when I discovered Python and its SimPy library. SimPy is a lightweight tool designed
for discrete-event simulation, and its potential was immediately clear. It was open-source,
flexible, and free of the licensing fees that came with traditional software. Despite having no
prior experience with Python, I was intrigued by the possibilities it offered.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
8
I proposed using SimPy to develop the simulations. This wasn’t an easy sell – stakeholders
were naturally cautious about moving away from tried-and-tested software to an
open-source solution. But I believed in the value it could bring, so I set out to prove its worth.
The transition was not without its hurdles. I was learning Python as I went, figuring out
version control for the first time, and navigating the complexities of creating detailed
simulations from scratch. Yet, the more I worked with SimPy, the more its advantages
became apparent. It allowed me to model complex sites on the Underground network – from
depots to intricate junctions – with a level of detail and customisation that the proprietary tool
couldn’t match.
The results were transformative. The simulations we built with SimPy provided insights that
shaped multimillion-pound decisions. They gave the Underground the ability to predict
outcomes with confidence, optimise operations, and plan for the future. The success of this
project didn’t just validate SimPy – it solidified Python as the foundation for my team’s
simulation work moving forward.
This experience taught me more than just how to use Python for simulation. It showed me
the power of challenging the status quo, embracing new tools, and trusting in my ability to
learn and adapt. These lessons have stayed with me, and I hope they’ll inspire you as you
embark on your own journey into simulation with Python.
Discrete-Event Simulation (DES) brings this idea of precision and timing into the world of
systems and processes. Rather than looking at smooth, continuous operations, DES focuses
on key events that drive performance. Whether you're fine-tuning a bustling factory floor,
managing patient flow in an overcrowded hospital, or handling bursts of network traffic, DES
lets you zoom in on those critical moments where everything either clicks into place or falls
spectacularly apart.
With DES, you can tackle the big 'what if' questions without the guesswork: What if a crucial
machine stops working? How would hiring extra hospital staff impact patient wait times?
Could the network actually survive an unexpected surge in traffic, or would it collapse faster
than my diet on holiday?
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
9
Instead of relying on intuition or luck, DES provides clear, actionable insights grounded in
realistic scenarios - helping you make smarter decisions, faster.
With such capabilities, it’s no surprise that DES is an essential tool for engineers, scientists,
and analysts working in today’s complex, data-driven world. But as we’ll explore, not all
simulation approaches are created equal - and that’s where Python, and its powerhouse
library SimPy, enter the stage.
This is where simulation becomes truly invaluable. It allows us to explore scenarios, test
different strategies, and fail safely. Each failure provides new insights, refining our
understanding and leading us to better solutions. Moreover, for large capital-intensive
projects, simulation offers immense cost-saving opportunities by allowing more optimal
decision-making early in the project lifecycle. By catching potential issues or inefficiencies
before they occur in reality, simulation can reduce waste, improve resource allocation, and
avoid costly redesigns or delays.
I encourage you, as the reader, to embrace this mindset. Dive into simulations with the
intention to experiment, fail, and learn, knowing that each iteration brings you closer to
mastering the complexities of the system you’re modelling.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
10
annual renewal fees quickly add up. For engineers working on tight budgets or freelancers
striking out on their own, these costs can create a significant barrier.
Vendor Lock-In
Proprietary tools rarely integrate seamlessly with external systems. They are designed to
keep users within their ecosystem, creating dependency on a single vendor. This lock-in
reduces flexibility and increases long-term costs, particularly if you need features not
included in the software’s package or decide to move to a different solution.
In a field that thrives on innovation and precision, these limitations are significant. Engineers
often need to work around the constraints of the software, wasting time and effort that could
be better spent solving problems. This is why Python – and SimPy – are rapidly becoming
the tools of choice for forward-thinking engineers and analysts.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
11
Why Simulations in Python Are a Game-Changer
When it comes to overcoming the limitations of proprietary software, Python offers a breath
of fresh air. With its open-source nature and a vast ecosystem of libraries, Python has
become the go-to language for simulation engineers seeking flexibility, transparency, and
cost-effectiveness. Here’s why simulations in Python, particularly with SimPy, are
revolutionising the field:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
12
transparency ensures your simulations are robust, reproducible, and trusted by
stakeholders.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
13
bring is always recognised. When you solve a problem that saves time, money, or resources,
people notice.
Simulation engineering is a rare field where you can combine technical creativity,
problem-solving, and practical impact with a flexible and well-compensated career. For me,
it’s been the perfect fit, and I want to share this opportunity with others who are ready to
embrace it.
Who This Book Is ForThis book is designed to meet you where you are and guide you to
where you want to be, whether you’re taking your first steps in simulation or aiming to level
up your existing skills. If any of the following scenarios sound familiar, you’re in the right
place:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
14
You’re Already Using Simulation Software but Want to Make the Switch
to Python
If you’ve worked with proprietary tools and felt the pain of high costs, limited flexibility, or
opaque black-box models, this book will help you transition to Python. You’ll learn how to
replicate and improve what you’ve been doing – but without the constraints.
Simulation in Python is an exciting, empowering skill that can open doors to new
opportunities and career paths. Whatever your motivation for learning, this book will give you
the tools and knowledge you need to succeed.
Exercises
1. Think about a system you encounter in your daily life (e.g., a coffee shop, traffic
intersection, grocery store checkout). Briefly describe how DES could be used to
model and understand its behavior. What are some key events and resources in this
system?
2. List three advantages of using Python for simulation over proprietary software. For
each advantage, briefly explain why it is beneficial for an engineer or analyst.
3. Describe a scenario where building a simulation could prevent costly real-world
mistakes or lead to significant improvements in a system.
4. Visit the official SimPy documentation (a quick web search for "SimPy
documentation" will find it). Identify one feature or capability of SimPy mentioned in
its documentation that you find particularly interesting or potentially useful, and briefly
explain why.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
15
Key Characteristics of DES
● Event-Driven Dynamics: In DES, nothing happens between events. Changes occur
only at specific points when events take place; like the ticking hands of a clock that
move only when prompted.
● Time Progression: Time leaps from one event to the next, ignoring the silent
intervals in between. This jump-forward mechanism ensures efficiency by
concentrating computational efforts on moments of change.
● Efficient Modelling: By simulating only the events that alter the system’s state, DES
efficiently handles complex, real-world systems without unnecessary computational
overhead.
Applications of DES
DES finds its strength in industries where timing and resource allocation are critical. Its
applications are as diverse as the systems it models:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
16
● Infrastructure Design: Exploring “what-if” scenarios in large capital projects to make
informed decisions early in the design lifecycle, saving time and resources.
Advantages of DES
● Precision in Resource Allocation: DES allows for meticulous simulation of systems
with limited resources; ensuring every machine, worker, or component is utilised
optimally.
● Scenario and “What-If” Testing: Easily test multiple scenarios to identify potential
bottlenecks or areas for improvement, enabling proactive decision-making.
● Cost-Effectiveness: By modelling complex systems virtually, DES reduces the need
for expensive real-world experiments, saving both time and money.
Limitations of DES
● High Initial Effort: Building a detailed simulation model requires significant upfront
work to define every event, state, and interaction; much like crafting the blueprint
before constructing a skyscraper.
● Unsuitable for Continuous Processes: DES excels with discrete events but isn’t
ideal for systems where continuous change is paramount, such as fluid dynamics or
temperature variations.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
17
Chapter 3 - SimPy Basics
Installation
Imagine possessing the power to predict the behaviour of a bustling shop or the seamless
operation of a factory all from the comfort of your desk. SimPy, a lightweight and intuitive
Python library for discrete-event simulations, allows you to do just that. To begin your journey
into the world of simulation, you need only a simple command:
Core Concepts
SimPy revolves around a few key concepts that help model the behaviour of real-world
systems.
Think of a generator function as a pause button on a video. When you hit pause, the video
doesn’t start over it picks up right where you left off when you hit play again. Similarly,
generator functions in SimPy allow you to model processes that unfold over time, but with
the ability to pause and wait for certain events (like a customer waiting for service or a
machine being repaired) before resuming.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
18
def countdown(n):
while n > 0:
yield n
n -= 1
In this example, the countdown function counts down from a given number, pausing after
each step. Each time you call the function, it resumes where it left off, making it ideal for
modelling time-based processes.
for i in countdown(5):
print(i)
Output:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
19
For example, in a bank simulation, you could model customers arriving at random intervals
and waiting to be served. Each customer would be a generator function that “yields” when
they arrive and waits until a teller is available to serve them. Once served, the function
resumes and simulates the customer leaving the bank.
Let’s take a look at how this works in practice - you can access the code here.
import simpy
yield req
yield [Link](service_time)
env = [Link]()
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
20
[Link](until=20)
Simulation output:
In this example:
● Each customer arrives at the bank, requests a counter, and waits if necessary.
● The yield keyword allows the customer to wait until a counter is free, simulating a
real-world queue.
● The simulation runs for a specified time (20 units), and we can see how each
customer’s interaction with the system plays out.
This ability to model concurrency makes SimPy an excellent choice for simulating systems
where many events happen at the same time, or where multiple resources are being shared
among many entities.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
21
The SimPy Environment
● The Environment is at the heart of any SimPy simulation. It manages the simulation
clock and controls the scheduling and execution of events.
● It tracks simulation time, which can be accessed through [Link].
● Processes, resources, and events are created and managed through the
environment.
Example:
import simpy
env = [Link]()
SimPy Processes
● In SimPy, processes are represented using Python's generator functions. These
processes yield events, which are scheduled by the environment.
● A process could represent anything from a customer arriving at a store to a machine
processing items. Processes can be paused (using yield) and resumed later.
Example:
def process_example(env):
print(f"Process starts at time {[Link]}")
yield [Link](5)
print(f"Process resumes at time {[Link]}")
SimPy Events
● Events represent specific points where something happens in the simulation, such
as a machine finishing a task or a resource being requested.
● Timeouts are the most basic type of event in SimPy. You can use [Link](t)
to simulate the passing of time. Other events include resource requests or process
completions.
Example:
def machine(env):
print(f"Machine starts at {[Link]}")
yield [Link](3) # Machine works for 3 units of time
print(f"Machine stops at {[Link]}")
SimPy Resources
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
22
Resources in SimPy model shared assets that processes compete for, such as servers,
machines, or workers. Resources are essential when modelling systems with limited
availability.
This is the simpler, more concise way to manage resource requests. The with statement
automatically handles the request and release of the resource.
Example:
In more complex simulations, you might need more control over the timing of resource
requests and releases. This can be done by explicitly managing these events.
Example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
23
# Release the resource manually
[Link](req)
print(f"Resource released at {[Link]}")
# Simulation setup
env = [Link]()
resource = [Link](env, capacity=1)
[Link](process_with_explicit_request(env, resource))
[Link](until=10)
Explanation
● Complex Simulations: In more complex scenarios, where you may need to request
multiple resources at different times, or where the resource usage depends on
conditions evaluated during the process.
● Conditional Releases: If the release of the resource depends on specific conditions
or additional logic, explicitly managing the resource gives you the flexibility to handle
these scenarios.
Summary
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
24
● Explicit request() and release(): Provides more control over the timing and
conditions of resource management, useful in complex simulations.
By understanding both approaches, you can choose the one that best fits the complexity and
requirements of your simulation.
Simulation Flow
Process Creation: Processes are added to the environment using [Link]() like so:
[Link](process_example(env))
Simulation Execution: The environment runs until a given time or until there are no more
events left using [Link](). This ensures that all events are processed in the correct
order. The run time is specified like so:
[Link](until=10)
Note that time is unitless in simpy - it is up to you to decide what units of time you wish to
use. Just remember to be consistent!
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
25
Chapter 4 - Writing a Simple SimPy Program
This section walks through the creation of a basic SimPy simulation, introducing key
concepts like processes, timeouts, and events. Here’s how to write a simple simulation using
SimPy.
import simpy
env = [Link]()
Let’s define a process where a car alternates between parking and driving:
def car(env):
while True:
print(f'Car parks at {[Link]}')
yield [Link](5) # Car is parked for 5 units of time
print(f'Car drives at {[Link]}')
yield [Link](2) # Car drives for 2 units of time
Here:
● [Link](5) tells the simulation to pause the car process for 5 units of time
(simulating that the car is parked).
● After 5 units, the process resumes and simulates the car driving for 2 units of time.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
26
To add a process to the environment, you use [Link](). This schedules the process
to start immediately:
[Link](car(env))
[Link](until=15)
def car(env):
while True:
print(f'Car parks at {[Link]}')
yield [Link](5) # Car is parked for 5 units of time
print(f'Car drives at {[Link]}')
yield [Link](2) # Car drives for 2 units of time
env = [Link]()
[Link](car(env))
[Link](until=15)
Explanation of Output
The simulation will produce output like:
Car parks at 0
Car drives at 5
Car parks at 7
Car drives at 12
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
27
Here’s what’s happening:
1. The car parks at time 0 and stays parked for 5 time units.
2. It then drives from time 5 to time 7.
3. This alternation between parking and driving continues until the simulation reaches
time 15.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
28
Chapter 5 - Key Components in SimPy
SimPy makes it simple to model real-world processes and systems by providing several
fundamental components. Understanding these core elements will help you build more
complex simulations.
Example:
def machine(env):
print(f'Machine starts at {[Link]}')
yield [Link](3) # Machine operates for 3 time units
print(f'Machine finishes at {[Link]}')
Here, the machine operates for 3 time units, simulated by the [Link]() function,
which represents the passage of time.
Example:
def worker(env):
print(f'Worker starts at {[Link]}')
yield [Link](2) # Worker works for 2 time units
print(f'Worker finishes at {[Link]}')
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
29
In this example, the worker stops working after 2 units of time. The simulation time advances
by 2 time units as the timeout is yielded.
Resources
Resources in SimPy model limited assets like machines, workers, or servers that processes
compete for. When a process needs access to a resource, it issues a request, and when it’s
done, it releases the resource.
import simpy
env = [Link]()
worker = [Link](env, capacity=1) # Only one worker
available
[Link](task(env, worker))
[Link](until=10)
In this example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
30
Scheduling Events
SimPy allows you to schedule future events and control how they’re processed by the
environment.
Example:
def event_scheduler(env):
print(f'Starting at {[Link]}')
yield [Link](5) # Schedule an event 5 units from now
print(f'Event occurred at {[Link]}')
env = [Link]()
[Link](event_scheduler(env))
[Link](until=10)
In this example, an event is scheduled to occur after 5 units of time, and the environment is
run until time 10.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
31
env = [Link]()
worker = [Link](env, capacity=1) # Only one worker
available
[Link](until=10)
Here:
● Three tasks are created, but since there’s only one worker, the tasks must wait for
the worker to be available.
● Each task takes 2 time units, and the simulation runs for 10 units of time.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
32
Chapter 6 - Simulating a Queue System
In many real-world systems, entities (like customers, jobs, or products) need to wait in line
for a resource to become available (e.g., a service desk, a machine, or a server). SimPy
makes it easy to simulate these kinds of queue systems using resources and processes.
import simpy
In this example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
33
○ Once served, they spend 5 time units at the service desk.
○ After being served, they leave the system.
Here:
● We define a resource counter with a capacity of 1, meaning only one customer can
be served at a time.
● If multiple customers request the counter at the same time, the rest will wait in a
queue.
Example:
env = [Link]()
counter = [Link](env, capacity=1)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
34
Introducing Stochastic Delays Between Customer Arrivals
In real life, customer arrivals usually follow some form of stochastic process. A common way
to model the time between arrivals is by using an exponential distribution. We can simulate
this by introducing a stochastic delay between customer arrivals using numpy to generate
random inter-arrival times, and [Link]() in SimPy to handle the delays.
import simpy
import numpy as np
yield req
for i in range(5):
interarrival_time =
[Link](mean_interarrival_time)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
35
env = [Link]()
[Link](customer_generator(env, counter,
mean_interarrival_time))
[Link](until=20)
Key Differences
● Stochastic Inter-arrival Times: The time between customer arrivals is now drawn
from an exponential distribution using
[Link](mean_interarrival_time), where
mean_interarrival_time is the average delay between arrivals.
● More Realistic Customer Flow: This models a more realistic arrival pattern, with
customers arriving at irregular intervals, rather than fixed intervals of 3 time units as
in the original example.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
36
Customer 1 is being served at time 2.1
Key Observations:
● Variable Arrival Times: Unlike in the fixed interval case, the times between
customer arrivals are now random.
● Queue Behaviour: Similar to the fixed case, customers may arrive while another is
being served and will queue up, waiting for their turn at the service counter.
Here’s how visualising the queue can be beneficial, followed by an example of how to
implement it in Python.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
37
resources. For example, if your queue frequently builds up, it might indicate
that your service process is a bottleneck or that more resources are needed
to handle the workload.
2. Monitor Queue Fluctuations:
○ The queue size may fluctuate significantly based on arrival rates and service
times. A visual representation helps track when queues grow and shrink,
allowing you to identify peak load periods, times when customers are left
waiting too long, or when resources are idle.
3. System Performance Analysis:
○ By visualising queues, you can analyse performance metrics like average
wait time, queue length over time, and peak queue size. This allows you to
fine-tune your system and optimise resource allocation.
4. Improve Decision-Making:
○ If your queue is consistently long, it could signal a need for more resources
(e.g., additional servers or machines). Conversely, if the queue is often empty
or short, it might indicate over-provisioning of resources. Visualisation aids in
these operational decisions.
Code Implementation:
import simpy
arrival_time = [Link]
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
38
queue_lengths.append(([Link], len([Link]))) # Track
the queue length
yield req
for i in range(10):
env = [Link]()
wait_times = []
queue_lengths = []
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
39
# Start the customer generation process
[Link](until=20)
[Link]('Time')
[Link](True)
[Link]()
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
40
Explanation of the Code
● Tracking Queue Lengths:
○ The line queue_lengths.append(([Link], len([Link])))
logs the current time ([Link]) and the number of customers in the queue at
that moment (len([Link])). This is done every time a customer
arrives and requests the resource.
● Plotting the Data:
○ After the simulation runs, we extract the time points and queue sizes using
zip(*queue_lengths) and plot them using Matplotlib.
○ The resulting plot will show how the queue size changes over time, with
markers indicating the points when customers arrive and leave the queue.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
41
1. Adding a Moving Average:
○ You can smooth out the queue data by adding a moving average, which helps
visualise trends over time rather than just individual points.
Example:
import numpy as np
window_size = 3
moving_avg = [Link](queue_sizes,
[Link](window_size)/window_size, mode='valid')
# Adjust the x-axis times to align the moving average with the
correct starting point
[Link]('Time')
[Link]()
[Link](True)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
42
plt.tight_layout()
[Link]()
Example:
[Link](times, queue_sizes, marker='o')
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
43
[Link](overload_times, overload_sizes, color='red',
label='Overloaded Queue', zorder=5)
Example:
avg_queue_size = sum(queue_sizes) / len(queue_sizes)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
44
Interpreting the Results
Once the plot is generated, you can begin to analyse:
● Peaks in Queue Size: High peaks in the graph indicate times when the system was
overloaded, potentially causing long customer wait times.
● Periods of Low Activity: Flat or low points on the graph may indicate periods when
the resource was idle or under-utilised.
● Average Queue Size: The overall trend of the queue size, along with the calculated
average queue size, helps in determining whether the system’s capacity is sufficient.
Practical Applications
● Manufacturing Systems: In manufacturing, queue visualisation can help identify
bottlenecks in production lines, where items might be waiting too long to be
processed.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
45
● Customer Service Systems: For call centres or service desks, queue visualisation
highlights periods of high traffic and customer wait times, allowing for better staffing
decisions.
● Logistics and Supply Chains: In logistics, tracking queue sizes can help monitor
shipping delays or warehouse processing times, improving overall efficiency.
This section demonstrates how to model multiple entities competing for a resource with
increased capacity and how to trace the system's performance through both print
statements and visualisation.
Here’s an example where the resource (e.g., a service desk) has a capacity of 3, meaning
up to three customers can be served simultaneously.
import simpy
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
46
def customer(env, name, counter, wait_times, queue_lengths,
active_servers):
arrival_time = [Link]
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
47
yield [Link](2) # Customer arrival every 2 unit of
time
env = [Link]()
wait_times = []
queue_lengths = []
active_servers = []
[Link](until=30)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
48
# Plot the number of customers in the queue over time
[Link]('Time')
[Link]('Count')
[Link]()
[Link](True)
plt.tight_layout()
[Link]()
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
49
Explanation of the Code
● Resource with Capacity 3:
○ counter = [Link](env, capacity=3) defines a resource
(e.g., a service desk) with a capacity of 3, meaning up to 3 customers can be
served simultaneously.
● Traceability via Print Statements:
○ Arrival: print(f'{name} arrives at time {[Link]}') logs when
each customer arrives.
○ Start of Service: print(f'{name} is being served at time
{[Link]}') logs when each customer begins service.
○ End of Service: print(f'{name} leaves at time {[Link]}') logs
when each customer leaves after being served.
● Tracking Queue Lengths and Active Servers:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
50
○ Queue Lengths: queue_lengths.append(([Link],
len([Link]))) tracks the number of customers waiting in the
queue at each time point.
○ Active Servers: active_servers.append(([Link],
[Link])) tracks the number of servers (workers or machines)
currently in use at each time point. This shows the resource utilisation over
time.
● Queue Size Over Time: This plot shows how many customers are waiting in the
queue at different time points. Peaks in the plot indicate times when the system is
overloaded.
● Active Servers Over Time: This plot shows the number of servers (or workers)
actively serving customers over time. If the number of active servers frequently hits
the resource capacity (e.g., 3), it indicates that the system is working at full capacity
and might need more resources to avoid queue build-ups.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
51
Practical Insights
By increasing the resource capacity and adding traceability, you can gain deeper insights
into how multiple entities compete for resources in real-world systems. This is particularly
useful for:
● Manufacturing Systems: Track how machines handle production loads and how
often queues build up for resources.
● Customer Service Systems: Monitor how service agents are utilised and whether
more agents are needed to prevent long customer wait times.
● Network Systems: Simulate how network servers handle multiple client requests
and how server capacity impacts performance.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
52
Chapter 7 - Advanced Resources
SimPy’s Resource class is versatile, but it also provides more specialised resource types to
model different real-world scenarios.
Priority Resources
In some systems, certain entities need to be prioritised over others. For example, in
healthcare, critical patients are treated before those with less urgent conditions. SimPy’s
PriorityResource allows you to assign priorities to requests, ensuring that high-priority
entities are served first, even if lower-priority entities arrived earlier.
In this example:
● The priority_customer function works just like the regular customer function, but it
includes a priority argument. This priority determines the order in which customers
are served.
● Lower numbers represent higher priority. So, a customer with priority 0 will be served
before a customer with priority 1, even if the latter arrived earlier.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
53
Preemptive Resources
Sometimes, high-priority entities need to interrupt ongoing activities. For example, in
emergency services, an ambulance responding to a life-threatening call might preempt a
vehicle that’s already en route to a less critical case. SimPy models this scenario with
PreemptiveResource.
With a PreemptiveResource, entities with higher priority can preempt (interrupt) lower-priority
entities that are currently using the resource. The lower-priority entity can resume its activity
later, once the higher-priority task is finished.
Here’s an example:
# Create a preemptive resource with 1 server
preemptive_teller = [Link](env, capacity=1)
Containers
For systems where resources accumulate or deplete over time, SimPy provides the
Container class. Containers are used to model resources like fuel, inventory, or water levels,
which can be added to or removed from over the course of the simulation.
# Create a container with an initial level of 100 and a maximum capacity of 200
fuel_tank = [Link](env, init=100, capacity=200)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
54
# A process that consumes fuel
def consume_fuel(env, amount, fuel_tank):
while True:
yield fuel_tank.get(amount)
print(f'Consumed {amount} fuel at {[Link]}. Fuel level: {fuel_tank.level}')
yield [Link](10) # Wait 10 units of time before consuming more fuel
In this example:
● We define a fuel_tank container with an initial level of 100 units of fuel and a
maximum capacity of 200 units.
● The consume_fuel process simulates fuel consumption. Each time the process runs,
it requests a certain amount of fuel from the tank. If enough fuel is available, the
process proceeds; otherwise, it waits until the tank is refilled.
In this scenario:
● The refill_fuel process adds fuel to the tank every 20 units of time, ensuring that the
fuel level doesn’t drop too low.
● The combination of consumption and refilling allows us to model a system where
resources fluctuate over time, providing a more realistic view of how the system
operates.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
55
Monitor Resource Utilisation
Always track how your resources are being used. SimPy makes it easy to monitor resource
utilisation, which helps you identify bottlenecks in your system. For example, if you see that
a resource is being used 100% of the time, it might indicate that the system is
under-resourced, and adding more capacity could improve performance. On the other hand,
if a resource is underutilised, it may be a sign that the system could be streamlined to reduce
costs. You can monitor resource utilisation by tracking how often resources are requested
and released, and how long entities wait for access to them. This data can be collected and
analysed during or after the simulation to help inform decision-making.
Be Mindful of Deadlocks
Deadlocks occur when two or more processes are waiting for each other to release
resources, and neither can proceed. For example, in a simulation of a manufacturing plant,
two machines might each need the same tool to complete their tasks. If both machines
request the tool at the same time and neither releases it, the simulation can get stuck.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
56
Prevent deadlocks by ensuring that processes request and release resources in a logical
order and by designing your system so that it can handle potential resource conflicts
gracefully.
Resource management is a key aspect of creating accurate and insightful simulations with
SimPy. By modelling how entities compete for limited resources, you can gain a deeper
understanding of system bottlenecks, resource utilisation, and the trade-offs involved in
balancing capacity with demand.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
57
Chapter 8 - Tips for Efficient Simulations
When working with simulations, especially for complex systems with multiple entities and
events, it’s essential to write efficient and manageable code. Here are some best practices to
ensure your simulations run smoothly and remain easy to understand.
This keeps each process focused, which makes debugging and extending the code easier.
Bad Example:
Good Example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
58
def customer(env, counter):
...
Example:
Example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
59
● Measure System Performance: Use counters, logs, or tracking variables to collect
statistics during the simulation. You can track things like wait times, service times, or
queue lengths to assess the performance of your system.
Example:
wait_times = []
At the end of the simulation, you can analyse this data to find bottlenecks or optimise
resource usage.
[Link](wait_times, bins=10)
[Link]('Customer Wait Times')
[Link]('Time Units')
[Link]('Number of Customers')
[Link]()
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
60
Debugging and Validation
● Print Statements: Use print statements to log key events, especially during
debugging. Logging the time ([Link]) and important transitions (like when a
customer arrives or leaves) helps you verify that your simulation behaves as
expected.
Example:
Example:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
61
Chapter 9 - Analysing and Visualising Simulation
Data
A critical aspect of building simulations is analysing the data that comes out of them. It’s not
enough to simply run a simulation - you need to understand the insights it provides.
The data generated by your simulation can reveal bottlenecks, inefficiencies, and
opportunities for improvement. In this chapter, we’ll explore how to collect, analyse, and
interpret simulation data to draw actionable conclusions.
● Wait times: How long do entities (e.g. customers, patients, tasks) wait before
receiving service or processing?
● Queue lengths: How many entities are waiting in line at any given moment?
● Resource utilisation: How often are resources (e.g. machines, staff, vehicles) in use,
and how much idle time do they have?
● Throughput: How many entities are processed or served over a given period?
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
62
import simpy
import random
# Product process
def product(env, name, machine1, machine2):
arrival_time = [Link]
print(f'{name} enters the factory at {[Link]}')
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
63
# Run the simulation for 50 units of time
[Link](until=50)
Example Output
Product 1 enters the factory at 0
Product 2 enters the factory at 0
Product 3 enters the factory at 0
Product 4 enters the factory at 0
Product 5 enters the factory at 0
Product 1 leaves the factory at 9.462990500968086, total time: 9.462990500968086
Product 2 leaves the factory at 19.94591558290178, total time: 19.94591558290178
Product 3 leaves the factory at 29.334574750299282, total time: 29.334574750299282
Product 4 leaves the factory at 34.59649286985815, total time: 34.59649286985815
Product 5 leaves the factory at 42.10036910976831, total time: 42.10036910976831
Analysis
Once you’ve collected data from the simulation, the next step is to analyse it. Depending on
the complexity of the simulation and the data collected, this can range from simple summary
statistics to more advanced data visualisation and statistical analysis.
The simplest way to start analysing simulation data is by calculating summary statistics such
as averages, medians, or standard deviations. These provide a quick overview of the
system’s performance.
For example, let’s calculate the average wait time for products in the factory simulation:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
64
Output:
Average product wait time: 24.39
Similarly, you can calculate the utilisation rate for each machine by dividing the total time the
machine was in use by the total simulation time:
Output:
Utilisation of Machine 1: 65.78%
Utilisation of Machine 2: 59.24%
In this example:
● Average Wait Time: We calculate the average time products spent in the factory,
giving us a measure of overall system performance.
● Machine Utilisation: By calculating the percentage of time each machine was in use,
we can identify whether the machines are underutilised or overworked.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
65
[Link]()
[Link](figsize=(7, 5))
[Link](machines, utilisations)
[Link]('Machine Utilisation')
[Link]('Utilisation (%)')
[Link]()
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
66
Interpreting the Results
● Product Wait Times: The line plot of product wait times shows how long each product
spent in the factory. You might notice patterns - such as increasing wait times for later
products - that could indicate bottlenecks in the system.
● Machine Utilisation: The bar chart of machine utilisation reveals how efficiently each
machine was used. If one machine is underutilised compared to another, you might
investigate why and whether changes in capacity or scheduling could improve overall
efficiency.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
67
Using Custom Logging
In Python, you can use the built-in logging module to create detailed logs of your simulation’s
execution. This can be particularly useful for debugging or understanding how different
processes interact with each other.
import logging
# Set up logging
[Link](level=[Link])
With logging in place, you can track when each product enters and exits the factory, as well
as when it finishes processing on each machine. This gives you a detailed view of how the
simulation unfolds over time, which can be invaluable for debugging or understanding
complex interactions between entities and resources.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
68
Here’s an example of what the log output might look like:
This log provides a step-by-step account of what happens to each product throughout the
simulation. You can adjust the logging level to show more or less detail, depending on your
needs.
Identifying Bottlenecks
A key outcome of simulation analysis is identifying bottlenecks: areas where entities are
delayed or resources are overburdened. Bottlenecks can limit system throughput, increase
wait times, and reduce overall efficiency. By understanding where these bottlenecks occur,
you can implement targeted improvements that address the root causes of inefficiencies.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
69
In the factory simulation example, bottlenecks might occur if one machine is used far more
than the other, leading to long queues at that machine. By analysing machine utilisation and
wait times, you can pinpoint the exact location of the bottleneck and explore solutions such
as increasing machine capacity, reducing processing times, or balancing the workload more
evenly.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
70
progress of multiple entities across several stages. In these cases, custom classes or data
structures provide a more flexible and scalable solution.
class Product:
def __init__(self, product_id):
self.product_id = product_id
[Link] = {}
# Example usage
product_1 = Product("Product_1")
product_1.add_stage_data("Assembly", processing_time=12, wait_time=3)
product_1.add_stage_data("Packaging", processing_time=8, wait_time=1)
This structure allows you to neatly organise data by product and stage, making it easier to
track and access later. Each product can be treated as a self-contained unit with its own
data, which can be further processed or analysed at the end of the simulation.
Event Tracing
Event tracing is an advanced data collection method that records the exact flow of a
simulation by logging specific events. This allows for granular analysis of how entities
interact with each other and the environment. Tracing specific events, such as the arrival and
departure of entities, or resource requests and releases, can help identify bottlenecks,
performance issues, or unexpected behaviours within a system.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
71
Recording Event Timestamps and Types
To implement event tracing, you can log details about each event that occurs, including
timestamps, event types, and the entities involved. This data can later be used for
debugging or for deeper analysis of system dynamics.
class EventTracer:
def __init__(self):
[Link] = []
By keeping a detailed event log, you can examine the sequence of events after the
simulation completes and assess how efficiently different parts of the system performed.
In-Memory Storage
For smaller simulations, storing data in memory using lists, dictionaries, or custom objects
can be sufficient. This approach is fast and allows for easy data manipulation during the
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
72
simulation. However, for larger datasets or long-running simulations, this method may
become impractical due to memory limitations.
File-Based Storage
Storing data in files is a more scalable solution for simulations that generate large amounts
of data. Common file formats include CSV, JSON, and HDF5. Libraries like pandas simplify
the process of saving, loading, and managing large datasets.
This approach is particularly useful for saving structured data that can later be analysed
using tools like Excel or Python’s data manipulation libraries.
Database Storage
For large-scale simulations that require fast access to vast amounts of data, databases offer
a robust solution. SQL databases (e.g., MySQL, PostgreSQL) and NoSQL databases (e.g.,
MongoDB) are commonly used to store simulation results in a way that allows for quick
querying and retrieval. This is especially useful when working in multi-user environments or
when simulation data needs to be accessed and analysed over time.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
73
conn = [Link]('simulation_results.db')
cursor = [Link]()
Using a database allows for greater flexibility when handling large datasets, and it enables
more advanced querying options to explore your simulation data efficiently.
By using pandas, you can perform complex data manipulations and analysis with minimal
code, making it an indispensable tool for processing simulation results.
The advanced data collection techniques outlined in this section provide the foundation for
effective simulation analysis. By organising data using custom structures, implementing
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
74
event tracing, and selecting appropriate storage solutions, you’ll be well-prepared to manage
even the most complex datasets your simulations produce.
In the next section, we’ll explore how to analyse the data you’ve collected, using descriptive
and inferential statistical methods to extract meaningful insights from your simulations.
Once you have collected and stored your simulation data, the next step is to analyse it.
Statistical analysis enables you to summarise the data, identify trends, and make informed
decisions based on your simulation’s performance. In this section, we’ll dive deeper into both
descriptive and inferential statistics, helping you extract actionable insights from your
simulation data.
Descriptive Statistics
Descriptive statistics provide a simple way to summarise your simulation data by calculating
key metrics such as the mean, median, variance, and percentiles. These statistics are critical
for understanding the overall performance of your system and can highlight areas that
require further investigation.
The mean is useful for understanding the average performance, but it can be skewed by
outliers. In contrast, the median offers a better indication of typical performance in systems
where outliers are present.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
75
Measures of Variability
In addition to central tendency, it’s important to understand the variability in your system’s
performance. Metrics like variance and standard deviation provide insights into the spread of
your data, helping you assess how consistent your system is.
print(f"Variance: {variance}")
print(f"Standard Deviation: {std_deviation}")
High variance or standard deviation may indicate that there are significant fluctuations in the
performance of the system, which could be a sign of inefficiency or instability.
Percentiles
Percentiles are useful for understanding the distribution of data and identifying outliers. For
example, the 90th percentile can show you the threshold under which 90% of the system’s
performance falls.
This helps identify extreme cases where certain processes take significantly longer than
usual, allowing you to investigate potential bottlenecks or inefficiencies in the system.
Probability Distributions
In many simulations, the data you collect may follow a particular probability distribution.
Understanding these distributions is critical for interpreting your data and applying statistical
models correctly.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
76
● Triangular Distribution: Fantastic for modelling based on stakeholder information: you
can gather a “best case”, a “worst case” ad a “typical case” through stakeholders
interviews to form the distribution.
By fitting the data to these distributions, you can determine which model best describes the
behaviour of your system. This is particularly useful for making predictions about future
performance or simulating different scenarios based on historical data.
In this example, [Link]() and [Link]() generate 1,000 new random samples based on
the fitted exponential and normal distributions, respectively. These newly generated data
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
77
points can be used in further simulations to explore how your system might perform under
similar conditions in the future.
● Scenario Testing: Simulate different scenarios based on real-world data and assess
system performance under various conditions.
● Monte Carlo Simulations: Use randomly generated samples from your fitted model to
run multiple simulation iterations, allowing you to quantify risk and uncertainty in your
system.
● Stress Testing: By generating extreme values from the fitted distribution, you can
evaluate how your system behaves under high-stress or rare events, such as peak
demand periods or service interruptions.
This method is an essential tool in both validating the robustness of your simulation and
preparing for unexpected changes in system behaviour.
By fitting distributions to your data and generating new samples, you can create more
realistic and data-driven simulations. This technique allows you to explore future scenarios
with a high degree of confidence, ensuring that your decisions are based on statistically
sound predictions.
Confidence Intervals
A confidence interval provides a range of values within which we can expect the true mean
of the population to lie. This is particularly useful when comparing different scenarios or
systems, as it provides an estimate of the uncertainty in the results.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
78
Confidence intervals provide a more complete understanding of your data by accounting for
uncertainty, making them invaluable when presenting results or making decisions based on
simulation data.
Hypothesis Testing
In simulations, hypothesis testing allows you to compare the performance of different
scenarios and determine whether the observed differences are statistically significant. For
example, you may want to test whether changing a parameter in your system (e.g.,
increasing the number of machines) leads to a significant improvement in processing times.
One of the most common tests is the t-test, which compares the means of two groups to
determine whether they are significantly different.
If the p-value is below a certain threshold (commonly 0.05), you can conclude that there is a
statistically significant difference between the two scenarios.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
79
# Perform a t-test to compare the means
t_stat, p_value = stats.ttest_ind(scenario_a, scenario_b)
By using statistical methods like hypothesis testing and confidence intervals, you can
confidently choose the optimal strategy based on data rather than intuition.
A box plot summarises the distribution of a dataset, showing the median, quartiles, and
outliers. A violin plot goes a step further by illustrating the density of the data, providing a
richer visualisation of the distribution.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
80
[Link]('Box Plot of Processing Times by Stage')
[Link]()
● Central Line (Median): Represents the median (middle value) of the dataset. Half of
the data lies above this line, and half below.
● Box (Interquartile Range - IQR): The box spans from the first quartile (Q1, the 25th
percentile) to the third quartile (Q3, the 75th percentile). This range covers the middle
50% of the data.
● Whiskers: Extend from the box to the smallest and largest values within 1.5 × IQR
from the edges of the box. These lines illustrate the expected range of typical data
values, excluding outliers.
● Outliers: Shown as individual points beyond the whiskers. These are data points
significantly different from other observations.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
81
Here’s what a violin plot represents:
● Width (Density): The width at any given point represents the density (frequency) of
the data at that value. A wider section means more data points are concentrated
there, while narrower sections indicate fewer observations.
● Central Marker (Median or Mean): Often shown as a dot or a small line inside the
violin, this represents the median or mean of the dataset.
● Box and Whisker Inside the Violin (Optional but commonly included in Seaborn):
● Box: Represents the interquartile range (25th to 75th percentile, Q1 to Q3).
● Whiskers: Extend to the largest and smallest values within 1.5 × IQR from the box
edges, showing typical data spread.
● Outliers: Sometimes shown as points beyond whiskers (optional).
Box and violin plots are particularly helpful for comparing multiple groups in your simulation,
such as different stages in a production line or various configurations in a logistics
simulation.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
82
A heatmap is a useful tool for visualising the intensity of data across two dimensions. In the
context of simulations, it can help you understand correlations between variables or highlight
areas where performance issues may arise.
import [Link] as px
data = {
'Machine': ['Machine 1', 'Machine 1', 'Machine 2', 'Machine 2'],
'Product': ['Product 1', 'Product 2', 'Product 1', 'Product 2'],
'Processing Time': [8, 7, 6, 5]
}
df = [Link](data)
fig = [Link]([Link](index='Machine', columns='Product', values='Processing Time'))
fig.update_layout(title='Processing Times by Machine and Product')
[Link]()
By using Plotly, you can create highly interactive visualisations that allow for deeper
exploration of the data. This is ideal for collaborative analysis or for presentations where
stakeholders need to interact with the data themselves.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
83
Time-Series Analysis
Simulations often generate time-based data, such as the time required for entities to pass
through various stages or the waiting times in a queue. Time-series analysis allows you to
visualise these trends over time, helping you identify patterns, peaks, and potential
inefficiencies.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
84
Interactive Dashboards
Interactive dashboards allow you to dynamically explore your simulation data, providing an
intuitive way to filter, drill down, and compare different aspects of your results. Tools like
Dash (built on top of Plotly) and Bokeh are ideal for creating web-based, interactive
dashboards that can be shared with others for further analysis.
import dash
import dash_core_components as dcc
from dash import html
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
85
# Run the Dash application
if __name__ == '__main__':
app.run_server(debug=True)
With Dash, you can build a custom dashboard that visualises key metrics from your
simulation, such as processing times, resource utilisation, or throughput. Interactive features
like sliders, drop-down menus, and real-time updates make it easy to explore different
scenarios or drill down into specific aspects of the simulation.
● Exploratory Data Analysis: By allowing users to interact with the data, these
visualisations make it easier to identify trends, correlations, and outliers that might be
missed in static charts.
● Collaboration: Interactive dashboards can be shared with team members or
stakeholders, facilitating collaborative decision-making based on simulation results.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
86
● Dynamic Exploration: Users can manipulate filters, adjust parameters, and zoom in
on specific areas of interest, providing a more engaging and insightful analysis
experience.
Conclusion
Effectively analysing and visualising simulation data is vital if you want to truly understand
how your systems are performing and make informed decisions. In this chapter, we've
explored a variety of advanced techniques to elevate your approach to simulation analysis.
You've learned to manage and structure complex data sets, apply inferential statistics to
draw meaningful conclusions, and even predict future system behaviours. Essentially, you've
turned raw numbers into practical, actionable insights.
We also covered advanced visualisation techniques using powerful libraries like Seaborn
and Plotly, helping you present your data clearly and convincingly. Whether through
compelling static visuals or interactive dashboards, you now have the tools to effortlessly
communicate trends, compare different scenarios, and emphasise key performance
indicators.
By integrating effective data collection methods, rigorous statistical analysis, and engaging
visualisation strategies, you're well-equipped to deeply understand your simulation results.
This will help you optimise processes, anticipate how changes could impact performance,
and ultimately support smarter, data-driven decision-making.
As you apply these skills in your own simulations, remember: the real power of analysis lies
not merely in collecting data, but in translating it into meaningful insights that genuinely
improve your systems.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
87
Chapter 10 - Monte Carlo Simulation and Full
Factorial Analysis
Now that you have a solid understanding of building and analysing simulations, it’s time to
delve into some more advanced topics. These will push the boundaries of what you can
achieve with SimPy and open the door to even more sophisticated simulations.
Simulate uncertainty with Monte Carlo methods or conduct a full factorial analysis - these
techniques will allow you to handle complex systems and draw deeper insights from your
models.
By running a simulation many times with different random inputs, you can create a
distribution of possible outcomes, helping you understand the range of scenarios your
system might encounter.
For example, let’s say you’re managing a warehouse and you want to simulate the time it
takes to fulfil orders. Some orders may be fulfilled quickly, while others take longer due to
stock shortages or shipping delays. A Monte Carlo simulation would allow you to model this
variability by introducing randomness into the process times and running the simulation
thousands of times to see the distribution of fulfilment times.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
88
Example: A Monte Carlo Simulation in SimPy
Let’s build a simple Monte Carlo simulation of a factory with randomised processing times.
We’ll run the simulation multiple times, each with different random input values, to see the
distribution of total factory processing times.
import simpy
import random
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
89
print(f'Average factory processing time: {sum(monte_carlo_results) /
len(monte_carlo_results):.2f}')
Output:
Average factory processing time: 10.28
For instance, the output might show that the average processing time is 10.2 units, but with
a range that spans from 5 to 15 units. This tells you that, while the system usually performs
within a certain range, there are cases where processing times might be significantly longer
or shorter. With this information, you can make better decisions about resource allocation,
scheduling, and risk management.
● Uncertainty and Variability: When you’re dealing with processes that involve
randomness, Monte Carlo methods allow you to simulate a wide range of possible
outcomes.
● Risk Assessment: By running the simulation multiple times, you can assess the
likelihood of different scenarios, helping you quantify risks and prepare for
unexpected events.
● Decision Support: Monte Carlo simulations allow you to test different strategies under
uncertainty. For example, you could experiment with different resource capacities or
scheduling policies to see how they impact system performance in the face of
random variability.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
90
Here’s how to implement a Monte Carlo simulation in SimPy step by step:
Use Python’s random module to introduce randomness into your processes. This could be
random customer arrival times, processing times, or resource availability. For example, you
might simulate customers arriving at random intervals by using [Link]() to
model exponentially distributed inter-arrival times.
A key feature of Monte Carlo simulations is that they are run multiple times, each with
different random inputs. In SimPy, this is easily done by running the simulation in a loop,
resetting the environment each time.
import simpy
import numpy as np
import pandas as pd
import itertools
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
91
"""
A single job process:
- Arrives at '[Link]' which is recorded as 'arrival_time'.
- Requests the server resource.
- Waits until it can be served.
- After obtaining the server, 'works' for an exponential time.
- Records waiting time and completion time in 'data'.
"""
# Mark the time the job actually arrived in the system.
# (We store it here in case the job gets queued or if there's a waiting line.)
arr_time = arrival_time
completion_time = [Link]
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
92
job_counter += 1
arrival_time = [Link]
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
93
completed_jobs = len(data["job_id"]) # Number of jobs actually served
throughput = completed_jobs / sim_time # jobs per unit time
if completed_jobs > 0:
avg_waiting_time = [Link](data["waiting_time"])
# Time in system = completion_time - arrival_time
times_in_system = [c - a for c, a in zip(data["completion_time"], data["arrival_time"])]
avg_time_in_system = [Link](times_in_system)
else:
avg_waiting_time = 0
avg_time_in_system = 0
return {
"arrival_rate": arrival_rate,
"service_time": service_time,
"queue_capacity": queue_capacity,
"throughput": throughput,
"avg_waiting_time": avg_waiting_time,
"avg_time_in_system": avg_time_in_system,
"lost_jobs": data["lost_jobs"]
}
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
94
# Simple Multivariate Analysis
correlation_matrix = [Link](numeric_only=True)
print("\nCorrelation Matrix:")
print(correlation_matrix)
Output:
Experiment Results:
arrival_rate service_time ... avg_time_in_system lost_jobs
0 0.8 1.0 ... 1.793195 12
1 0.8 1.0 ... 1.116539 0
2 0.8 1.5 ... 2.226897 15
3 0.8 1.5 ... 4.766826 16
4 1.0 1.0 ... 1.491335 18
5 1.0 1.0 ... 2.129484 4
6 1.0 1.5 ... 2.000232 19
7 1.0 1.5 ... 3.887218 1
8 1.2 1.0 ... 1.500817 17
9 1.2 1.0 ... 3.603226 15
10 1.2 1.5 ... 2.988851 43
11 1.2 1.5 ... 5.349550 34
Correlation Matrix:
Correlation Matrix
The correlation matrix is a table that shows us the pairwise linear relationships between all
numerical variables in your dataset. In the final code example, we have columns such as:
● arrival_rate
● service_time
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
95
● queue_capacity
● throughput
● avg_waiting_time
● avg_time_in_system
● lost_jobs
When we call:
correlation_matrix = [Link](numeric_only=True)
Why it is useful
● It gives a quick view of which parameters have the strongest relationships with
each other.
● For example, you might see a strong positive correlation between arrival_rate and
avg_waiting_time (because, as more jobs arrive, queues get longer and waiting
times go up).
● You might see a negative correlation between queue_capacity and lost_jobs
(increasing queue size means fewer dropped jobs).
Caveats
● Correlation ≠ causation. A high positive correlation doesn’t prove that one variable
causes another; it only signals that they tend to vary together in a linear way.
● Non-linear patterns can exist without showing up strongly in a simple correlation.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
96
If your dataset is very small (few data points), correlation values might be unstable. For
better statistical confidence, you’d typically run more simulation replications or gather more
data points at each setting.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
97
The correlation matrix is a powerful way of visualising the relationships at a glance between
variables that make up your full factorial experiment.
For example, you might find that increasing the machine capacity has a much larger effect
on reducing total processing time than changing the processing times, indicating that adding
more machines is a more effective strategy for improving performance.
● Exploring All Combinations: Full factorial analysis allows you to explore every
possible combination of input parameters, ensuring that you fully understand how
different factors interact and affect system performance.
● Identifying Optimal Solutions: By analysing the results of each combination, you can
identify the best configuration for your system and make informed decisions about
resource allocation and process improvements.
● Understanding Interactions: Full factorial analysis highlights interactions between
factors that might not be obvious from single-variable analysis. For example, you
might discover that increasing machine capacity only improves performance when
combined with faster processing times.
Both techniques allow you to push your simulations further, helping you gain deeper insights
into system behaviour and make more informed decisions.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
98
Chapter 11 - Simulation Architecture and
Patterns in SimPy
Choosing the right architecture for your SimPy simulation is crucial for its clarity,
maintainability, and scalability. As your models grow in complexity, a well-thought-out
structure will save you significant time and effort.
In essence, investing a little thought into the architecture upfront is like drawing a good
blueprint before building a house. It prevents your simulation from becoming a "spaghetti
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
99
code" nightmare, making it a more valuable and robust tool for analysis and
decision-making.
This chapter explores three primary architectural approaches for SimPy simulations and a
common, helpful design pattern.
Core Idea: Define behaviors as functions that yield events to the SimPy environment.
Pros:
● Simplicity: Very easy to understand and implement for small models or quick
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
100
prototypes.
● Low Overhead: Minimal boilerplate code.
● Good for Linear Processes: Ideal for simulations with a few, straightforward
sequences of events.
Cons:
● Scalability Issues: Can become difficult to manage as the number of processes and
their interactions grow.
● State Management: Managing the state of many entities can become complex, often
relying on global variables or complex parameter passing, which can lead to tangled
code.
● Reusability: Harder to reuse or extend specific parts of the logic without modification.
When to Pick:
● Small, simple simulations.
● Prototyping ideas quickly.
● Educational examples where the focus is on SimPy basics.
● When entities have minimal state or very distinct, non-overlapping behaviors.
Core Idea: Represent real-world entities as classes. Each instance of a class has its own
state and defined behaviors (processes).
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
101
yield [Link](self.driving_time)
print(f"Car {self.car_id} arrived and starts charging at {[Link]}")
yield [Link](self.charging_duration)
print(f"Car {self.car_id} finished charging at {[Link]}")
# Simulation setup
env = [Link]()
car1 = Car(env, 1, driving_time=5, charging_duration=2)
car2 = Car(env, 2, driving_time=7, charging_duration=3)
[Link](until=20)
Pros:
● Modularity & Encapsulation: Groups data and behavior, making the model easier to
understand, maintain, and debug. Each object manages its own state.
● Scalability: Handles complexity well. Adding more entities or types of entities is
straightforward.
● Reusability: Classes can be easily reused, extended (via inheritance), or composed
to build more complex models.
● Intuitive Mapping: Often provides a natural mapping from real-world systems to
simulation code.
Cons:
● Initial Overhead: Requires more upfront design and boilerplate code compared to
simple functions.
● Potential for Deep Hierarchies: Overuse of inheritance can sometimes lead to
complex class hierarchies that are hard to manage (though composition is often
preferred).
When to Pick:
● Most simulations of moderate to high complexity.
● When modeling systems with multiple interacting entities that have their own state and
distinct behaviors (e.g., machines, customers, vehicles).
● When reusability and extensibility are important.
● When a clear, organized structure reflecting the real-world system is desired.
ECS is an architectural pattern more common in game development but can be adapted for
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
102
complex simulations. It favors composition over inheritance.
● Entities: Are just unique IDs. They don't hold data or logic themselves.
● Components: Are plain data containers (structs or simple classes) that represent a
single aspect or property of an entity (e.g., PositionComponent,
SpeedComponent, EnergyStorageComponent).
● Systems: Are functions or classes that implement the logic. They operate on entities
that possess a specific set of components. For example, a MovementSystem would
update the position of all entities that have both PositionComponent and
SpeedComponent.
In a SimPy context, a "System" could be a SimPy process that queries for entities with
certain components and then enacts behaviors or schedules events for them.
Core Idea: Entities are collections of data components, and systems provide the behavior
based on these components.
Link to Google Colab Notebook for Detailed ECS Gas Station Example
This detailed example demonstrates how to manage entities and their components, and how
systems (as SimPy processes) can operate on these components to drive the simulation
logic. It further explores the advantages and considerations when applying ECS in a SimPy
context.
Pros:
Cons:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
103
● Increased Abstraction: Can be harder to grasp initially compared to OOA, as logic
is spread across systems rather than encapsulated within entity objects.
● Boilerplate: Requires more setup for defining components, entities, and systems.
● SimPy Integration: Not a native SimPy pattern. Requires careful design to integrate
SimPy's process-based nature with ECS (e.g., systems themselves can be SimPy
processes, or they can trigger SimPy processes associated with entities).
● Debugging: Tracing behavior for a single "entity" might involve looking at multiple
systems.
When to Pick:
● Very complex simulations with many diverse entities that share some characteristics
but differ in others.
● When you anticipate needing to add or change behaviors frequently and dynamically.
● If you need to model entities that can gain or lose capabilities (components) during
the simulation.
● Large-scale agent-based models where performance for specific operations across
many entities is critical (though this benefit is less direct in Python/SimPy compared
to C++).
Core Idea: An entity can be in one of a finite number of states. It transitions between states
based on events or conditions. Each state can have associated behaviors.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
104
[Link] = [Link]([Link]())
self.parts_processed = 0
def run(self):
"""Main lifecycle of the machine using FSM logic."""
while True:
if [Link] == 'IDLE':
print(f"Time {[Link]}: Machine {self.machine_id} is IDLE.")
# In a real model, it would wait for a part or a signal to start processing
# For this example, let's simulate it gets a part after a short delay
yield [Link](1)
[Link] = 'PROCESSING'
elif [Link] == 'PROCESSING':
print(f"Time {[Link]}: Machine {self.machine_id} starts PROCESSING part.")
try:
# Process for a certain time, but might break down
yield [Link](self.processing_time) | [Link](self.time_to_fail())
# If processing finished without failure:
if [Link].active_process.triggered_events[0].value is None: # Check if timeout
for processing completed
self.parts_processed += 1
print(f"Time {[Link]}: Machine {self.machine_id} finished
PROCESSING part {self.parts_processed}.")
[Link] = 'IDLE' # Back to idle
else: # Failure occurred
[Link] = 'BROKEN'
except [Link]: # Could be an external interrupt to stop processing
print(f"Time {[Link]}: Machine {self.machine_id} PROCESSING
interrupted.")
[Link] = 'IDLE' # Or some other state
# Check for breakdown (simplified, could be more sophisticated)
# This part is simplified; a more robust way is to have a separate failure process
# or check remaining time_to_fail against processing_time.
# For this example, we assume the timeout combination handles it.
elif [Link] == 'BROKEN':
print(f"Time {[Link]}: Machine {self.machine_id} is BROKEN.")
yield [Link](self.repair_time)
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
105
print(f"Time {[Link]}: Machine {self.machine_id} is REPAIRED.")
[Link] = 'IDLE' # Back to idle after repair
else:
print(f"Error: Machine {self.machine_id} in unknown state: {[Link]}")
yield [Link](99999) # Halt
def time_to_next_failure():
# Example: time to failure is exponentially distributed
import random
return [Link](1/10) # Average time to failure: 10 time units
# Simulation Setup
env = [Link]()
machine1 = Machine(env, "M1", processing_time=3, repair_time=5,
time_to_fail=time_to_next_failure)
# To make it more interesting, let's add another machine
# machine2 = Machine(env, "M2", processing_time=2, repair_time=7,
time_to_fail=time_to_next_failure)
[Link](until=30)
Note: The FSM example above uses a simplified way to handle combined processing and
failure. A more robust FSM might use env.any_of() for competing events or have separate
SimPy processes for failure generation that interrupt the main process.
Pros:
● Clarity: Makes complex entity logic explicit and easier to follow by clearly defining
states and transitions.
● Manageability: Helps manage entities that have distinct modes of operation.
● Reduced Errors: Reduces the chance of logical errors from deeply nested if/else
statements by formalizing state changes.
● Debugging: Easier to debug because you can often pinpoint issues to a specific state
or transition.
Cons:
● State Explosion: For entities with many possible states and complex transitions, the
FSM itself can become complicated.
● Overhead for Simple Entities: Can be overkill for entities with very simple, linear
behavior.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
106
When to Pick:
● When an entity's behavior changes significantly based on its current condition or mode
of operation.
● For modeling entities with lifecycles (e.g., patient in a hospital, part in a manufacturing
line, task in a workflow).
● To manage complex conditional logic within an entity's process.
● Commonly used within an Object-Oriented Architecture.
● Basic Processes are great for getting started and for simple models.
● Object-Oriented Architecture offers a robust and scalable approach for most
non-trivial simulations, providing a natural way to model real-world entities.
● Entity Component Systems, while requiring more setup, offer maximum flexibility for
highly complex and dynamic models where entities have many overlapping but distinct
characteristics.
● Finite State Machines are a valuable pattern to manage internal states and
transitions within your entities, often used in conjunction with OOA.
Understanding these architectures and patterns will empower you to build more effective,
maintainable, and understandable SimPy simulations. As your models evolve, don't be afraid
to refactor or adopt a more structured approach if your initial choice becomes limiting.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
107
Chapter 12 - Final Thoughts and Next Steps
As we wrap up this book, now’s a good moment to pause and reflect - not just because you
deserve a break, but also because applying what you've learned is key to making all this
knowledge stick.
By this point, you've built a strong foundation in modelling and simulation using Python and
SimPy. You can confidently create detailed simulations, manage resources effectively, and
dig into data analysis to make informed decisions. But let's be honest: this is really just the
beginning.
Reflecting on Your JourneyOver the course of this book, you've moved from grasping the
basics of discrete-event simulation to mastering advanced topics like Monte Carlo
simulations and factorial analysis.
What’s Next?
If you've enjoyed getting stuck into simulations and want to keep pushing your skills further,
there’s plenty more to explore. Here are a few areas worth diving into, all of which I cover in
more depth in my School of Simulation course:
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
108
● Advanced Simulation Techniques: Go beyond the basics by mastering techniques
like PriorityStores, FilterStores interrupts, and conditional events to tackle complex
real-world challenges.
● Visual Modelling and Stakeholder Engagement: Learn how to transform stakeholder
insights and requirements into actionable simulation models using visual mapping
techniques - essential for getting your simulations right first time.
● Simulation Project Management: Building a great simulation is only part of the job.
Develop the skills to scope, manage, and deliver high-impact projects, communicate
effectively with stakeholders, and present results clearly.
● Optimisation and Automation: Use optimisation methods such as genetic algorithms
and simulated annealing to fine-tune your models, ensuring they deliver maximum
value with minimal fuss.
● Interactive and Animated Simulations: Discover how to bring your simulations to life
with dynamic animations, making complex scenarios easy to understand and
engaging to stakeholders.
Here’s how you can practically start applying your new skills:
Start Small: Pick manageable projects to build confidence and finesse your skills. A small
success beats a big, ambitious failure - every time.
Collaborate: Good simulations often involve teamwork. Work with colleagues or experts who
can provide real-world context, better data, or just sanity checks.
Use Simulation for Decision-Making: Next time you're facing an important decision - like
launching a new product or changing a process - let your simulations do the heavy lifting.
Keep Learning: Simulation is constantly evolving, so stay curious. Join online communities,
attend conferences, or keep up with new research to stay ahead of the curve.
Final Thoughts
Remember, simulation isn't just numbers and algorithms. It's also an art. Combining
technical know-how with a practical understanding of real-world systems makes you
uniquely capable of solving challenging problems.
Thank you for taking this journey into simulation with Python and SimPy. Hopefully, this book
has sparked your curiosity and given you the confidence to dive deeper into this fascinating
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
109
field. Every system is a potential simulation waiting to be built - and every simulation is a
step toward a smarter solution.
If you fancy joining my free webinar, “How to Become a Go-To Expert in Simulation with
Python,” you can register at: [Link]
P.s. if you found this guide helpful, I’d be so grateful for a review on Goodreads:
[Link]
Thank you!
- Harry
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
110
About Harry Munro
I've been working with simulation for over 14 years across all sorts of industries, from
transport to mining to defence to energy.
Simulation is the beating heart of everything I do. It's how I 10x'd my annual earnings and
achieved financial freedom. It's how I enjoy a fully flexible, remote lifestyle. And it's why
people seek me out from all over the world for help with their modelling and simulation
projects.
My work has never been dull: from individual contributor to team lead, tech lead, business
owner and consultant. This allows me to bring a unique perspective to training and coaching
others.
Based in Bermuda, I enjoy rum-fuelled island life with my beautiful wife and son, while
helping others to create their own success stories.
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
111
P.s. If you would like to join my complimentary free masterclass “How to Become a Go-To
Expert in Simulation with Python” you can register for access here:
[Link]
Join My Free Masterclass “How to Become a Go-To Expert in Simulation with Python”
© 2025 Aspegio Ltd
112