import salabim as sim from numpy.random import normal from math import exp import numpy as np def delay(duration, percentage_variation): stdev = percentage_variation / 100.0 * duration random_additive_noise = normal(0, stdev) return max(0, int(duration + random_additive_noise)) class Crane(sim.Component): def __init__(self, name, duration, env, debug=True,*args, **kwargs): sim.Component.__init__(self, *args, **kwargs) self.name=name self.duration = duration self.debug = debug self.env = env def process(self): if self.debug: print(self.name + ": input") self.enter(pl) if self.debug: print(self.name + ": go_forward") #self.logger.addMessage(self.name + " FORWARD"); self.state = "running" yield self.hold(delay(self.duration, 1)) if self.debug: print(self.name + ": wait") self.state = "waiting" if self.debug: print(self.name + ": item_taken") print(self.name + ": go_back") #self.logger.addMessage(self.name + " BACKWARD"); yield self.hold(delay(self.duration, 1)) if self.debug: print(self.name + ": stop") self.leave(pl) #self.logger.addMessage(self.name + " STOP"); class BowlFeeder(sim.Component): def __init__(self, name, duration, env, debug=True,*args, **kwargs): sim.Component.__init__(self, *args, **kwargs) self.debug = debug self.duration = duration self.name = name self.state = "waiting" self.env = env self.faults = [] def add_fault(self, fault): yield self.hold(0) self.faults.append(fault) def process(self): if self.debug: print(self.name + ": give") self.enter(pl) self.state = "giving" yield self.hold(delay(self.duration, 1)) for fault in self.faults: print('FAULT') if self.debug: print(self.name + ": given") self.leave(pl) self.state = "waiting" class Conveyor(sim.Component): def __init__(self, name, duration, env, debug=True,*args, **kwargs): sim.Component.__init__(self, *args, **kwargs) self.debug = debug self.duration = duration self.name = name self.env = env self.faults = [] def add_fault(self, fault): self.faults.append(fault) def process(self): if self.debug: print(self.name + ": input") self.enter(pl) yield self.hold(delay(self.duration, 1)) for fault in self.faults: print('FAULT') if self.debug: print(self.name + ": to_next_step") self.leave(pl) class ManualStep(sim.Component): def __init__(self, name, duration, env, debug=True,*args, **kwargs): sim.Component.__init__(self, *args, **kwargs) self.debug = debug self.duration = duration self.state = "waiting" self.name = name self.env = env self.queue = 0 def process(self): if self.debug: print(self.name + ": input") self.enter(pl) self.queue = self.queue + 1 if (self.queue >= 5): print("QUEUE_ALARM"); if self.debug: print(self.name + ": process") self.queue = self.queue - 1 self.state = "running" yield self.hold(delay(self.duration, 5)) if self.debug: print(self.name + ": ok") if self.debug: print(self.name + ": wait") self.leave(pl) self.state = "waiting" class RetryDelay(sim.Component): def __init__(self, env, debug=True,*args, **kwargs): sim.Component.__init__(self, *args, **kwargs) self.debug = debug self.t = 0 self.env = env def process(self): self.t = self.t + 1 delay_factor = np.random.poisson((exp(self.t/5)-1)/4) * 0.2 if self.debug: print("FAULT: RETRY_DELAY: ", delay_factor) yield self.hold(self.add_delay(2, delay_factor)) def add_delay(self, delay, delay_factor): return delay * delay_factor class ProductionLine(): def __init__(self,env): self.env = env self.crane1 = Crane("CRANE1", 3, env) self.manual_inspection = ManualStep("MANUAL_INSPECTION", 3, env) self.conveyor1 = Conveyor("CONVEYOR1", 3, env) self.bowl1 = BowlFeeder("BOWL1", 5, env) self.manual_add_components1 = ManualStep("MANUAL_ADD_COMPONENTS1", 2.1, env) self.conveyor2 = Conveyor("CONVEYOR2", 3, env) self.bowl2 = BowlFeeder("BOWL2", 1, env) self.bowl2.add_fault(RetryDelay(env,self.bowl2)) self.manual_add_components2 = ManualStep("MANUAL_ADD_COMPONENTS2", 3, env) self.conveyor3 = Conveyor("CONVEYOR3", 3, env) self.crane_input_subassembly_a = Crane("CRANE_INPUT_SUBASSEMBLY_A", 1, env) self.manual_combine_subassembly_a = ManualStep("MANUAL_COMBINE_SUBASSEMBLY_A", 3.4, env) self.conveyor4 = Conveyor("CONVEYOR4", 3, env) self.conveyor_input_subassembly_b = Conveyor("CONVEYOR_INPUT_SUBASSEMBLY_B", 1, env) self.manual_combine_subassembly_b = ManualStep("MANUAL_COMBINE_SUBASSEMBLY_B", 3.5, env) self.conveyor5 = Conveyor("CONVEYOR5", 3, env) self.bowl3 = BowlFeeder("BOWL3", 5, env) self.conveyor6 = Conveyor("CONVEYOR6", 1, env) self.manual_add_cover_and_bolts = ManualStep("MANUAL_ADD_COVER_AND_BOLTS", 7, env) self.conveyor7 = Conveyor("CONVEYOR7", 3, env) self.manual_tighten_bolts1 = ManualStep("MANUAL_TIGHTEN_BOLTS1", 2, env) self.conveyor8 = Conveyor("CONVEYOR8", 3, env) self.conveyor_input_subassembly_c = Conveyor("CONVEYOR_INPUT_SUBASSEMBLY_C", 1, env) self.manual_combine_subassembly_c = ManualStep("MANUAL_COMBINE_SUBASSEMBLY_C", 6, env) self.conveyor9 = Conveyor("CONVEYOR9", 2, env) self.manual_tighten_bolts2 = ManualStep("MANUAL_TIGHTEN_BOLTS2", 1, env) self.conveyor10 = Conveyor("CONVEYOR10", 2, env) self.bowl4 = BowlFeeder("BOWL4", 5, env) self.manual_add_components3 = ManualStep("MANUAL_ADD_COMPONENTS3", 1, env) self.conveyor11 = Conveyor("CONVEYOR11", 2, env) self.manual_tighten_bolts3 = ManualStep("MANUAL_TIGHTEN_BOLTS3", 3, env) env = sim.Environment() production_line = ProductionLine(env) pl = sim.Queue('pl') env.background_color('20%gray') env.modelname('FAS queue animation') pl1 = sim.AnimateQueue(pl, x=100, y=300, title='queue, normal', direction='e') pl2 = sim.AnimateQueue(pl, x=100, y=220, title='queue, maximum 6 components', direction='e', max_length=6) pl3 = sim.AnimateQueue(pl, x=100, y=140, title='queue, reversed', direction='e', reverse=True) sim.AnimateMonitor(pl.length, x=10, y=450, width=480, height=100, horizontal_scale=5, vertical_scale=5) sim.AnimateMonitor(pl.length_of_stay, x=10, y=570, width=480, height=100, horizontal_scale=5, vertical_scale=5) sim.AnimateText(text=lambda: pl.length.print_histogram(as_str=True), x=500, y=700,text_anchor='nw', font='narrow', fontsize=10) #sim.AnimateText(text=lambda: pl.print_info(as_str=True), x=500, y=340,text_anchor='nw', font='narrow', fontsize=10) env.animate(True) env.run(till=20) print("Done.") #pl.print_statistics() pl.length_of_stay.print_statistics()