I am trying to simulate running of two manufacturing lines (Line A and Line B).Their time to failure follows Weibull distribution(shape = 0.7, scale = 12 (mins)). Line A and Line B both produces at rate of 100 products/min. From real world scenario, if any of lines fails, I want to increase rate of other line (say - 120 products/min) till the time failed line has not repaired.
Challenge: With increase in rate, chances of failure increases, hence, scale parameter changes (e.g for rate of 120 products/min, scale parameter changes from 12 mins to 10 mins). I want to model this change in distribution parameter in simulation.
Example :
- Line A and Line B starts running at time 0.
- Generate random number using weibull distribution for their time to failure (TTF) - Line A : 15 mins and Line B : 20 mins.
- Line A failed at 15 mins and got repaired at 20 mins. For this 5 mins, Line B ran at increased speed.
- At t= 15 min, generate a random number using weibull (with changed parameter) to get next TTF. The process repeats till the simulation time.
Currently I am using Python Simpy to code the logic but can't find a way to model this. Any help or reference would be very helpful. Here is my try but i am definitely missing something.
import simpy
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import weibull_min
class Machine(object):
def __init__(self, env, name,scale_parameter,shape_parameter, mean_repair_time,std_repair_time,increased_rate):
self.env = env
self.name = name
self.scale_parameter = scale_parameter
self.shape_parameter = shape_parameter
self.mean_repair_time = mean_repair_time
self.std_repair_time = std_repair_time
self.increased_rate = increased_rate
self.broken = False
self.processing_list = [0,]
self.machine_status = 1
self.process = env.process(self.run())
# Start the failure process
env.process(self.check_machines_status())
def run(self):
"""
Run as long as the simulation runs.
"""
while True:
try:
yield self.env.timeout(self.mean_time_to_failure())
self.processing_list.append(self.env.now)
print(f'{self.env.now:.2f} {self.name} is in failure.')
trial_resource.get(1)
yield self.env.timeout(self.mean_time_to_repair())
print(f'{self.env.now:.2f} {self.name} is repaired.')
self.processing_list.append(env.now)
trial_resource.put(1)
except simpy.Interrupt:
self.machine_status = 0
yield self.env.timeout(self.updated_mean_time_to_failure())
print(f'{self.env.now:.2f} {self.name} is in updated failure.')
#trial_resource.get(1)
self.broken = True
yield self.env.timeout(self.mean_time_to_repair())
print(f'{self.env.now:.2f} {self.name} is in updated repaired.')
trial_resource.put(1)
self.machine_status =1
def check_machines_status(self):
"""Periodically check the status of running machines. If any machine fails
interrupt the process"""
while True:
print(self.env.now,trial_resource.level)
print(self.name)
if trial_resource.level < trial_resource.capacity and self.broken == False and self.machine_status == 1:
# Only break the machine if it is currently working.
self.process.interrupt()
print('Machine running process interrupted %d' % env.now)
yield env.timeout(1)
def mean_time_to_failure(self):
x = int(weibull_min.rvs(self.shape_parameter, loc=0, scale= self.scale_parameter, size=1).tolist()[0])
if x == 0:
x = 1
return x
def updated_mean_time_to_failure(self):
correction_factor = (1-self.increased_rate)/100
x = int(weibull_min.rvs(self.shape_parameter*correction_factor, loc=0, scale= self.scale_parameter, size=1).tolist()[0])
if x == 0:
x = 1
return x
def mean_time_to_repair(self):
x = int(np.random.lognormal(self.mean_repair_time,self.std_repair_time))
if x ==0:
x =1
return x
env = simpy.Environment()
trial_resource = simpy.Container(env,init=3,capacity=3)
machine_1 = Machine(env, 'M1', 12, 0.65, 0.51,1,10)
machine_2 = Machine(env, 'M2', 14, 0.65, 0.51,1,10)
machine_3 = Machine(env, 'M3', 8, 0.65, 0.51,1,10)
env.run(until = 12)
print(machine_1.processing_list)
print(machine_2.processing_list)
print(machine_3.processing_list)