import simpy
import pandas as pd
import random
from vidigi.animation import animate_activity_log
from vidigi.logging import EventLogger
from vidigi.utils import EventPosition, create_event_position_df
from vidigi.resources import VidigiStore
A slightly more complex example with multiple servers
When dealing with multiple servers, we need to have a way to monitor which resource is in use. This is where vidigi’s custom resource classes come in, such as VidigiStore.
VidigiStore is designed to mimic the Resource class in Simpy - so you can continue to use the same patterns of resource requesting you are familiar with.
Step 1. Import required libraries
vidigi
simpy
- for simulation model (or see the Ciw functions and examples elsewhere in this documentation)random
- for generating random arrivalspandas
- for managing dataframes
Step 2. Set up simulation parameters
# Simple simulation parameters
= 50
SIM_DURATION = 3
NUM_SERVERS = 4.0
ARRIVAL_RATE = 3.0 SERVICE_TIME
Step 3. Write model code with event logs
Create a simple simulation model using simpy
.
On the left is a basic simpy
model. If not familiar check out simpy
documentation for intro to simpy.
On the right is how we incorporate vidigi
. Information for vidigi
collected in a list of dictionaries which we will convert into a dataframe. You need a arrival_departure
event.
Simple SimPy Model
def patient_generator(env, server, event_log):
"""Generate patients arriving at the shop"""
= 0
patient_id
while True:
+= 1
patient_id
# Start the patient process
env.process(patient_process(env, patient_id, server, event_log))
# Wait for next arrival
yield env.timeout(random.expovariate(ARRIVAL_RATE))
def patient_process(env, patient_id, server, event_log):
"""Process a single patient through the system"""
# Request server
with server.request() as request:
yield request
# Service time
= random.expovariate(1.0/SERVICE_TIME)
service_duration yield env.timeout(service_duration)
# Run the simulation
def run_simulation():
= simpy.Environment()
env = simpy.Resource(env, capacity=NUM_SERVERS)
server = []
event_log
# Start patient generator
env.process(patient_generator(env, server, event_log))
# Run simulation
=SIM_DURATION) env.run(until
With Vidigi Modifications
class Params:
def __init__(self):
self.num_servers = 3
def patient_generator(env, servers, logger):
"""Generate patients arriving at the shop"""
= 0
patient_id
while True:
+= 1
patient_id
# Log arrival
=patient_id)
logger.log_arrival(entity_id
# Start the patient process
env.process(patient_process(env, patient_id, servers, logger))
# Wait for next arrival
yield env.timeout(random.expovariate(ARRIVAL_RATE))
def patient_process(env, patient_id, servers, logger):
"""Process a single patient through the system"""
# Log start of queue wait
=patient_id, event='queue_wait_begins')
logger.log_queue(entity_id
# Request server
with servers.request() as request:
= yield request
server
# Log service start
=patient_id, event="service_begins", resource_id=server.id_attribute)
logger.log_resource_use_start(entity_id
# Service time
= random.expovariate(1.0/SERVICE_TIME)
service_duration yield env.timeout(service_duration)
# Log service start
=patient_id, event="service_complete", resource_id=server.id_attribute)
logger.log_resource_use_end(entity_id
# Log departure
=patient_id)
logger.log_departure(entity_id
# Run the simulation
def run_simulation():
= Params()
params = simpy.Environment()
env = VidigiStore(env=env, num_resources=params.num_servers)
servers = EventLogger(env=env)
logger
# Start patient generator
env.process(patient_generator(env, servers, logger))
# Run simulation
=SIM_DURATION)
env.run(until
return logger.to_dataframe()
Step 4. Run simulation
# Run simulation and get event log
= run_simulation()
event_log_df print(f"Generated {len(event_log_df)} events")
Generated 546 events
Step 5. Create event positions dataframe
# Define positions for animation
= create_event_position_df([
event_positions ='arrival', x=0, y=350, label="Entrance"),
EventPosition(event='queue_wait_begins', x=250, y=250, label="Queue"),
EventPosition(event='service_begins', x=250, y=150, resource='num_servers', label="Being Served"),
EventPosition(event='depart', x=250, y=50, label="Exit")
EventPosition(event ])
Step 6. Create animation
Explaining:
plotly_height
andplotly_width
override_x_max
andoverride_y_max
setup_mode
every_x_time_units
We pass our Params() class in so that vidigi knows the number of resource icons it needs to generate.
# Create animation
animate_activity_log(=event_log_df,
event_log=event_positions,
event_position_df=Params(),
scenario=1,
every_x_time_units=600,
plotly_height=360,
override_x_max=SIM_DURATION
limit_duration )