|
| 1 | +from vidigi.logging import EventLogger |
| 2 | +from vidigi.utils import EventPosition, create_event_position_df |
| 3 | +from vidigi.animation import animate_activity_log, generate_animation |
| 4 | +from vidigi.prep import generate_animation_df, reshape_for_animations |
| 5 | +from vidigi.resources import VidigiStore |
| 6 | +import simpy |
| 7 | +import numpy as np |
| 8 | + |
| 9 | +class g: |
| 10 | + n_cubicles =5 |
| 11 | + |
| 12 | +class Patient: |
| 13 | + def __init__(self, p_id): |
| 14 | + self.id = p_id |
| 15 | + |
| 16 | +class SimpleActivityModel: |
| 17 | + def __init__(self, master_seed=42): |
| 18 | + self.env = simpy.Environment() |
| 19 | + self.patient_counter = 0 |
| 20 | + self.patient_inter = 2 |
| 21 | + self.logger = EventLogger(env=self.env) |
| 22 | + |
| 23 | + # Seed setup using numpy's SeedSequence |
| 24 | + self.master_seed = master_seed |
| 25 | + self.seed_seq = np.random.SeedSequence(master_seed) |
| 26 | + self.rng = np.random.default_rng(self.seed_seq) |
| 27 | + |
| 28 | + self.cubicles = VidigiStore(self.env, num_resources=g.n_cubicles) |
| 29 | + |
| 30 | + def generate_arrivals(self): |
| 31 | + while True: |
| 32 | + self.patient_counter += 1 |
| 33 | + p = Patient(self.patient_counter) |
| 34 | + self.logger.log_arrival(entity_id=p.id) |
| 35 | + self.env.process(self.patient_journey(p)) |
| 36 | + sampled_inter = self.rng.exponential(scale=self.patient_inter) |
| 37 | + yield self.env.timeout(sampled_inter) |
| 38 | + |
| 39 | + def patient_journey(self, patient): |
| 40 | + self.logger.log_queue(entity_id=patient.id, event="wait_here") |
| 41 | + |
| 42 | + with self.cubicles.request() as req: |
| 43 | + cubicle = yield req |
| 44 | + |
| 45 | + self.logger.log_resource_use_start( |
| 46 | + entity_id=patient.id, |
| 47 | + event="start_treatment", |
| 48 | + resource_id=cubicle.id_attribute |
| 49 | + ) |
| 50 | + |
| 51 | + yield self.env.timeout(self.rng.uniform(low=1, high=10)) |
| 52 | + |
| 53 | + self.logger.log_resource_use_end( |
| 54 | + entity_id=patient.id, |
| 55 | + event="end_treatment", |
| 56 | + resource_id=cubicle.id_attribute |
| 57 | + ) |
| 58 | + |
| 59 | + self.logger.log_departure(entity_id=patient.id) |
| 60 | + |
| 61 | + def run(self): |
| 62 | + self.env.process(self.generate_arrivals()) |
| 63 | + self.env.run(until=180) |
| 64 | + |
| 65 | +model = SimpleActivityModel() |
| 66 | +model.run() |
| 67 | +event_log = model.logger.to_dataframe() |
| 68 | +# event_log.to_csv("test_log.csv") |
| 69 | + |
| 70 | +event_position_df = create_event_position_df([ |
| 71 | + EventPosition(event="wait_here", x=150 , y=150 , label="Wait Here!"), |
| 72 | + EventPosition(event="start_treatment", x=150 , y=75 , resource="n_cubicles", label="Be Treated"), |
| 73 | + EventPosition(event="depart", x=150, y=5, label="Exit") |
| 74 | + ]) |
| 75 | + |
| 76 | +animate_activity_log( |
| 77 | + event_log = event_log, |
| 78 | + event_position_df = event_position_df, |
| 79 | + scenario=g(), |
| 80 | + every_x_time_units=1, |
| 81 | + limit_duration=60, |
| 82 | + override_x_max=300, |
| 83 | + override_y_max=250, |
| 84 | + plotly_height=600, |
| 85 | + plotly_width=1100, |
| 86 | + display_stage_labels=True, |
| 87 | + gap_between_entities=20, |
| 88 | + entity_icon_size=40, |
| 89 | + wrap_queues_at=10, |
| 90 | + gap_between_resources=30, |
| 91 | + gap_between_queue_rows=30, |
| 92 | + resource_icon_size=80, |
| 93 | + simulation_time_unit="minutes", |
| 94 | + custom_resource_icon="☐", |
| 95 | + resource_opacity=0.7, |
| 96 | + debug_write_intermediate_objects=True |
| 97 | +).update_layout( |
| 98 | + plot_bgcolor='white', |
| 99 | + ) |
0 commit comments