A discrete-event simulation of an Emergency Department (ED) with triage and two-tier doctor staffing (Junior/Senior doctors). Built with Python, SimPy for simulation engine, Streamlit for UI, and Altair for interactive visualization.
This simulation is built using SimPy, a process-based discrete-event simulation framework for Python. SimPy provides:
- Process-based simulation: Components are modeled as Python generator functions
- Shared resources: Limited capacity resources like servers and queues
- Event-driven architecture: Discrete events drive the simulation forward
- Flexible timing: Simulations can run as fast as possible or in real-time
- Resource management: Built-in handling of resource allocation and queuing
SimPy is ideal for modeling complex systems with interacting components, making it perfect for healthcare operations research and queue management simulations.
- Two-tier doctor system: Junior and Senior doctors with different capabilities
- Patient classification: Configurable percentage of patients requiring Senior doctors only
- Time-varying arrivals: Customizable arrival patterns by hour
- Queue management: Triage → Doctor flow with multiple queues
- Patience modeling: Patients leave without being seen (LWBS) if they wait too long
- Cost analysis: Doctor staffing costs and scenario comparison
- Interactive UI: Streamlit-based interface with real-time parameter adjustment
- Multiple scenarios: Compare different staffing configurations
- Statistical analysis: Multiple replications with confidence intervals
- Professional simulation engine: Built on SimPy for robust discrete-event simulation
The demo includes three predefined scenarios to demonstrate different staffing strategies:
- Staffing: 1 triage nurse, 3 junior doctors, 1 senior doctor
- Purpose: Establish baseline performance metrics
- Use Case: Typical ED staffing for moderate patient volume
- Expected Outcomes: Balanced wait times and costs
- Staffing: 1 triage nurse, 4 junior doctors, 1 senior doctor
- Purpose: Test impact of additional junior doctor capacity
- Use Case: High volume of general patients
- Expected Outcomes: Reduced wait times for general patients, moderate cost increase
- Staffing: 1 triage nurse, 3 junior doctors, 2 senior doctors
- Purpose: Test impact of additional senior doctor capacity
- Use Case: High percentage of complex cases requiring senior doctors
- Expected Outcomes: Reduced wait times for senior-only patients, higher cost
Users can create custom scenarios to test specific staffing configurations:
- Triage Bays: Number of triage assessment stations
- Junior Doctors: Number of junior doctors on shift
- Senior Doctors: Number of senior doctors on shift
- Scenario Naming: Descriptive names for easy identification
Each scenario is evaluated using multiple performance indicators:
- Wait Times: Average wait to see doctor (overall and senior-only)
- Length of Stay: Total time from arrival to discharge
- Utilization: Percentage of time staff are busy
- LWBS Rate: Patients who left without being seen
- Cost Analysis: Total staffing costs per shift
- Efficiency: Wait-time-to-cost ratio
- Arrivals: Time-varying Poisson arrivals by hour
- Triage: Exponential service times, configurable number of bays
- Routing: Patients are classified as "senior-only" or "general"
- Doctor queues:
- Senior-only queue (must see senior doctor)
- General queue (can see junior or senior)
- Service: Senior doctors prioritize senior-only patients, then general
- Patience: Patients leave if they wait beyond the threshold
- Arrival pattern: Comma-separated arrivals per hour
- Service times: Exponential distribution with configurable means
- Senior-only share: Percentage of patients requiring senior doctors
- Patience threshold: Maximum wait time before LWBS
- Staffing: Number of triage bays, junior doctors, senior doctors
- Costs: Per-shift costs for junior and senior doctors
simulation-python/
├── simulation.py # Core simulation logic using SimPy
├── app.py # Streamlit UI application
├── requirements.txt # Python dependencies
├── test_simulation.py # Unit tests and validation
└── README.md # This file
The main simulation class that encapsulates all SimPy components:
class EmergencyDepartmentSimulation:
"""
Emergency Department simulation environment using SimPy.
Key components:
- SimPy Environment: Controls simulation timing and events
- Resources: Triage nurses, junior doctors, senior doctors
- Stores: Patient queues for different types
- Processes: Patient journey, doctor service processes
"""Key Methods:
__init__(): Initialize SimPy environment and resourcesprocess_patient_journey(): Simulate individual patient flowsenior_doctor_service_process(): Senior doctor service logicjunior_doctor_service_process(): Junior doctor service logicrun_simulation(): Execute complete simulation
-
Resources:
triage_nurses,junior_doctors,senior_doctors- Limited capacity staff members
- Automatic queuing when busy
- Utilization tracking
-
Stores:
senior_only_patient_queue,general_patient_queue- Patient waiting areas
- Priority-based service (senior-only first)
- Patience checking and LWBS handling
Each component is modeled as a SimPy process:
def process_patient_journey(self, patient_id, arrival_time, requires_senior_doctor):
"""Patient flow: Arrival → Triage → Doctor Queue → Treatment → Discharge"""
# Phase 1: Triage Assessment
with self.triage_nurses.request() as triage_request:
yield triage_request
# ... triage service time
# Phase 2: Route to appropriate doctor queue
if requires_senior_doctor:
yield self.senior_only_patient_queue.put(patient_data)
else:
yield self.general_patient_queue.put(patient_data)- Multiple Replications: Configurable number of simulation runs
- Aggregation: Mean values across replications
- Confidence Intervals: Statistical reliability
- Performance Metrics: Comprehensive KPIs
- Sidebar Controls: All simulation parameters
- Real-time Validation: Input validation and help text
- Preset Values: Sensible defaults for quick start
- Default Scenarios: Pre-configured staffing options
- Custom Scenarios: User-defined configurations
- Interactive Editing: Direct table editing
- Wait Time Analysis: Comparison charts and tables
- Cost Analysis: Staffing costs and comparisons
- Efficiency Analysis: Scatter plots and trade-offs
- Performance Indicators: Summary metrics and KPIs
Main entry point for single simulation runs:
def simulate_ed_two_classes(simulation_config: Dict, random_seed: int = 1) -> Dict:
"""Create and run ED simulation, return performance metrics"""Execute multiple replications for statistical confidence:
def run_simulation_with_replications(simulation_config, number_of_replications,
starting_seed, junior_doctor_cost, senior_doctor_cost):
"""Run multiple simulations and aggregate results"""Convert CSV arrival patterns to simulation-ready format:
def parse_arrivals(arrival_csv_string: str, simulation_hours: int, volume_multiplier: float):
"""Parse and scale arrival rates for simulation"""- Clone or download the repository
- Install dependencies:
pip install -r requirements.txt
Run the Streamlit app:
streamlit run app.pyThe app will open in your browser at http://localhost:8501.
-
Set Global Parameters (sidebar):
- Simulation horizon (hours)
- Arrival pattern and scale
- Service time means
- Senior-only patient share
- Patience threshold
- Number of replications
- Doctor costs
-
Manage Scenarios:
- Edit existing scenarios in the table
- Add new scenarios with the form
- Each scenario defines triage bays, junior doctors, and senior doctors
-
Run Simulation:
- Click "Run Simulation" to execute all scenarios
- View results table with key metrics
- Analyze comparison charts
- Download results as CSV
- Simulation type: Discrete-event simulation using SimPy
- Random number generation: Configurable seed for reproducibility
- Statistical analysis: Multiple replications for confidence
- Data visualization: Altair charts for interactive exploration
- Export: CSV download for further analysis
- Simulation engine: SimPy provides robust resource management and process scheduling
You can easily modify the simulation by:
- Adjusting the arrival patterns in the sidebar
- Creating new scenarios with different staffing levels
- Modifying service time distributions in
simulation.py - Adding new metrics or cost calculations
- Extending the UI with additional visualizations
- Leveraging SimPy's advanced features for complex scenarios
- Python 3.8+
- SimPy 3.0+
- Streamlit 1.28+
- Altair 5.0+
- Pandas 2.0+
- NumPy 1.24+