218 lines
7.3 KiB
Python
218 lines
7.3 KiB
Python
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()
|
|
|
|
|
|
|
|
|
|
|