I have been having problems with the simulation I have built and I am not sure how I can go about solving them. The idea of this simulation is as follows:
There are a total of 10 machines in the system. When the simulation starts, 6 of the machines will begin working, while the other 4 machines will be kept in an inventory as spares.
The requirement is that at any one time in the system, there should be 6 machines working. Any amount of time when there aren't a total of 6 machines working will be counted as downtime.
After some time of working, one of the 6 working machines will fail. When this failure event occurs, we will take 1 machine from the inventory and add it to the group of working machines, so that we can fulfill the requirement of having 6 machines working at any one time.
The failed machine will then be sent to a repair workshop and be repaired after a certain amount of time. When its repair finishes, it will be moved to the inventory where it will join the other machines.
The next time another one of the 6 working machine fails, 1 machine will be taken from the inventory again to replace the failed one. This means that the number of machines inside the inventory will constantly be fluctuating throughout the simulation. Throughout the simulation, I also need to how many machines are there inside the inventory, thus I have added print
statements to show me that.
In summary, a machine will go through the following loop: starts working -> fails -> sent to repair workshop -> after repair, placed in inventory -> gets pulled into operation again when another machine fails -> starts working -> fails .. etc.
Another requirement that I have in this simulation is that I need know where Machine 1 to 10 is at any one time. This is so that I can trace the movement of each machine, such as for example, when does machine 7 fail, when does it enter and leave the repair workshop, when does it enter and leave the inventory etc.
After this simulation is built, I will subsequently be varying the initial number of spares and the repair time to study how these factors affect the level of operational availability.
The main problems I am facing:
I am unable to trace each of the 10 machines individually through the entire cycle
I am unable to properly model my spares inventory. If machines 5 - 10 are in operation at the beginning, when one of them fails, the next line of output should tell me that machine 1 has been taken from the inventory (and thus begins operating) to replace the failed one. However, I am unable to get such an output.
Thank you in advance!
I have included my progress so far:
import simpy
import random
RANDOM_SEED = 42
NUM_SERVERS = 2
MTBF = 10
MTTR = 2
TOTAL_MACHINES = 10
TOTAL_SPARES = 4
TOTAL_WORKING = TOTAL_MACHINES - TOTAL_SPARES
SIM_TIME = 100
class Working(object):
def __init__ (self, env, num, repair_workshop, spares_inventory, downtime):
self.env = env
self.repair_workshop = repair_workshop
self.spares_inventory = spares_inventory
self.downtime = downtime
self.name = 'Machine %d' % (num + 1)
print('%s begins working %.2f' % (self.name, self.env.now))
self.env.process(self.run())
def run(self):
yield self.env.timeout(random.expovariate(1.0 / MTBF))
print('%s stops working %.2f' % (self.name, self.env.now))
downtime_start = self.env.now
spare = yield self.spares_inventory.get(1)
self.downtime.append(self.env.now - downtime_start)
print('%s taken from inventory at %.2f' % (spare.name, self.env.now))
print('%d inside inventory' % len(spares_inventory.items))
with self.repair_workshop.request() as req:
yield req
print('%s starts repair %.2f' % (self.name, self.env.now))
yield self.env.timeout(random.expovariate(1.0 / MTTR))
yield self.spares_inventory.put(1)
print('%s finishes repair at %.2f' % (self.name, self.env.now))
print(' %d inside inventory' % len(spares_inventory.items))
def main():
env = simpy.Environment()
repair_workshop = simpy.Resource(env, capacity = NUM_SERVERS)
spares_inventory = simpy.Container(env, capacity = TOTAL_MACHINES, init = TOTAL_SPARES)
downtime = []
working = [Working(env, i, repair_workshop, spares_inventory, downtime) for i in range(TOTAL_WORKING)]
env.run(SIM_TIME)
print('Total downtime for all machines throughout simulation time is %.2f hours' % sum(downtime))
print('Operational Availability = %.2f percent' % ( (SIM_TIME - sum(downtime)) * 100 / (SIM_TIME)))
if __name__ == '__main__':
main()
With Stefan's help, I have modified my script:
class Working(object):
def __init__ (self, env, num, repair_workshop, spares_inventory, downtime, machine):
self.env = env
self.repair_workshop = repair_workshop
self.spares_inventory = spares_inventory
self.downtime = downtime
self.machine = machine
self.name = ('Machine %d' % (num + 1))
print('%s begins working %.2f' % (self.name, self.env.now))
self.env.process(self.run())
def run(self):
yield self.env.timeout(random.expovariate(1.0 / MTBF))
print('%s stops working %.2f' % (self.name, self.env.now))
downtime_start = self.env.now
spare = yield self.spares_inventory.get(1)
self.downtime.append(self.env.now - downtime_start)
print('%s taken from inventory at %.2f' % (spare.name, self.env.now))
print('%d inside inventory' % len(spares_inventory.items))
with self.repair_workshop.request() as req:
yield req
print('%s starts repair %.2f' % (self.name, self.env.now))
yield self.env.timeout(random.expovariate(1.0 / MTTR))
yield self.spares_inventory.put(1)
print('%s finishes repair at %.2f' % (self.name, self.env.now))
print(' %d inside inventory' % len(spares_inventory.items))
def main():
env = simpy.Environment()
repair_workshop = simpy.Resource(env, capacity = NUM_SERVERS)
downtime = []
machines = [object() for i in range(TOTAL_MACHINES)]
working, spares = machines[:TOTAL_WORKING], machines[TOTAL_WORKING:]
spares_inventory = simpy.Store(env, capacity = TOTAL_MACHINES)
spares_inventory.items = spares
working = [Working(env, i, repair_workshop, spares_inventory, downtime, machine) for i, machine in enumerate(working)]
env.run(SIM_TIME)
print('Total downtime for all machines throughout simulation time is %.2f hours' % sum(downtime))
print('Operational Availability = %.2f percent' % ( (SIM_TIME - sum(downtime)) * 100 / (SIM_TIME)))
if __name__ == '__main__':
main()
This is the traceback I have received:
Traceback (most recent call last):
File "/Users/Scripts/8oct1.py", line 70, in <module> main()
File "/Users/Scripts/8oct1.py", line 64, in main env.run(SIM_TIME)
File "/Library/Python/2.7/site-packages/simpy/core.py", line 120, in run self.step()
File "/Library/Python/2.7/site-packages/simpy/core.py", line 213, in step raise event._value
TypeError: __init__() takes exactly 2 arguments (3 given)