def getEntity(self): activeObject = self.getActiveObject() activeEntity = Machine.getEntity(self) #run the default code # read the processing time from the corresponding remainingRoute entry processingTime = activeEntity.remainingRoute[0].get( 'processingTime', {}) processingTime = self.getOperationTime(processingTime) self.rng = RandomNumberGenerator(self, processingTime) self.procTime = self.rng.generateNumber() # check if there is a need for manual processing self.checkForManualOperation(type='Processing', entity=activeEntity) # read the setup time from the corresponding remainingRoute entry setupTime = activeEntity.remainingRoute[0].get('setupTime', {}) setupTime = self.getOperationTime(setupTime) self.stpRng = RandomNumberGenerator(self, setupTime) # check if there is a need for manual processing self.checkForManualOperation(type='Setup', entity=activeEntity) activeEntity.currentStep = activeEntity.remainingRoute.pop( 0) #remove data from the remaining route of the entity if activeEntity.currentStep: # update the task_id of the currentStep dict within the schedule try: activeEntity.schedule[-1][ "task_id"] = activeEntity.currentStep["task_id"] # if there is currentOperator then update the taskId of corresponding step of their schedule according to the task_id of the currentStep if self.currentOperator: self.currentOperator.schedule[-1][ "task_id"] = activeEntity.currentStep["task_id"] except KeyError: pass return activeEntity
def __init__(self, id, name, capacity=1, \ processingTime=None, repairman='None',\ scrapQuantity={}, operatorPool='None',operationType='None',\ setupTime=None, loadTime=None, canDeliverOnInterruption=False, **kw): if not processingTime: processingTime = {'distributionType': 'Fixed', 'mean': 1} # initialize using the default method of the object Machine.__init__(self,id=id,name=name,\ capacity=capacity,\ processingTime=processingTime, repairman=repairman, canDeliverOnInterruption=canDeliverOnInterruption, operatorPool=operatorPool,operationType=operationType,\ setupTime=setupTime, loadTime=loadTime, ) # set the attributes of the scrap quantity distribution if not scrapQuantity: scrapQuantity = {'Fixed': {'mean': 0}} self.scrapRng = RandomNumberGenerator(self, scrapQuantity) from Globals import G G.BatchScrapMachineList.append(self)
def __init__(self, id, name, interArrivalTime=None, entity='Dream.Part', **kw): # Default values if not interArrivalTime: interArrivalTime = {'Fixed': {'mean': 1}} if 'Normal' in interArrivalTime.keys() and\ interArrivalTime['Normal'].get('max', None) is None: interArrivalTime['Normal']['max'] = interArrivalTime['Normal'][ 'mean'] + 5 * interArrivalTime['Normal']['stdev'] CoreObject.__init__(self, id, name) # properties used for statistics self.totalinterArrivalTime = 0 # the total interarrival time self.numberOfArrivals = 0 # the number of entities that were created self.type = "Source" #String that shows the type of object self.rng = RandomNumberGenerator(self, interArrivalTime) self.item = Globals.getClassFromName( entity) #the type of object that the Source will generate self.scheduledEntities = [ ] # list of creations that are scheduled. pattern is [timeOfCreation, EntityCounter] from Globals import G G.SourceList.append(self)
def __init__(self, id="", name="", victim=None, distribution=None, index=0, repairman=None, **kw): ObjectInterruption.__init__(self, id, name, victim=victim) self.rngTTF = RandomNumberGenerator(self, distribution.get("TTF", {"Fixed": {"mean": 100}})) self.rngTTR = RandomNumberGenerator(self, distribution.get("TTR", {"Fixed": {"mean": 10}})) self.name = "F" + str(index) self.repairman = repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type = "PeriodicMaintenance"
def __init__(self, id='',name='',victim=None, distribution=None, index=0, repairman=None,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTF=RandomNumberGenerator(self, distribution.get('TTF',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="PeriodicMaintenance"
def __init__(self, victim=None, distribution=None, index=0, repairman=None, offshift=False, deteriorationType='constant',**kw): #Process.__init__(self) ObjectInterruption.__init__(self,victim) if distribution: self.distType=distribution.get('distributionType','No') # the distribution that the failure duration follows self.MTTF=distribution.get('MTTF',60) # the MTTF self.MTTR=distribution.get('MTTR',5) # the MTTR self.availability=distribution.get('availability',100) # the availability else: self.distType='No' self.MTTF=60 self.MTTR=5 self.availability=100 self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" self.id=0 # shows how the time to failure is measured # 'constant' means it counts not matter the state of the victim # 'onShift' counts only if the victim is onShift # 'working' counts only working time self.deteriorationType=deteriorationType if(self.distType=="Availability"): # -------------------------------------------------------------- # the following are used if we have availability defined # (as in plant) the erlang is a special case of Gamma. # To model the Mu and sigma (that is given in plant) # as alpha and beta for gamma you should do the following: # beta=(sigma^2)/Mu # alpha=Mu/beta # -------------------------------------------------------------- self.AvailabilityMTTF=self.MTTR*(float(availability)/100)/(1-(float(availability)/100)) self.sigma=0.707106781185547*self.MTTR self.theta=(pow(self.sigma,2))/float(self.MTTR) self.beta=self.theta self.alpha=(float(self.MTTR)/self.theta) self.rngTTF=RandomNumberGenerator(self, "Exp") self.rngTTF.avg=self.AvailabilityMTTF self.rngTTR=RandomNumberGenerator(self, "Erlang") self.rngTTR.alpha=self.alpha self.rngTTR.beta=self.beta else: # -------------------------------------------------------------- # if the distribution is fixed # -------------------------------------------------------------- self.rngTTF=RandomNumberGenerator(self, self.distType) self.rngTTF.mean=self.MTTF self.rngTTR=RandomNumberGenerator(self, self.distType) self.rngTTR.mean=self.MTTR # flag used to identify if the time between failures should be counted while the victim is off-shift self.offshift=offshift
def __generate_instance(self, seed): RNG = RandomNumberGenerator(seed) task_queue = [] for J in range(0, self.size): task_queue.append({'j': J + 1}) for M in range(1, self.machines + 1): task_queue[J].update({f'p{M}': RNG.nextInt(1, MAX_VALUE)}) task_queue[J].update({f'S{M}': 0}) task_queue[J].update({f'C{M}': 0}) return task_queue
def calculateProcessingTime(self): # this is only for processing of the initial wip if self.isProcessingInitialWIP: activeEntity=self.getActiveObjectQueue()[0] if activeEntity.remainingProcessingTime: remainingProcessingTime=activeEntity.remainingProcessingTime from RandomNumberGenerator import RandomNumberGenerator initialWIPrng=RandomNumberGenerator(self, remainingProcessingTime) return initialWIPrng.generateNumber() return self.rng.generateNumber() # this is if we have a default processing time for all the entities
def __init__(self, id='',name='',victim=None, distribution={}, endUnfinished=True,offShiftAnticipation=0,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTB=RandomNumberGenerator(self, distribution.get('TTB',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.type="Break" # end current wip before going to break self.endUnfinished=endUnfinished # if the break is close to end of shift below a limit it will be suspended self.offShiftAnticipation=offShiftAnticipation
def instanceGenerator(Z, size): generator = RandomNumberGenerator(Z) d = [[0 for i in range(size)] for j in range(size)] for i in range(size): for j in range(size): if (i > j): d[i][j] = generator.nextInt(1, 50) d[j][i] = generator.nextInt(1, 50) return d
def __init__(self, id, name, numberOfSubBatches=1, processingTime=None, operator='None', outputResults=False, **kw): CoreObject.__init__(self, id, name) self.type = "BatchRassembly" #String that shows the type of object if not processingTime: processingTime = {'Fixed': {'mean': 0}} if 'Normal' in processingTime.keys() and\ processingTime['Normal'].get('max', None) is None: processingTime['Normal']['max'] = float( processingTime['Normal']['mean']) + 5 * float( processingTime['Normal']['stdev']) # holds the capacity of the object self.numberOfSubBatches = numberOfSubBatches # sets the operator resource of the Machine self.operator = operator # Sets the attributes of the processing (and failure) time(s) self.rng = RandomNumberGenerator(self, processingTime) from Globals import G G.BatchReassemblyList.append(self) # flag to show if the objects outputs results self.outputResults = bool(int(outputResults))
def __init__(self, id, name, processingTime=None, numberOfSubBatches=1, operator='None', **kw): CoreObject.__init__(self, id, name) self.type = "BatchDecomposition" #String that shows the type of object if not processingTime: processingTime = {'Fixed': {'mean': 0}} if 'Normal' in processingTime.keys() and\ processingTime['Normal'].get('max', None) is None: processingTime['Normal']['max'] = float( processingTime['Normal']['mean']) + 5 * float( processingTime['Normal']['stdev']) # holds the capacity of the object self.numberOfSubBatches = int(numberOfSubBatches) # sets the operator resource of the Machine self.operator = operator # Sets the attributes of the processing (and failure) time(s) self.rng = RandomNumberGenerator(self, processingTime) from Globals import G G.BatchDecompositionList.append(self)
def calculateInitialOperationTimes(self): # read the setup/processing time from the first entry of the full route activeEntity = self.getActiveObjectQueue()[0] #if the entity has its route defined in the BOM then remainingProcessing/SetupTime is provided # XX consider moving setupUPtime update to checkForManualOperationTypes as Setup is performed before Processing if activeEntity.routeInBOM: processingTime = self.getOperationTime( activeEntity.remainingProcessingTime) setupTime = self.getOperationTime(activeEntity.remainingSetupTime) else: # other wise these should be read from the route processingTime = activeEntity.route[0].get('processingTime', {}) processingTime = self.getOperationTime(processingTime) setupTime = activeEntity.route[0].get('setupTime', {}) setupTime = self.getOperationTime(setupTime) self.rng = RandomNumberGenerator(self, processingTime) self.stpRng = RandomNumberGenerator(self, setupTime)
def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing time from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # check if there is a need for manual processing self.checkForManualOperation(type='Processing',entity=activeEntity) # read the setup time from the corresponding remainingRoute entry setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # check if there is a need for manual processing self.checkForManualOperation(type='Setup',entity=activeEntity) activeEntity.currentStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity if activeEntity.currentStep: # update the task_id of the currentStep dict within the schedule try: activeEntity.schedule[-1]["task_id"] = activeEntity.currentStep["task_id"] # if there is currentOperator then update the taskId of corresponding step of their schedule according to the task_id of the currentStep if self.currentOperator: self.currentOperator.schedule[-1]["task_id"] = activeEntity.currentStep["task_id"] except KeyError: pass return activeEntity
def __init__(self, id, name, capacity=1, \ processingTime=None, repairman='None',\ scrapQuantity={}, operatorPool='None',operationType='None',\ setupTime=None, loadTime=None, canDeliverOnInterruption=False, technology=None, **kw): if not processingTime: processingTime = {'distributionType': 'Fixed', 'mean': 1} # initialize using the default method of the object Machine.__init__(self,id=id,name=name,\ capacity=capacity,\ processingTime=processingTime, repairman=repairman, canDeliverOnInterruption=canDeliverOnInterruption, operatorPool=operatorPool,operationType=operationType,\ setupTime=setupTime, loadTime=loadTime, technology=technology ) # set the attributes of the scrap quantity distribution if not scrapQuantity: scrapQuantity = {'Fixed':{'mean': 0}} self.scrapRng=RandomNumberGenerator(self, scrapQuantity) from Globals import G G.BatchScrapMachineList.append(self)
class Main: generator = RandomNumberGenerator() observer1 = DigitObserver() observer2 = GraphObserver() generator.addObserver(observer1) generator.addObserver(observer2) generator.execute()
def __init__(self, victim=None, distribution=None, index=0, repairman=None): #Process.__init__(self) ObjectInterruption.__init__(self,victim) if distribution: self.distType=distribution.get('distributionType','No') # the distribution that the failure duration follows self.MTTF=distribution.get('MTTF',60) # the MTTF self.MTTR=distribution.get('MTTR',5) # the MTTR self.availability=distribution.get('availability',100) # the availability else: self.distType='No' self.MTTF=60 self.MTTR=5 self.availability=100 self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" self.id=0 if(self.distType=="Availability"): # -------------------------------------------------------------- # the following are used if we have availability defined # (as in plant) the erlang is a special case of Gamma. # To model the Mu and sigma (that is given in plant) # as alpha and beta for gamma you should do the following: # beta=(sigma^2)/Mu # alpha=Mu/beta # -------------------------------------------------------------- self.AvailabilityMTTF=self.MTTR*(float(availability)/100)/(1-(float(availability)/100)) self.sigma=0.707106781185547*self.MTTR self.theta=(pow(self.sigma,2))/float(self.MTTR) self.beta=self.theta self.alpha=(float(self.MTTR)/self.theta) self.rngTTF=RandomNumberGenerator(self, "Exp") self.rngTTF.avg=self.AvailabilityMTTF self.rngTTR=RandomNumberGenerator(self, "Erlang") self.rngTTR.alpha=self.alpha self.rngTTR.beta=self.beta else: # -------------------------------------------------------------- # if the distribution is fixed # -------------------------------------------------------------- self.rngTTF=RandomNumberGenerator(self, self.distType) self.rngTTF.mean=self.MTTF self.rngTTR=RandomNumberGenerator(self, self.distType) self.rngTTR.mean=self.MTTR
def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing time from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # check if there is a need for manual processing self.checkForManualOperation(type='Processing',entity=activeEntity) # read the setup time from the corresponding remainingRoute entry setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # check if there is a need for manual processing self.checkForManualOperation(type='Setup',entity=activeEntity) removedStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity return activeEntity
def readLoadTime(self,callerObject=None): assert callerObject!=None, 'the caller of readLoadTime cannot be None' thecaller=callerObject thecaller.sortEntities() activeEntity=thecaller.Res.users[0] # read the load time from the corresponding remainingRoute entry loadTime=activeEntity.remainingRoute[0].get('loadTime',{}) loadTime=self.getOperationTime(loadTime) self.loadRng=RandomNumberGenerator(self, loadTime)
def main(): seed = int(input("Wprowadź Z: ")) generator = RandomNumberGenerator(seed) taskNumber = int(input("Wprowadź rozmiar problemu: ")) tasks = range(1, taskNumber + 1) nr = [] pj = [] #czas wykonania wj = [] #waga/współczynnik kary dj = [] #żądany termin zakończenia for task in tasks: nr.append(task) pj.append(generator.nextInt(1, 29)) A = 0 for number in pj: A += number for task in tasks: wj.append(generator.nextInt(1, 9)) X = 29 #X=A for task in tasks: dj.append(generator.nextInt(1, X)) print("\nnr:", nr) print("pj: ", pj) print("wj ", wj) print("dj", dj) witi_start = target_fun(pj, wj, dj, taskNumber) print(f'\nWiTi dla początkowego = {witi_start[0]}') print(f'C: {witi_start[2]}') print(f'T: {witi_start[1]}') witi_greedy = greedy(pj, wj, dj, taskNumber) print(f'\nWiTi dla Greedy algorithm = {witi_greedy[0]}') print(f'C: {witi_greedy[2]}') print(f'T: {witi_greedy[1]}') witi_brute_force = brute_force(pj, wj, dj, taskNumber) print(f'\nWiTi dla Brute Force = {witi_brute_force[0]}') print(f'C: {witi_brute_force[2]}') print(f'T: {witi_brute_force[1]}')
def main(): seed = int(input("Wprowadź Z: ")) generator = RandomNumberGenerator(seed) taskNumber = int(input("Wprowadź liczbę zadań: ")) tasks = range(1, taskNumber + 1) machineNumber = int(input("Wprowadź liczbę maszyn: ")) machines = range(1, machineNumber + 1) #lista wszystkich zadan na konkretnych maszynach p_ij = [] # permutacja zadan pi = [] # wyswietlenie rozwiazania po wykonaniu algorytmu optymalizacji solution = [] #lista zadan przydzielonych do jednej maszyny pj = [] for task in tasks: for machine in machines: pj.append(generator.nextInt(1, 29)) p_ij.append(pj.copy()) pj.clear() pi.append(task) print(p_ij) print("Permutacj naturalna: ") print("pi: ", pi) Cj, Cmax = calculate(p_ij, taskNumber, machineNumber) print("C:", Cj) print("Cmax:", Cmax) for task in tasks: solution.append([pi[task - 1], p_ij[task - 1]]) pi = Johnson(tasks, p_ij.copy()) print("Johnson: ") print("pi: ", pi) sort = {x: i for i, x in enumerate(pi)} solution.sort(key=lambda x: sort[x[0]]) Cj, Cmax = calculate([row[1] for row in solution], taskNumber, machineNumber) print("C", Cj) print("Cmax:", Cmax)
class BatchScrapMachine(Machine): # ======================================================================= # constructor run every time a new instance is created # calls the Machine constructor, but also reads attributes for # scraping distribution # ======================================================================= def __init__(self, id, name, capacity=1, \ processingTime=None, repairman='None',\ scrapQuantity={}, **kw): if not processingTime: processingTime = {'distributionType': 'Fixed', 'mean': 1} # initialize using the default method of the object Machine.__init__(self,id=id,name=name,\ capacity=capacity,\ processingTime=processingTime, repairman=repairman) # set the attributes of the scrap quantity distribution if not scrapQuantity: scrapQuantity = {'distributionType': 'Fixed', 'mean': 0} self.scrapRng=RandomNumberGenerator(self, **scrapQuantity) from Globals import G G.BatchScrapMachineList.append(self) # ======================================================================= # removes an Entity from the Object the Entity to be removed is passed # as argument by getEntity of the receiver # extends the default behaviour so that # it can scrap a number of units before disposing the Batch/SubBatch # ======================================================================= def removeEntity(self, entity=None): activeEntity = Machine.removeEntity(self, entity) scrapQuantity=self.scrapRng.generateNumber() activeEntity.numberOfUnits-=int(scrapQuantity) # the scrapQuantity should be integer at whatever case if activeEntity.numberOfUnits<0: activeEntity.numberOfUnits==0 return activeEntity # ======================================================================= # calculates the processing time # extends the default behaviour so that # the per-unit processing time is multiplied with the number of units # ======================================================================= def calculateProcessingTime(self): activeEntity = self.getActiveObjectQueue()[0] # this is only for processing of the initial wip if self.isProcessingInitialWIP: if activeEntity.unitsToProcess: return self.rng.generateNumber()*activeEntity.unitsToProcess return self.rng.generateNumber()*activeEntity.numberOfUnits
def __init__(self, id='',name='',victim=None, distribution={}, index=0, repairman=None, offshift=False, deteriorationType='constant', waitOnTie=False,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTF=RandomNumberGenerator(self, distribution.get('TTF',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" # shows how the time to failure is measured # 'constant' means it counts not matter the state of the victim # 'onShift' counts only if the victim is onShift # 'working' counts only working time self.deteriorationType=deteriorationType # flag used to identify if the time between failures should be counted while the victim is off-shift self.offshift=offshift # flag to show if the failure will wait on tie with other events before interrupting the victim self.waitOnTie=waitOnTie
def defineScrapQuantities(): process = G.CMSDData.getElementsByTagName('Process') #loop through the processes for proc in process: try: #read the scrap quantity Property = proc.getElementsByTagName('Property') for prop in Property: name = prop.getElementsByTagName('Name') name = name[0].toxml().replace('<Name>', '').replace('</Name>', '') if name == 'ScrapQuantity': scrap = Property[0].getElementsByTagName('Distribution') scrapName = scrap[0].getElementsByTagName('Name') scrapName = scrapName[0].toxml().replace('<Name>', '').replace( '</Name>', '') distrParA = scrap[0].getElementsByTagName( 'DistributionParameterA') parAName = distrParA[0].getElementsByTagName('Name') parAName = parAName[0].toxml().replace('<Name>', '').replace( '</Name>', '') parAValue = distrParA[0].getElementsByTagName('Value') parAValue = parAValue[0].toxml().replace( '<Value>', '').replace('</Value>', '') else: continue #read the id of the station resource ResourcesRequired = proc.getElementsByTagName( 'ResourcesRequired') for res in ResourcesRequired: Resource = res.getElementsByTagName('Resource') ResourceIdentifier = Resource[0].getElementsByTagName( 'ResourceIdentifier') ResourceIdentifier = ResourceIdentifier[0].toxml().replace( '<ResourceIdentifier>', '').replace('</ResourceIdentifier>', '') #loop through the stations and for the one with the id set the scrap distributionDict = { str(scrapName): { str(parAName): parAValue } } for obj in G.ObjList: if obj.id == ResourceIdentifier: obj.rng = RandomNumberGenerator(obj, distributionDict) except IndexError: continue
def __init__(self, size, seed): self.size = size self.last_permutation = [] RNG = RandomNumberGenerator(seed) p_list = [] w_list = [] d_list = [] p_sum = 0 self.queue = [] for J in range(0, self.size): p_list.append(RNG.nextInt(1, MAX_VALUE)) p_sum += p_list[-1] for J in range(0, self.size): w_list.append(RNG.nextInt(1, 9)) for J in range(0, self.size): d_list.append(RNG.nextInt(1, MAX_D)) for J in range(0, self.size): self.queue.append(task(J + 1, p_list[J], w_list[J], d_list[J])) self.last_permutation.append(J + 1)
def __init__(self, id='', name='', victim=None, distribution={}, endUnfinished=True, offShiftAnticipation=0, **kw): ObjectInterruption.__init__(self, id, name, victim=victim) self.rngTTB = RandomNumberGenerator( self, distribution.get('TTB', {'Fixed': { 'mean': 100 }})) self.rngTTR = RandomNumberGenerator( self, distribution.get('TTR', {'Fixed': { 'mean': 10 }})) self.type = "Break" # end current wip before going to break self.endUnfinished = endUnfinished # if the break is close to end of shift below a limit it will be suspended self.offShiftAnticipation = offShiftAnticipation
def defineProcessingTimes(): process = G.CMSDData.getElementsByTagName('Process') #loop through the processes for proc in process: try: #read the mean processing time a the unit OperationTime = proc.getElementsByTagName('OperationTime') distr = OperationTime[0].getElementsByTagName('Distribution') distrName = distr[0].getElementsByTagName('Name') distrName = distrName[0].toxml().replace('<Name>', '').replace( '</Name>', '') distrParA = distr[0].getElementsByTagName('DistributionParameterA') parAName = distrParA[0].getElementsByTagName('Name') parAName = parAName[0].toxml().replace('<Name>', '').replace('</Name>', '') parAValue = distrParA[0].getElementsByTagName('Value') parAValue = parAValue[0].toxml().replace('<Value>', '').replace( '</Value>', '') distrParB = distr[0].getElementsByTagName('DistributionParameterB') parBName = distrParB[0].getElementsByTagName('Name') parBName = parBName[0].toxml().replace('<Name>', '').replace('</Name>', '') parBValue = distrParB[0].getElementsByTagName('Value') parBValue = parBValue[0].toxml().replace('<Value>', '').replace( '</Value>', '') #read the id of the station resource ResourcesRequired = proc.getElementsByTagName('ResourcesRequired') for res in ResourcesRequired: Resource = res.getElementsByTagName('Resource') ResourceIdentifier = Resource[0].getElementsByTagName( 'ResourceIdentifier') ResourceIdentifier = ResourceIdentifier[0].toxml().replace( '<ResourceIdentifier>', '').replace('</ResourceIdentifier>', '') #loop through the stations and for the one with the id set the processing time distributionDict = { str(distrName): { str(parAName): parAValue, str(parBName): parBValue } } for obj in G.ObjList: if obj.id == ResourceIdentifier: obj.rng = RandomNumberGenerator(obj, distributionDict) except IndexError: continue
def calculateProcessingTime(self): # this is only for processing of the initial wip if self.isProcessingInitialWIP: # read the processing/setup/load times from the first entry of the full route activeEntity=self.getActiveObjectQueue()[0] processingTime=activeEntity.route[0].get('processingTime',{}) processingTime=self.getProcessingTime(processingTime) self.rng=RandomNumberGenerator(self, **processingTime) self.procTime=self.rng.generateNumber() setupTime=activeEntity.route[0].get('setupTime',{}) setupTime=self.getSetupTime(setupTime) self.stpRng=RandomNumberGenerator(self, **setupTime) return self.procTime #this is the processing time for this unique entity
def simulatedAnnealing(tasks): RNG = RandomNumberGenerator(123) t = copy.deepcopy(tasks) T = 1550.0 #temperatura zarzenia na bialo rozgrzanej stali :) Tend = 1E-10 # cokolwiek większe od zera it = 0 L = 10 pi = [] pi_new = [] pi_best = [] #natural perm for perm in range(1, t.size + 1): pi.append(perm) pi_best.append(perm) while T > Tend: for k in range(L): i = RNG.nextInt(0, t.size) - 1 j = RNG.nextInt(0, t.size) - 1 pi_new = copy.deepcopy(pi) swap_value = pi_new[i] pi_new[i] = pi_new[j] pi_new[j] = swap_value cmax_new = t.calculate_Cmax(pi_new) cmax_old = t.calculate_Cmax(pi) if cmax_new > cmax_old: r = RNG.nextFloat(0, 1) dCmax = cmax_old - cmax_new if r >= math.exp(dCmax / T): pi_new = copy.deepcopy(pi) pi = copy.deepcopy(pi_new) if t.calculate_Cmax(pi_best) > t.calculate_Cmax(pi): pi_best = copy.deepcopy(pi) it += 1 T = T / math.log(it + 1) #ln(it+1) return pi_best
def calculateInitialOperationTimes(self): # read the setup/processing time from the first entry of the full route activeEntity=self.getActiveObjectQueue()[0] #if the entity has its route defined in the BOM then remainingProcessing/SetupTime is provided # XX consider moving setupUPtime update to checkForManualOperationTypes as Setup is performed before Processing if activeEntity.routeInBOM: processingTime=self.getOperationTime(activeEntity.remainingProcessingTime) setupTime=self.getOperationTime(activeEntity.remainingSetupTime) else: # other wise these should be read from the route processingTime=activeEntity.route[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) setupTime=activeEntity.route[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.rng=RandomNumberGenerator(self, processingTime) self.stpRng=RandomNumberGenerator(self, setupTime)
def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing/setup/load times from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getProcessingTime(processingTime) self.rng=RandomNumberGenerator(self, **processingTime) self.procTime=self.rng.generateNumber() setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getSetupTime(setupTime) self.stpRng=RandomNumberGenerator(self, **setupTime) removedStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity return activeEntity
def __init__(self, id, name, capacity=1, \ processingTime=None, repairman='None',\ scrapQuantity={}, **kw): if not processingTime: processingTime = {'distributionType': 'Fixed', 'mean': 1} # initialize using the default method of the object Machine.__init__(self,id=id,name=name,\ capacity=capacity,\ processingTime=processingTime, repairman=repairman) # set the attributes of the scrap quantity distribution if not scrapQuantity: scrapQuantity = {'distributionType': 'Fixed', 'mean': 0} self.scrapRng=RandomNumberGenerator(self, **scrapQuantity) from Globals import G G.BatchScrapMachineList.append(self)
def __init__(self, id, name, interArrivalTime=None, entity='Dream.Part',**kw): # Default values if not interArrivalTime: interArrivalTime = {'Fixed': {'mean': 1}} if 'Normal' in interArrivalTime.keys() and\ interArrivalTime['Normal'].get('max', None) is None: interArrivalTime['Normal']['max'] = interArrivalTime['Normal']['mean'] + 5 * interArrivalTime['Normal']['stdev'] CoreObject.__init__(self, id, name) # properties used for statistics self.totalinterArrivalTime = 0 # the total interarrival time self.numberOfArrivals = 0 # the number of entities that were created self.type="Source" #String that shows the type of object self.rng = RandomNumberGenerator(self, interArrivalTime) self.item=Globals.getClassFromName(entity) #the type of object that the Source will generate self.scheduledEntities=[] # list of creations that are scheduled. pattern is [timeOfCreation, EntityCounter] from Globals import G G.SourceList.append(self)
def __init__(self, id='', name='', processingTime=None, inputsDict=None, **kw): self.type = "Assembly" #String that shows the type of object self.next = [] #list with the next objects in the flow self.previous = [] #list with the previous objects in the flow self.previousPart = [] #list with the previous objects that send parts self.previousFrame = [ ] #list with the previous objects that send frames self.nextIds = [] #list with the ids of the next objects in the flow self.previousIds = [ ] #list with the ids of the previous objects in the flow #lists to hold statistics of multiple runs self.Waiting = [] self.Working = [] self.Blockage = [] if not processingTime: processingTime = {'Fixed': {'mean': 0}} if 'Normal' in processingTime.keys() and\ processingTime['Normal'].get('max', None) is None: processingTime['Normal']['max'] = float( processingTime['Normal']['mean']) + 5 * float( processingTime['Normal']['stdev']) CoreObject.__init__(self, id, name) self.rng = RandomNumberGenerator(self, processingTime) # ============================== variable that is used for the loading of machines ============= self.exitAssignedToReceiver = False # by default the objects are not blocked # when the entities have to be loaded to operatedMachines # then the giverObjects have to be blocked for the time # that the machine is being loaded from Globals import G G.AssemblyList.append(self)
def __init__(self, id, name, interarrivalTime=None, entity='Dream.Part'): # Default values if not interarrivalTime: interarrivalTime = {'distributionType': 'Fixed', 'mean': 1} if interarrivalTime['distributionType'] == 'Normal' and\ interarrivalTime.get('max', None) is None: interarrivalTime['max'] = interarrivalTime['mean'] + 5 * interarrivalTime['stdev'] CoreObject.__init__(self, id, name) # properties used for statistics self.totalInterArrivalTime = 0 # the total interarrival time self.numberOfArrivals = 0 # the number of entities that were created # # list containing objects that follow in the routing # self.next=[] # list with the next objects in the flow # self.nextIds=[] # list with the ids of the next objects in the flow # self.previousIds=[] # list with the ids of the previous objects in the flow. # # For the source it is always empty! self.type="Source" #String that shows the type of object self.rng = RandomNumberGenerator(self, **interarrivalTime) self.item=Globals.getClassFromName(entity) #the type of object that the Source will generate
def parseInputs(self, inputsDict): CoreObject.parseInputs(self, inputsDict) processingTime = inputsDict.get('processingTime', {}) if not processingTime: processingTime = { 'distributionType': 'Fixed', 'mean': 0, 'stdev': 0, 'min': 0, } if processingTime['distributionType'] == 'Normal' and\ processingTime.get('max', None) is None: processingTime['max'] = float( processingTime['mean']) + 5 * float(processingTime['stdev']) self.rng = RandomNumberGenerator(self, **processingTime) # ============================== variable that is used for the loading of machines ============= self.exitAssignedToReceiver = False # by default the objects are not blocked # when the entities have to be loaded to operatedMachines # then the giverObjects have to be blocked for the time # that the machine is being loaded from Globals import G G.AssemblyList.append(self)
class Break(ObjectInterruption): def __init__(self, id='', name='', victim=None, distribution={}, endUnfinished=True, offShiftAnticipation=0, **kw): ObjectInterruption.__init__(self, id, name, victim=victim) self.rngTTB = RandomNumberGenerator( self, distribution.get('TTB', {'Fixed': { 'mean': 100 }})) self.rngTTR = RandomNumberGenerator( self, distribution.get('TTR', {'Fixed': { 'mean': 10 }})) self.type = "Break" # end current wip before going to break self.endUnfinished = endUnfinished # if the break is close to end of shift below a limit it will be suspended self.offShiftAnticipation = offShiftAnticipation def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess = self.env.event() self.victimEndsProcess = self.env.event() # ======================================================================= # The run method for the break which has to served by a repairman # ======================================================================= def run(self): from CoreObject import CoreObject from ObjectResource import ObjectResource while 1: # if the victim is off-shift wait for the victim to become on-shift if not self.victim.onShift: self.isWaitingForVictimOnShift = True self.expectedSignals['victimOnShift'] = 1 yield self.victimOnShift self.victimOnShift = self.env.event() timeToBreak = self.rngTTB.generateNumber() remainingTimeToBreak = timeToBreak self.expectedSignals['victimOffShift'] = 1 self.isWaitingForVictimOffShift = True # wait for the break or the end off shift of the victim receivedEvent = yield self.env.any_of( [self.env.timeout(remainingTimeToBreak), self.victimOffShift]) # if the victim became off shift the loop should start again (to wait on-shift etc) if self.victimOffShift in receivedEvent: transmitter, eventTime = self.victimOffShift.value assert eventTime == self.env.now, 'victimOffShift was triggered earlier, not now' # reset the signalparam of the victimOffShift event self.victimOffShift = self.env.event() continue # check if we are close to the end of the shift. If yes then the break may be suspended # (depending on offShiftAnticipation) timeToNextOfShift = None for oi in self.victim.objectInterruptions: if oi.type == 'ShiftScheduler': if oi.remainingShiftPattern: timeToNextOfShift = oi.remainingShiftPattern[0][1] if timeToNextOfShift: if self.offShiftAnticipation >= timeToNextOfShift - self.env.now: continue # interrupt the victim # if the victim is station if issubclass(self.victim.__class__, CoreObject): # if the mode is to end current work before going to break and there is current work, # wait for victimEndedLastProcessing or victimFailed # signal before going into break if self.endUnfinished and self.victim.isProcessing: self.victim.isWorkingOnTheLast = True self.waitingSignal = True self.expectedSignals['endedLastProcessing'] = 1 self.expectedSignals['victimFailed'] = 1 receivedEvent = yield self.env.any_of( [self.victim.endedLastProcessing, self.victimFailed]) if self.victim.endedLastProcessing in receivedEvent: transmitter, eventTime = self.victim.endedLastProcessing.value self.victim.endedLastProcessing = self.env.event() elif self.victimFailed in receivedEvent: transmitter, eventTime = self.victimFailed.value self.victimFailed = self.env.event() self.interruptVictim() # if the victim is operator elif issubclass(self.victim.__class__, ObjectResource): # if the operator is working in a station and the mode is # to stop current work in the end of shift # signal to the station that the operator has to leave station = self.victim.workingStation if station: if not self.endUnfinished and station.expectedSignals[ 'processOperatorUnavailable']: self.sendSignal( receiver=station, signal=station.processOperatorUnavailable) if self.victim.schedule: if not self.victim.schedule[-1].get("exitTime", None): self.victim.schedule[-1]["exitTime"] = self.env.now self.victim.schedule.append({ "station": { 'id': 'on-break' }, "entranceTime": self.env.now }) self.requestAllocation() self.victim.timeLastBreakStarted = self.env.now self.victim.onBreak = True # get the victim on break self.outputTrace(self.victim.name, "starts break") # update the break time breakTime = self.env.now self.expectedSignals['victimOffShift'] = 1 self.isWaitingForVictimOffShift = True # wait for the break or the end off shift of the victim receivedEvent = yield self.env.any_of([ self.env.timeout(self.rngTTR.generateNumber()), self.victimOffShift ]) # if the victim became off shift the break is considered over and # the loop should start again (to wait on-shift etc) if self.victimOffShift in receivedEvent: transmitter, eventTime = self.victimOffShift.value assert eventTime == self.env.now, 'victimOffShift was triggered earlier, not now' # reset the signalparam of the victimOffShift event self.victimOffShift = self.env.event() self.outputTrace(self.victim.name, "went off-shift so not on break anymore") else: self.outputTrace(self.victim.name, "returns from break") if issubclass(self.victim.__class__, CoreObject): self.reactivateVictim( ) # re-activate the victim in case it was interrupted else: if self.victim.schedule: if not self.victim.schedule[-1].get("exitTime", None): self.victim.schedule[-1]["exitTime"] = self.env.now self.requestAllocation() self.victim.timeLastBreakEnded = self.env.now self.victim.totalBreakTime += self.env.now - breakTime self.victim.onBreak = False # get the victim on break
class PeriodicMaintenance(ObjectInterruption): def __init__(self, id="", name="", victim=None, distribution=None, index=0, repairman=None, **kw): ObjectInterruption.__init__(self, id, name, victim=victim) self.rngTTF = RandomNumberGenerator(self, distribution.get("TTF", {"Fixed": {"mean": 100}})) self.rngTTR = RandomNumberGenerator(self, distribution.get("TTR", {"Fixed": {"mean": 10}})) self.name = "F" + str(index) self.repairman = repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type = "PeriodicMaintenance" def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess = self.env.event() self.victimEndsProcess = self.env.event() # ======================================================================= # The run method for the failure which has to served by a repairman # ======================================================================= def run(self): while 1: # if the time that the victim is off-shift should not be counted timeToFailure = self.rngTTF.generateNumber() remainingTimeToFailure = timeToFailure failureNotTriggered = True yield self.env.timeout(remainingTimeToFailure) if self.victim.isProcessing: self.victim.isWorkingOnTheLast = True self.waitingSignal = True self.expectedSignals["endedLastProcessing"] = 1 self.expectedSignals["victimFailed"] = 1 receivedEvent = yield self.env.any_of([self.victim.endedLastProcessing, self.victimFailed]) if self.victim.endedLastProcessing in receivedEvent: transmitter, eventTime = self.victim.endedLastProcessing.value self.victim.endedLastProcessing = self.env.event() elif self.victimFailed in receivedEvent: transmitter, eventTime = self.victimFailed.value self.victimFailed = self.env.event() # interrupt the victim self.interruptVictim() # interrupt the victim # check in the ObjectInterruptions of the victim. If there is a one that is waiting for victimFailed send it for oi in self.victim.objectInterruptions: if oi.expectedSignals["victimFailed"]: self.sendSignal(receiver=oi, signal=oi.victimFailed) self.victim.Up = False self.victim.timeLastFailure = self.env.now self.outputTrace(self.victim.name, "is down") # update the failure time failTime = self.env.now if self.repairman and self.repairman != "None": # if the failure needs a resource to be fixed, # the machine waits until the # resource is available with self.repairman.getResource().request() as request: yield request # update the time that the repair started timeOperationStarted = self.env.now self.repairman.timeLastOperationStarted = self.env.now yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over self.victim.totalFailureTime += self.env.now - failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up = True self.outputTrace(self.victim.name, "is up") self.repairman.totalWorkingTime += self.env.now - timeOperationStarted continue yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over # add the failure # if victim is off shift add only the fail time before the shift ended if not self.victim.onShift and failTime < self.victim.timeLastShiftEnded: self.victim.totalFailureTime += self.victim.timeLastShiftEnded - failTime # if the victim was off shift since the start of the failure add nothing elif not self.victim.onShift and failTime >= self.victim.timeLastShiftEnded: pass # if victim was off shift in the start of the fail time, add on elif self.victim.onShift and failTime < self.victim.timeLastShiftStarted: self.victim.totalFailureTime += self.env.now - self.victim.timeLastShiftStarted # this can happen only if deteriorationType is constant assert ( self.deteriorationType == "constant" ), "object got failure while off-shift and deterioration type not constant" else: self.victim.totalFailureTime += self.env.now - failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up = True self.outputTrace(self.victim.name, "is up")
class Source(CoreObject): def __init__(self, id, name, interarrivalTime=None, entity='Dream.Part'): # Default values if not interarrivalTime: interarrivalTime = {'distributionType': 'Fixed', 'mean': 1} if interarrivalTime['distributionType'] == 'Normal' and\ interarrivalTime.get('max', None) is None: interarrivalTime['max'] = interarrivalTime['mean'] + 5 * interarrivalTime['stdev'] CoreObject.__init__(self, id, name) # properties used for statistics self.totalInterArrivalTime = 0 # the total interarrival time self.numberOfArrivals = 0 # the number of entities that were created # # list containing objects that follow in the routing # self.next=[] # list with the next objects in the flow # self.nextIds=[] # list with the ids of the next objects in the flow # self.previousIds=[] # list with the ids of the previous objects in the flow. # # For the source it is always empty! self.type="Source" #String that shows the type of object self.rng = RandomNumberGenerator(self, **interarrivalTime) self.item=Globals.getClassFromName(entity) #the type of object that the Source will generate def initialize(self): # using the Process __init__ and not the CoreObject __init__ CoreObject.initialize(self) # initialize the internal Queue (type Resource) of the Source self.Res=Resource(capacity=infinity) self.Res.activeQ=[] self.Res.waitQ=[] def run(self): # get active object and its queue activeObject=self.getActiveObject() activeObjectQueue=self.getActiveObjectQueue() while 1: entity=self.createEntity() # create the Entity object and assign its name entity.creationTime=now() # assign the current simulation time as the Entity's creation time entity.startTime=now() # assign the current simulation time as the Entity's start time entity.currentStation=self # update the current station of the Entity G.EntityList.append(entity) self.outputTrace(entity.name, "generated") # output the trace activeObjectQueue.append(entity) # append the entity to the resource self.numberOfArrivals+=1 # we have one new arrival G.numberOfEntities+=1 yield hold,self,self.calculateInterarrivalTime() # wait until the next arrival #============================================================================ # sets the routing out element for the Source #============================================================================ def defineRouting(self, successorList=[]): self.next=successorList # only successors allowed for the source #============================================================================ # creates an Entity #============================================================================ def createEntity(self): return self.item(id = self.item.type+str(G.numberOfEntities), name = self.item.type+str(self.numberOfArrivals)) #return the newly created Entity #============================================================================ # calculates the processing time #============================================================================ def calculateInterarrivalTime(self): return self.rng.generateNumber() #this is if we have a default interarrival time for all the entities
from implement_observers import DigitObserver, GraphObserver from RandomNumberGenerator import RandomNumberGenerator if __name__ == "__main__": generator = RandomNumberGenerator() observer1 = DigitObserver() observer2 = GraphObserver() generator.add_observer(observer1) generator.add_observer(observer2) generator.execute()
class PeriodicMaintenance(ObjectInterruption): def __init__(self, id='',name='',victim=None, distribution=None, index=0, repairman=None,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTF=RandomNumberGenerator(self, distribution.get('TTF',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="PeriodicMaintenance" def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess=self.env.event() self.victimEndsProcess=self.env.event() # ======================================================================= # The run method for the failure which has to served by a repairman # ======================================================================= def run(self): while 1: # if the time that the victim is off-shift should not be counted timeToFailure=self.rngTTF.generateNumber() remainingTimeToFailure=timeToFailure failureNotTriggered=True yield self.env.timeout(remainingTimeToFailure) if self.victim.isProcessing: self.victim.isWorkingOnTheLast=True self.waitingSignal=True self.expectedSignals['endedLastProcessing']=1 self.expectedSignals['victimFailed']=1 receivedEvent=yield self.env.any_of([self.victim.endedLastProcessing , self.victimFailed]) if self.victim.endedLastProcessing in receivedEvent: transmitter, eventTime=self.victim.endedLastProcessing.value self.victim.endedLastProcessing=self.env.event() elif self.victimFailed in receivedEvent: transmitter, eventTime=self.victimFailed.value self.victimFailed=self.env.event() # interrupt the victim self.interruptVictim() # interrupt the victim # check in the ObjectInterruptions of the victim. If there is a one that is waiting for victimFailed send it for oi in self.victim.objectInterruptions: if oi.expectedSignals['victimFailed']: self.sendSignal(receiver=oi, signal=oi.victimFailed) self.victim.Up=False self.victim.timeLastFailure=self.env.now self.outputTrace(self.victim.name,"is down") # update the failure time failTime=self.env.now if(self.repairman and self.repairman!="None"): # if the failure needs a resource to be fixed, # the machine waits until the # resource is available with self.repairman.getResource().request() as request: yield request # update the time that the repair started timeOperationStarted=self.env.now self.repairman.timeLastOperationStarted=self.env.now yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up") self.repairman.totalWorkingTime+=self.env.now-timeOperationStarted continue yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over # add the failure # if victim is off shift add only the fail time before the shift ended if not self.victim.onShift and failTime < self.victim.timeLastShiftEnded: self.victim.totalFailureTime+=self.victim.timeLastShiftEnded-failTime # if the victim was off shift since the start of the failure add nothing elif not self.victim.onShift and failTime >= self.victim.timeLastShiftEnded: pass # if victim was off shift in the start of the fail time, add on elif self.victim.onShift and failTime < self.victim.timeLastShiftStarted: self.victim.totalFailureTime+=self.env.now-self.victim.timeLastShiftStarted # this can happen only if deteriorationType is constant assert self.deteriorationType=='constant', 'object got failure while off-shift and deterioration type not constant' else: self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up")
class MouldAssembly(MachineJobShop): # ======================================================================= # parses inputs if they are given in a dictionary # ======================================================================= def parseInputs(self, **kw): from Globals import G G.MouldAssemblyList.append(self) # ======================================================================= # the initialize method # ======================================================================= def initialize(self): self.mouldParent = None # the mould's to be assembled parent order self.mouldToBeCreated = None # the mould to be assembled MachineJobShop.initialize(self) # run default behaviour # ======================================================================= # getEntity method that gets the entity from the giver # it should run in a loop till it get's all the entities from the same order # (with the flag componentsReadyForAssembly set) # it is run only once, and receives all the entities to be assembled inside a while loop # ======================================================================= def getEntity(self): activeObject = self.getActiveObject() giverObject = activeObject.getGiverObject() # get the first entity from the predecessor # TODO: each MachineJobShop.getEntity is invoked, # the self.procTime is updated. Have to decide where to assign # the processing time of the assembler activeEntity = MachineJobShop.getEntity(self) # this is kept so that in the next loop it will not try to re-get this Entity firstObtained = activeEntity # check weather the activeEntity is of type Mould if activeEntity.type == 'Mould': # and return the mould received return activeEntity # otherwise, collect all the entities to be assembled # read the number of basic and secondary components of the moulds capacity = len(activeEntity.order.getAssemblyComponents()) # clear the active object queue del activeObject.getActiveObjectQueue()[:] # and set the capacity of the internal queue of the assembler activeObject.updateCapacity(capacity) # append the activeEntity to the activeObjectQueue activeObjectQueue = activeObject.getActiveObjectQueue() activeObjectQueue.append(activeEntity) # loop through the basic/secondary components of the order that is currently obtained # all the components are received at the same time for entity in activeEntity.order.getAssemblyComponents(): # continue for the one that is already obtained before if entity is firstObtained: continue self.entityToGet = entity # get the next component activeEntity = MachineJobShop.getEntity(self) # check whether the activeEntity is of type Mould try: if activeEntity.type == 'Mould': # and return the mould received raise AssembleMouldError( 'Having already received an orderComponent the assembler\ is not supposed to receive an object of type Mould' ) # check if the last component received has the same parent order as the previous one elif not (activeEntity.order is activeObjectQueue[1].order): raise AssembleMouldError( 'The orderComponents received by the assembler must have the\ same parent order') except AssembleMouldError as mouldError: print 'Mould Assembly Error: {0}'.format(mouldError) return False # perform the assembly-action and return the assembled mould activeEntity = activeObject.assemble() return activeEntity # ======================================================================= # method that updates the capacity according to the componentsList of the # activeEntity's parent order # ======================================================================= def updateCapacity(self, capacity): activeObject = self.getActiveObject() self.capacity = capacity self.Res = simpy.Resource(self.env, self.capacity) # ======================================================================= # assemble method that assembles the components together to a mould (order # and returns the product of the assembly. Furthermore, it resets the capacity # of the internal queue to 1 # ======================================================================= def assemble(self): activeObject = self.getActiveObject() # get the internal queue of the active core object activeObjectQueue = activeObject.getActiveObjectQueue() # assert that all the components are of the same parent order for entity in activeObjectQueue: assert entity.order==activeObjectQueue[0].order,\ 'The components residing in the MouldAssembly internal queue\ are not of the same parent order!' # if we have to create a new Entity (mould) this should be modified # we need the new entity's route, priority, isCritical flag, etc. self.mouldParent = activeObjectQueue[0].order # assert that there is a parent order assert self.mouldParent.type == 'Order', 'the type of the assembled to be mould\' s parent is not correct' # delete the contents of the internal queue temp_activeObjectQueue = list(activeObjectQueue) for element in temp_activeObjectQueue: # update their schedule element.schedule[-1]["exitTime"] = self.env.now # remove the elements from the activeObjectQueue and reset the current station of the entity activeObjectQueue.remove(element) element.currentStation = None del temp_activeObjectQueue[:] # after assembling reset the capacity activeObject.updateCapacity(1) #if there is a mould to be assembled try: if self.mouldParent: # find the component which is of type Mould # there must be only one mould component for entity in self.mouldParent.componentsList: entityClass = entity.get('_class', None) if entityClass == 'Dream.Mould': self.mouldToBeCreated = entity break # create the mould self.createMould(self.mouldToBeCreated) # check if there is a need for manual processing self.checkForManualOperation(type='Processing', entity=self.mouldToBeCreated) # check if there is a need for manual processing self.checkForManualOperation(type='Setup', entity=self.mouldToBeCreated) # set the created mould as WIP import Globals Globals.setWIP([self.mouldToBeCreated]) # read the activeObjectQueue again as it has been updated by the setWIP() activeObjectQueue = activeObject.getActiveObjectQueue() # reset attributes self.mouldParent = None self.mouldToBeCreated = None # return the assembled mould return activeObjectQueue[0] else: raise AssembleMouldError('There is no mould to be assembled') except AssembleMouldError as mouldError: print 'Mould Assembly Error: {0}'.format(mouldError) # ======================================================================= # creates the mould # ======================================================================= def createMould(self, component): #read attributes from the json or from the orderToBeDecomposed id = component.get('id', 'not found') name = component.get('name', 'not found') try: # dummy variable that holds the routes of the jobs the route from the JSON file is a sequence of dictionaries JSONRoute = component.get('route', []) # variable that holds the argument used in the Job initiation hold None for each entry in the 'route' list route = [x for x in JSONRoute] # copy JSONRoute # assert that the assembler is in the moulds route and update the initial step of the mould's route firstStep = route.pop(0) assert (self.id in firstStep.get('stationIdsList',[])),\ 'the assembler must be in the mould-to-be-created route\' initial step' # normal processing operation processingTime = firstStep['processingTime'] processingTime = self.getOperationTime(processingTime) self.rng = RandomNumberGenerator(self, processingTime) self.procTime = self.rng.generateNumber() # update the activeObject's processing time according to the readings in the mould's route processDistType = processingTime.keys()[0] procTime = float(processingTime[processDistType].get('mean', 0)) processOpType = firstStep.get('operationType', {}).get( 'Processing', 'not found') # can be manual/automatic # task_id task_id = firstStep.get('task_id', None) # sequence sequence = firstStep.get('sequence', None) # operator operator = firstStep.get('operator', {}) # technology technology = firstStep.get('technology', None) # quantity quantity = firstStep.get('quantity', None) # setup operation setupTime = firstStep.get('setupTime', None) if setupTime: setupTime = self.getOperationTime(setupTime) self.stpRng = RandomNumberGenerator(self, setupTime) # update the activeObject's processing time according to the readings in the mould's route setupDistType = setupTime.keys()[0] setTime = float(setupTime[setupDistType].get('mean', 0)) setupOpType = firstStep.get('operationType', {}).get( 'Setup', 'not found') # can be manual/automatic # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}},\ 'setupTime':{str(setupDistType):{'mean':str(setupTime)}}, 'operationType':{'Processing':processOpType,'Setup':setupOpType}}) else: # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert( 0, { 'stationIdsList': [str(self.id)], 'processingTime': { str(processDistType): { 'mean': str(procTime) } }, 'operationType': { 'Processing': processOpType } }) # if there is task_id then add it to the route if task_id: route[0]["task_id"] = task_id # if there is sequence then add it to the route if sequence: route[0]["sequence"] = sequence # if there is operator then add it to the route if operator: route[0]["operator"] = operator # if there is technology then add it to the route if technology: route[0]["technology"] = technology # if there is quantity then add it to the route if quantity != None: route[0]["quantity"] = quantity #Below it is to assign an exit if it was not assigned in JSON #have to talk about it with NEX exitAssigned = False for element in route: elementIds = element.get('stationIdsList', []) for obj in G.ObjList: for elementId in elementIds: if obj.id == elementId and obj.type == 'Exit': exitAssigned = True # assign an exit to the route of the mould if not exitAssigned: exitId = None for obj in G.ObjList: if obj.type == 'Exit': exitId = obj.id break if exitId: route.append({ 'stationIdsList': [str(exitId)], 'processingTime': {} }) # keep a reference of all extra properties passed to the job extraPropertyDict = {} for key, value in component.items(): if key not in ('_class', 'id'): extraPropertyDict[key] = value # create and initiate the OrderComponent from Mould import Mould M=Mould(id, name, route, \ priority=self.mouldParent.priority, \ order=self.mouldParent,\ dueDate=self.mouldParent.dueDate, \ orderDate=self.mouldParent.orderDate, \ extraPropertyDict=extraPropertyDict,\ isCritical=self.mouldParent.isCritical) # update the mouldToBeCreated self.mouldToBeCreated = M G.JobList.append(M) G.WipList.append(M) G.EntityList.append(M) G.MouldList.append(M) #initialize the component M.initialize() except: # added for testing print 'the mould to be created', component.get( 'name', 'not found'), 'cannot be created', 'time', self.env.now raise
class MachineJobShop(Machine): # ======================================================================= # set all the objects in previous and next # ======================================================================= def initialize(self): from Globals import G self.previous=G.ObjList self.next=[] Machine.initialize(self) #run default behaviour # ======================================================================= # gets an entity from the predecessor that the predecessor index points to # ======================================================================= def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing time from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # check if there is a need for manual processing self.checkForManualOperation(type='Processing',entity=activeEntity) # read the setup time from the corresponding remainingRoute entry setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # check if there is a need for manual processing self.checkForManualOperation(type='Setup',entity=activeEntity) activeEntity.currentStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity if activeEntity.currentStep: # update the task_id of the currentStep dict within the schedule try: activeEntity.schedule[-1]["task_id"] = activeEntity.currentStep["task_id"] # if there is currentOperator then update the taskId of corresponding step of their schedule according to the task_id of the currentStep if self.currentOperator: self.currentOperator.schedule[-1]["task_id"] = activeEntity.currentStep["task_id"] except KeyError: pass return activeEntity #=========================================================================== # update the next list of the object based on the activeEentity #=========================================================================== def updateNext(self,entity=None): activeObject = self.getActiveObject() activeEntity=entity # read the possible receivers - update the next list import Globals # XXX: in the case of MouldAssembler there is no next defined in the route of the entities that are received # the position activeEntity.remainingRoute[1] is out of bound. the next should be updated by the remaining route of the entity to be assembled if len(activeEntity.remainingRoute)>1: nextObjectIds=activeEntity.remainingRoute[1].get('stationIdsList',[]) nextObjects = [] for nextObjectId in nextObjectIds: nextObject = Globals.findObjectById(nextObjectId) nextObjects.append(nextObject) # update the next list of the object for nextObject in nextObjects: # append only if not already in the list if nextObject not in activeObject.next: activeObject.next.append(nextObject) # ======================================================================= # calculates the processing time # ======================================================================= def calculateProcessingTime(self): # this is only for processing of the initial wip if self.isProcessingInitialWIP: self.procTime = self.rng.generateNumber() return self.procTime #this is the processing time for this unique entity #=========================================================================== # get the initial operation times (setup/processing); # XXX initialy only setup time is calculated here #=========================================================================== def calculateInitialOperationTimes(self): # read the setup/processing time from the first entry of the full route activeEntity=self.getActiveObjectQueue()[0] #if the entity has its route defined in the BOM then remainingProcessing/SetupTime is provided # XX consider moving setupUPtime update to checkForManualOperationTypes as Setup is performed before Processing if activeEntity.routeInBOM: processingTime=self.getOperationTime(activeEntity.remainingProcessingTime) setupTime=self.getOperationTime(activeEntity.remainingSetupTime) else: # other wise these should be read from the route processingTime=activeEntity.route[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) setupTime=activeEntity.route[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.rng=RandomNumberGenerator(self, processingTime) self.stpRng=RandomNumberGenerator(self, setupTime) # ======================================================================= # checks if the Queue can accept an entity # it checks also the next station of the Entity # and returns true only if the active object is the next station # ======================================================================= def canAccept(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #return according to the state of the Queue # also check if (if the machine is to be operated) there are available operators if (self.operatorPool!='None' and (any(type=='Load' for type in self.multOperationTypeList))): return self.operatorPool.checkIfResourceIsAvailable()\ and len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRouteOf(thecaller)\ and not self.entryIsAssignedTo() else: return len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRouteOf(thecaller)\ and not self.entryIsAssignedTo() #=========================================================================== # method used to check whether the station is in the entity-to-be-received route #=========================================================================== def isInRouteOf(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject # if the caller is not defined then return True. We are only interested in checking whether # the station can accept whatever entity from whichever giver if not thecaller: return True #check it the caller object holds an Entity that requests for current object if len(thecaller.Res.users)>0: # TODO: make sure that the first entity of the callerObject is to be disposed activeEntity=thecaller.Res.users[0] # if the machine's Id is in the list of the entity's next stations if self.id in activeEntity.remainingRoute[0].get('stationIdsList',[]): return True return False # ======================================================================= # checks if the Machine can dispose an entity. # Returns True only to the potential receiver # ======================================================================= def haveToDispose(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #if we have only one successor just check if machine waits to dispose and also is up # this is done to achieve better (cpu) processing time if(callerObject==None): return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ #return True if the Machine in the state of disposing and the caller is the receiver return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ and thecaller.isInRouteOf(self) # ======================================================================= # method to execute preemption # ======================================================================= def preempt(self): # self.printTrace(self.id,preempted='') activeEntity=self.Res.users[0] #get the active Entity #calculate the remaining processing time #if it is reset then set it as the original processing time if self.resetOnPreemption: remainingProcessingTime=self.procTime #else subtract the time that passed since the entity entered #(may need also failure time if there was. TO BE MELIORATED) else: remainingProcessingTime=self.procTime-(self.env.now-self.timeLastEntityEntered) #update the remaining route of activeEntity activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.id)],\ 'processingTime':\ {'Fixed':{'mean':str(remainingProcessingTime)}}}) activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.lastGiver.id)],\ 'processingTime':{'Fixed':{'mean':'0'}}}) #set the receiver as the object where the active entity was preempted from self.receiver=self.lastGiver self.next=[self.receiver] self.waitToDispose=True #set that I have to dispose self.receiver.timeLastEntityEnded=self.env.now #required to count blockage correctly in the preemptied station # TODO: use a signal and wait for it, reactivation is not recognised as interruption # reactivate(self) if self.expectedSignals['preemptQueue']: self.sendSignal(receiver=self, signal=self.preemptQueue) # TODO: consider the case when a failure has the Station down. The event preempt will not be received now() # but at a later simulation time. #=========================================================================== # extend the default behaviour to check if whether the station # is in the route of the entity to be received #=========================================================================== def canAcceptAndIsRequested(self,callerObject): giverObject=callerObject assert giverObject, 'there must be a caller for canAcceptAndIsRequested' if self.isInRouteOf(giverObject): if Machine.canAcceptAndIsRequested(self,giverObject): self.readLoadTime(giverObject) return True return False #=========================================================================== # to be called by canAcceptAndIsRequested if it is to return True. # the load time of the Entity must be read #=========================================================================== def readLoadTime(self,callerObject=None): assert callerObject!=None, 'the caller of readLoadTime cannot be None' thecaller=callerObject thecaller.sortEntities() activeEntity=thecaller.Res.users[0] # read the load time from the corresponding remainingRoute entry loadTime=activeEntity.remainingRoute[0].get('loadTime',{}) loadTime=self.getOperationTime(loadTime) self.loadRng=RandomNumberGenerator(self, loadTime) #=========================================================================== # get the initial operationTypes (Setup/Processing) : manual or automatic #=========================================================================== def checkInitialOperationTypes(self): # check if manual Setup is required self.checkForManualOperation(type='Setup') # check if manual Processing is required self.checkForManualOperation(type='Processing') #=========================================================================== # check if the operation defined as an argument requires manual operation #=========================================================================== def checkForManualOperation(self,type,entity=None): typeDict={'Setup':'setupTime', 'Processing':'processingTime'} assert type!=None, 'a type must be defined for the checkForManualOperation method' if not entity: activeEntity=self.getActiveObjectQueue()[0] else: activeEntity=entity # read the definition of the time from the remainingRoute dict if not self.isProcessingInitialWIP: operationTypeDict=activeEntity.remainingRoute[0].get('operationType',{}) operationType=operationTypeDict.get(str(type),'not defined') else: # if the active entity is initialWIP at the start of simulation operationType=activeEntity.initialOperationTypes.get(str(type),'not defined') # if the operationType is not 'not defined' if operationType!='not defined': # if the operationType key has value 1 (manual operation) if operationType: # add setup to the multOpeartionTypeList if not type in self.multOperationTypeList: self.multOperationTypeList.append(str(type)) else: # otherwise remove it from the multOperationTypeList if type in self.multOperationTypeList: self.multOperationTypeList.remove(str(type)) # ======================================================================= # removes an entity from the Machine # extension to remove possible receivers accordingly # ======================================================================= def removeEntity(self, entity=None): receiverObject=self.receiver activeEntity=Machine.removeEntity(self, entity) #run the default method removeReceiver=True # search in the internalQ. If an entity has the same receiver do not remove for ent in self.Res.users: nextObjectIds=ent.remainingRoute[0].get('stationIdsList',[]) if receiverObject.id in nextObjectIds: removeReceiver=False # if not entity had the same receiver then the receiver will be removed if removeReceiver: self.next.remove(receiverObject) return activeEntity
class Break(ObjectInterruption): def __init__(self, id='',name='',victim=None, distribution={}, endUnfinished=True,offShiftAnticipation=0,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTB=RandomNumberGenerator(self, distribution.get('TTB',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.type="Break" # end current wip before going to break self.endUnfinished=endUnfinished # if the break is close to end of shift below a limit it will be suspended self.offShiftAnticipation=offShiftAnticipation def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess=self.env.event() self.victimEndsProcess=self.env.event() # ======================================================================= # The run method for the break which has to served by a repairman # ======================================================================= def run(self): from CoreObject import CoreObject from ObjectResource import ObjectResource while 1: # if the victim is off-shift wait for the victim to become on-shift if not self.victim.onShift: self.isWaitingForVictimOnShift=True self.expectedSignals['victimOnShift']=1 yield self.victimOnShift self.victimOnShift=self.env.event() timeToBreak=self.rngTTB.generateNumber() remainingTimeToBreak=timeToBreak self.expectedSignals['victimOffShift']=1 self.isWaitingForVictimOffShift=True # wait for the break or the end off shift of the victim receivedEvent = yield self.env.any_of([self.env.timeout(remainingTimeToBreak),self.victimOffShift]) # if the victim became off shift the loop should start again (to wait on-shift etc) if self.victimOffShift in receivedEvent: transmitter, eventTime=self.victimOffShift.value assert eventTime==self.env.now, 'victimOffShift was triggered earlier, not now' # reset the signalparam of the victimOffShift event self.victimOffShift=self.env.event() continue # check if we are close to the end of the shift. If yes then the break may be suspended # (depending on offShiftAnticipation) timeToNextOfShift=None for oi in self.victim.objectInterruptions: if oi.type=='ShiftScheduler': if oi.remainingShiftPattern: timeToNextOfShift=oi.remainingShiftPattern[0][1] if timeToNextOfShift: if self.offShiftAnticipation>=timeToNextOfShift-self.env.now: continue # interrupt the victim # if the victim is station if issubclass(self.victim.__class__, CoreObject): # if the mode is to end current work before going to break and there is current work, # wait for victimEndedLastProcessing or victimFailed # signal before going into break if self.endUnfinished and self.victim.isProcessing: self.victim.isWorkingOnTheLast=True self.waitingSignal=True self.expectedSignals['endedLastProcessing']=1 self.expectedSignals['victimFailed']=1 receivedEvent=yield self.env.any_of([self.victim.endedLastProcessing , self.victimFailed]) if self.victim.endedLastProcessing in receivedEvent: transmitter, eventTime=self.victim.endedLastProcessing.value self.victim.endedLastProcessing=self.env.event() elif self.victimFailed in receivedEvent: transmitter, eventTime=self.victimFailed.value self.victimFailed=self.env.event() self.interruptVictim() # if the victim is operator elif issubclass(self.victim.__class__, ObjectResource): # if the operator is working in a station and the mode is # to stop current work in the end of shift # signal to the station that the operator has to leave station=self.victim.workingStation if station: if not self.endUnfinished and station.expectedSignals['processOperatorUnavailable']: self.sendSignal(receiver=station, signal=station.processOperatorUnavailable) if self.victim.schedule: if not self.victim.schedule[-1].get("exitTime", None): self.victim.schedule[-1]["exitTime"] = self.env.now self.victim.schedule.append({"station": {'id':'on-break'}, "entranceTime": self.env.now}) self.requestAllocation() self.victim.timeLastBreakStarted=self.env.now self.victim.onBreak=True # get the victim on break self.outputTrace(self.victim.name,"starts break") # update the break time breakTime=self.env.now self.expectedSignals['victimOffShift']=1 self.isWaitingForVictimOffShift=True # wait for the break or the end off shift of the victim receivedEvent = yield self.env.any_of([self.env.timeout(self.rngTTR.generateNumber()),self.victimOffShift]) # if the victim became off shift the break is considered over and # the loop should start again (to wait on-shift etc) if self.victimOffShift in receivedEvent: transmitter, eventTime=self.victimOffShift.value assert eventTime==self.env.now, 'victimOffShift was triggered earlier, not now' # reset the signalparam of the victimOffShift event self.victimOffShift=self.env.event() self.outputTrace(self.victim.name,"went off-shift so not on break anymore") else: self.outputTrace(self.victim.name,"returns from break") if issubclass(self.victim.__class__, CoreObject): self.reactivateVictim() # re-activate the victim in case it was interrupted else: if self.victim.schedule: if not self.victim.schedule[-1].get("exitTime", None): self.victim.schedule[-1]["exitTime"] = self.env.now self.requestAllocation() self.victim.timeLastBreakEnded=self.env.now self.victim.totalBreakTime+=self.env.now-breakTime self.victim.onBreak=False # get the victim on break
class MachineJobShop(Machine): # ======================================================================= # set all the objects in previous and next # ======================================================================= def initialize(self): from Globals import G self.previous=G.ObjList self.next=[] Machine.initialize(self) #run default behaviour # ======================================================================= # gets an entity from the predecessor that the predecessor index points to # ======================================================================= def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing time from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # check if there is a need for manual processing self.checkForManualOperation(type='Processing',entity=activeEntity) # read the setup time from the corresponding remainingRoute entry setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # check if there is a need for manual processing self.checkForManualOperation(type='Setup',entity=activeEntity) removedStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity return activeEntity #=========================================================================== # update the next list of the object based on the activeEentity #=========================================================================== def updateNext(self,entity=None): activeObject = self.getActiveObject() activeEntity=entity # read the possible receivers - update the next list import Globals # XXX: in the case of MouldAssembler there is no next defined in the route of the entities that are received # the position activeEntity.remainingRoute[1] is out of bound. the next should be updated by the remaining route of the entity to be assembled if len(activeEntity.remainingRoute)>1: nextObjectIds=activeEntity.remainingRoute[1].get('stationIdsList',[]) nextObjects = [] for nextObjectId in nextObjectIds: nextObject = Globals.findObjectById(nextObjectId) nextObjects.append(nextObject) # update the next list of the object for nextObject in nextObjects: # append only if not already in the list if nextObject not in activeObject.next: activeObject.next.append(nextObject) # ======================================================================= # calculates the processing time # ======================================================================= def calculateProcessingTime(self): # this is only for processing of the initial wip if self.isProcessingInitialWIP: # read the setup/processing time from the first entry of the full route activeEntity=self.getActiveObjectQueue()[0] #if the entity has its route defined in the BOM then remainingProcessing/SetupTime is provided # XX consider moving setupUPtime update to checkForManualOperationTypes as Setup is performed before Processing if activeEntity.routeInBOM: processingTime=self.getOperationTime(activeEntity.remainingProcessingTime) setupTime=self.getOperationTime(activeEntity.remainingSetupTime) else: # other wise these should be read from the route processingTime=activeEntity.route[0].get('processingTime',{}) processingTime=self.getOperationTime(processingTime) setupTime=activeEntity.route[0].get('setupTime',{}) setupTime=self.getOperationTime(setupTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() self.stpRng=RandomNumberGenerator(self, setupTime) return self.procTime #this is the processing time for this unique entity # ======================================================================= # checks if the Queue can accept an entity # it checks also the next station of the Entity # and returns true only if the active object is the next station # ======================================================================= def canAccept(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #return according to the state of the Queue # also check if (if the machine is to be operated) there are available operators if (self.operatorPool!='None' and (any(type=='Load' for type in self.multOperationTypeList))): return self.operatorPool.checkIfResourceIsAvailable()\ and len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRouteOf(thecaller)\ and not self.entryIsAssignedTo() else: return len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRouteOf(thecaller)\ and not self.entryIsAssignedTo() #=========================================================================== # method used to check whether the station is in the entity-to-be-received route #=========================================================================== def isInRouteOf(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject # if the caller is not defined then return True. We are only interested in checking whether # the station can accept whatever entity from whichever giver if not thecaller: return True #check it the caller object holds an Entity that requests for current object if len(thecaller.Res.users)>0: # TODO: make sure that the first entity of the callerObject is to be disposed activeEntity=thecaller.Res.users[0] # if the machine's Id is in the list of the entity's next stations if self.id in activeEntity.remainingRoute[0].get('stationIdsList',[]): return True return False # ======================================================================= # checks if the Machine can dispose an entity. # Returns True only to the potential receiver # ======================================================================= def haveToDispose(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #if we have only one successor just check if machine waits to dispose and also is up # this is done to achieve better (cpu) processing time if(callerObject==None): return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ #return True if the Machine in the state of disposing and the caller is the receiver return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ and thecaller.isInRouteOf(self) # ======================================================================= # method to execute preemption # ======================================================================= def preempt(self): # self.printTrace(self.id,preempted='') activeEntity=self.Res.users[0] #get the active Entity #calculate the remaining processing time #if it is reset then set it as the original processing time if self.resetOnPreemption: remainingProcessingTime=self.procTime #else subtract the time that passed since the entity entered #(may need also failure time if there was. TO BE MELIORATED) else: remainingProcessingTime=self.procTime-(self.env.now-self.timeLastEntityEntered) #update the remaining route of activeEntity activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.id)],\ 'processingTime':\ {'Fixed':{'mean':str(remainingProcessingTime)}}}) activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.lastGiver.id)],\ 'processingTime':{'Fixed':{'mean':'0'}}}) #set the receiver as the object where the active entity was preempted from self.receiver=self.lastGiver self.next=[self.receiver] self.waitToDispose=True #set that I have to dispose self.receiver.timeLastEntityEnded=self.env.now #required to count blockage correctly in the preemptied station # TODO: use a signal and wait for it, reactivation is not recognised as interruption # reactivate(self) if self.expectedSignals['preemptQueue']: self.sendSignal(receiver=self, signal=self.preemptQueue) # TODO: consider the case when a failure has the Station down. The event preempt will not be received now() # but at a later simulation time. #=========================================================================== # extend the default behaviour to check if whether the station # is in the route of the entity to be received #=========================================================================== def canAcceptAndIsRequested(self,callerObject): giverObject=callerObject assert giverObject, 'there must be a caller for canAcceptAndIsRequested' if self.isInRouteOf(giverObject): if Machine.canAcceptAndIsRequested(self,giverObject): self.readLoadTime(giverObject) return True return False #=========================================================================== # to be called by canAcceptAndIsRequested if it is to return True. # the load time of the Entity must be read #=========================================================================== def readLoadTime(self,callerObject=None): assert callerObject!=None, 'the caller of readLoadTime cannot be None' thecaller=callerObject thecaller.sortEntities() activeEntity=thecaller.Res.users[0] # read the load time from the corresponding remainingRoute entry loadTime=activeEntity.remainingRoute[0].get('loadTime',{}) loadTime=self.getOperationTime(loadTime) self.loadRng=RandomNumberGenerator(self, loadTime) #=========================================================================== # get the initial operationTypes (Setup/Processing) : manual or automatic #=========================================================================== def checkInitialOperationTypes(self): # check if manual Setup is required self.checkForManualOperation(type='Setup') # check if manual Processing is required self.checkForManualOperation(type='Processing') #=========================================================================== # check if the operation defined as an argument requires manual operation #=========================================================================== def checkForManualOperation(self,type,entity=None): typeDict={'Setup':'setupTime', 'Processing':'processingTime'} assert type!=None, 'a type must be defined for the checkForManualOperation method' if not entity: activeEntity=self.getActiveObjectQueue()[0] else: activeEntity=entity # read the definition of the time from the remainingRoute dict if not self.isProcessingInitialWIP: operationTypeDict=activeEntity.remainingRoute[0].get('operationType',{}) operationType=operationTypeDict.get(str(type),'not defined') else: # if the active entity is initialWIP at the start of simulation operationType=activeEntity.initialOperationTypes.get(str(type),'not defined') # if the operationType is not 'not defined' if operationType!='not defined': # if the operationType key has value 1 (manual operation) if operationType: # add setup to the multOpeartionTypeList if not type in self.multOperationTypeList: self.multOperationTypeList.append(str(type)) else: # otherwise remove it from the multOperationTypeList if type in self.multOperationTypeList: self.multOperationTypeList.remove(str(type)) # ======================================================================= # removes an entity from the Machine # extension to remove possible receivers accordingly # ======================================================================= def removeEntity(self, entity=None): receiverObject=self.receiver activeEntity=Machine.removeEntity(self, entity) #run the default method removeReceiver=True # search in the internalQ. If an entity has the same receiver do not remove for ent in self.Res.users: nextObjectIds=ent.remainingRoute[0].get('stationIdsList',[]) if receiverObject.id in nextObjectIds: removeReceiver=False # if not entity had the same receiver then the receiver will be removed if removeReceiver: self.next.remove(receiverObject) return activeEntity
class Failure(ObjectInterruption): def __init__(self, id='',name='',victim=None, distribution={}, index=0, repairman=None, offshift=False, deteriorationType='constant', waitOnTie=False,**kw): ObjectInterruption.__init__(self,id,name,victim=victim) self.rngTTF=RandomNumberGenerator(self, distribution.get('TTF',{'Fixed':{'mean':100}})) self.rngTTR=RandomNumberGenerator(self, distribution.get('TTR',{'Fixed':{'mean':10}})) self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" # shows how the time to failure is measured # 'constant' means it counts not matter the state of the victim # 'onShift' counts only if the victim is onShift # 'working' counts only working time self.deteriorationType=deteriorationType # flag used to identify if the time between failures should be counted while the victim is off-shift self.offshift=offshift # flag to show if the failure will wait on tie with other events before interrupting the victim self.waitOnTie=waitOnTie def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess=self.env.event() self.victimEndsProcess=self.env.event() # ======================================================================= # The run method for the failure which has to served by a repairman # ======================================================================= def run(self): while 1: # if the time that the victim is off-shift should not be counted timeToFailure=self.rngTTF.generateNumber() remainingTimeToFailure=timeToFailure failureNotTriggered=True # if time to failure counts not matter the state of the victim if self.deteriorationType=='constant': yield self.env.timeout(remainingTimeToFailure) # if time to failure counts only in onShift time elif self.deteriorationType=='onShift': while failureNotTriggered: timeRestartedCounting=self.env.now self.isWaitingForVictimOffShift=True self.expectedSignals['victimOffShift']=1 receivedEvent=yield self.env.timeout(remainingTimeToFailure) | self.victimOffShift # the failure should receive a signal if there is a shift-off triggered if self.victimOffShift in receivedEvent: assert self.victim.onShift==False, 'shiftFailure cannot recalculate TTF if the victim is onShift' self.victimOffShift=self.env.event() remainingTimeToFailure=remainingTimeToFailure-(self.env.now-timeRestartedCounting) # wait for the shift to start again self.isWaitingForVictimOnShift=True self.expectedSignals['victimOnShift']=1 yield self.victimOnShift self.isWaitingForVictimOnShift=False self.victimOnShift=self.env.event() assert self.victim.onShift==True, 'the victim of shiftFailure must be onShift to continue counting the TTF' else: self.isWaitingForVictimOffShift=False failureNotTriggered=False # if time to failure counts only in working time elif self.deteriorationType=='working': # wait for victim to start process self.expectedSignals['victimStartsProcess']=1 yield self.victimStartsProcess self.victimStartsProcess=self.env.event() while failureNotTriggered: timeRestartedCounting=self.env.now self.expectedSignals['victimEndsProcess']=1 # wait either for the failure or end of process receivedEvent=yield self.env.timeout(remainingTimeToFailure) | self.victimEndsProcess if self.victimEndsProcess in receivedEvent: self.victimEndsProcess=self.env.event() remainingTimeToFailure=remainingTimeToFailure-(self.env.now-timeRestartedCounting) self.expectedSignals['victimStartsProcess']=1 yield self.victimStartsProcess # wait for victim to start again processing self.victimStartsProcess=self.env.event() else: failureNotTriggered=False # if the mode is to wait on tie before interruption add a dummy hold for 0 # this is done so that if processing finishes exactly at the time of interruption # the processing will finish first (if this mode is selected) if self.waitOnTie: if hasattr(self.victim, 'timeToEndCurrentOperation'): if float(self.victim.timeToEndCurrentOperation)==float(self.env.now): yield self.env.timeout(0) # interrupt the victim self.interruptVictim() # interrupt the victim # check in the ObjectInterruptions of the victim. If there is a one that is waiting for victimFailed send it for oi in self.victim.objectInterruptions: if oi.expectedSignals['victimFailed']: self.sendSignal(receiver=oi, signal=oi.victimFailed) self.victim.Up=False self.victim.timeLastFailure=self.env.now self.outputTrace(self.victim.name,"is down") # update the failure time failTime=self.env.now if(self.repairman and self.repairman!="None"): # if the failure needs a resource to be fixed, # the machine waits until the # resource is available with self.repairman.getResource().request() as request: yield request # update the time that the repair started timeOperationStarted=self.env.now self.repairman.timeLastOperationStarted=self.env.now yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up") self.repairman.totalWorkingTime+=self.env.now-timeOperationStarted continue yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over # add the failure # if victim is off shift add only the fail time before the shift ended if not self.victim.onShift and failTime < self.victim.timeLastShiftEnded: self.victim.totalFailureTime+=self.victim.timeLastShiftEnded-failTime # if the victim was off shift since the start of the failure add nothing elif not self.victim.onShift and failTime >= self.victim.timeLastShiftEnded: pass # if victim was off shift in the start of the fail time, add on elif self.victim.onShift and failTime < self.victim.timeLastShiftStarted: self.victim.totalFailureTime+=self.env.now-self.victim.timeLastShiftStarted # this can happen only if deteriorationType is constant assert self.deteriorationType=='constant', 'object got failure while off-shift and deterioration type not constant' else: self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up")
class Source(CoreObject): #=========================================================================== # the __init__method of the Source class #=========================================================================== def __init__(self, id, name, interArrivalTime=None, entity='Dream.Part',**kw): # Default values if not interArrivalTime: interArrivalTime = {'Fixed': {'mean': 1}} if 'Normal' in interArrivalTime.keys() and\ interArrivalTime['Normal'].get('max', None) is None: interArrivalTime['Normal']['max'] = interArrivalTime['Normal']['mean'] + 5 * interArrivalTime['Normal']['stdev'] CoreObject.__init__(self, id, name) # properties used for statistics self.totalinterArrivalTime = 0 # the total interarrival time self.numberOfArrivals = 0 # the number of entities that were created self.type="Source" #String that shows the type of object self.rng = RandomNumberGenerator(self, interArrivalTime) self.item=Globals.getClassFromName(entity) #the type of object that the Source will generate self.scheduledEntities=[] # list of creations that are scheduled. pattern is [timeOfCreation, EntityCounter] from Globals import G G.SourceList.append(self) #=========================================================================== # The initialize method of the Source class #=========================================================================== def initialize(self): # using the Process __init__ and not the CoreObject __init__ CoreObject.initialize(self) # initialize the internal Queue (type Resource) of the Source # self.Res=Resource(capacity=infinity) self.Res=simpy.Resource(self.env, capacity=float('inf')) self.Res.users=[] self.entityGenerator=EntityGenerator(victim=self) # the EntityGenerator of the Source self.numberOfArrivals = 0 # self.entityGenerator.initialize() # activate(self.entityGenerator,self.entityGenerator.run()) self.env.process(self.entityGenerator.run()) # self.entityCreated=SimEvent('an entity is created') self.entityCreated=self.env.event() # event used by router # self.loadOperatorAvailable=SimEvent('loadOperatorAvailable') self.loadOperatorAvailable=self.env.event() self.scheduledEntities=[] # list of creations that are scheduled self.expectedSignals['entityCreated']=1 self.expectedSignals['loadOperatorAvailable']=1 self.expectedSignals['canDispose']=1 #=========================================================================== # the generator of the Source class #=========================================================================== def run(self): # get active object and its queue activeObject=self.getActiveObject() activeObjectQueue=self.getActiveObjectQueue() while 1: # wait for any event (entity creation or request for disposal of entity) self.expectedSignals['canDispose']=1 self.expectedSignals['entityCreated']=1 self.expectedSignals['loadOperatorAvailable']=1 receivedEvent=yield self.env.any_of([self.entityCreated, self.canDispose, self.loadOperatorAvailable]) self.printTrace(self.id, received='') # if an entity is created try to signal the receiver and continue if self.entityCreated in receivedEvent: transmitter, eventTime=self.entityCreated.value self.entityCreated=self.env.event() # otherwise, if the receiver requests availability then try to signal him if there is anything to dispose of if self.canDispose in receivedEvent: transmitter, eventTime=self.canDispose.value self.canDispose=self.env.event() if self.loadOperatorAvailable in receivedEvent: transmitter, eventTime=self.loadOperatorAvailable.value self.loadOperatorAvailable=self.env.event() if self.haveToDispose(): if self.signalReceiver(): continue #=========================================================================== # add newly created entity to pendingEntities #=========================================================================== def appendEntity(self, entity): from Globals import G assert entity, 'cannot append None entity' activeEntity=entity if G.RouterList: # at the newly created entity to the pendingEntities G.pendingEntities.append(activeEntity) #============================================================================ # sets the routing out element for the Source #============================================================================ def defineRouting(self, successorList=[]): self.next=successorList # only successors allowed for the source #============================================================================ # creates an Entity #============================================================================ def createEntity(self): self.printTrace(self.id, create='') return self.item(id = self.item.type+str(G.numberOfEntities), name = self.item.type+str(self.numberOfArrivals)) #return the newly created Entity #============================================================================ # calculates the processing time #============================================================================ def calculateInterArrivalTime(self): return self.rng.generateNumber() #this is if we have a default interarrival time for all the entities # ======================================================================= # removes an entity from the Source # ======================================================================= def removeEntity(self, entity=None): if len(self.getActiveObjectQueue())==1 and len(self.scheduledEntities): newEntity=self.createEntity() # create the Entity object and assign its name newEntity.creationTime=self.scheduledEntities.pop(0) # assign the current simulation time as the Entity's creation time newEntity.startTime=newEntity.creationTime # assign the current simulation time as the Entity's start time #print self.env.now, 'getting from the list. StartTime=',newEntity.startTime newEntity.currentStation=self # update the current station of the Entity G.EntityList.append(newEntity) self.getActiveObjectQueue().append(newEntity) # append the entity to the resource self.numberOfArrivals+=1 # we have one new arrival G.numberOfEntities+=1 self.appendEntity(newEntity) activeEntity=CoreObject.removeEntity(self, entity) # run the default method if len(self.getActiveObjectQueue())==1: if self.expectedSignals['entityCreated']: self.sendSignal(receiver=self, signal=self.entityCreated) return activeEntity
class BatchScrapMachine(Machine): # ======================================================================= # constructor run every time a new instance is created # calls the Machine constructor, but also reads attributes for # scraping distribution # ======================================================================= def __init__(self, id, name, capacity=1, \ processingTime=None, repairman='None',\ scrapQuantity={}, operatorPool='None',operationType='None',\ setupTime=None, loadTime=None, canDeliverOnInterruption=False, **kw): if not processingTime: processingTime = {'distributionType': 'Fixed', 'mean': 1} # initialize using the default method of the object Machine.__init__(self,id=id,name=name,\ capacity=capacity,\ processingTime=processingTime, repairman=repairman, canDeliverOnInterruption=canDeliverOnInterruption, operatorPool=operatorPool,operationType=operationType,\ setupTime=setupTime, loadTime=loadTime, ) # set the attributes of the scrap quantity distribution if not scrapQuantity: scrapQuantity = {'Fixed': {'mean': 0}} self.scrapRng = RandomNumberGenerator(self, scrapQuantity) from Globals import G G.BatchScrapMachineList.append(self) # ======================================================================= # removes an Entity from the Object the Entity to be removed is passed # as argument by getEntity of the receiver # extends the default behaviour so that # it can scrap a number of units before disposing the Batch/SubBatch # ======================================================================= def removeEntity(self, entity=None): activeEntity = Machine.removeEntity(self, entity) scrapQuantity = self.scrapRng.generateNumber() activeEntity.numberOfUnits -= int( scrapQuantity ) # the scrapQuantity should be integer at whatever case if activeEntity.numberOfUnits < 0: activeEntity.numberOfUnits == 0 return activeEntity # ======================================================================= # calculates the processing time # extends the default behaviour so that # the per-unit processing time is multiplied with the number of units # ======================================================================= def calculateProcessingTime(self): activeEntity = self.getActiveObjectQueue()[0] # this is only for processing of the initial wip if self.isProcessingInitialWIP: if activeEntity.unitsToProcess: return self.rng.generateNumber() * activeEntity.unitsToProcess return self.rng.generateNumber() * activeEntity.numberOfUnits
class MouldAssembly(MachineJobShop): # ======================================================================= # parses inputs if they are given in a dictionary # ======================================================================= def parseInputs(self, **kw): from Globals import G G.MouldAssemblyList.append(self) # ======================================================================= # the initialize method # ======================================================================= def initialize(self): self.mouldParent = None # the mould's to be assembled parent order self.mouldToBeCreated = None # the mould to be assembled MachineJobShop.initialize(self) # run default behaviour # ======================================================================= # getEntity method that gets the entity from the giver # it should run in a loop till it get's all the entities from the same order # (with the flag componentsReadyForAssembly set) # it is run only once, and receives all the entities to be assembled inside a while loop # ======================================================================= def getEntity(self): activeObject = self.getActiveObject() giverObject = activeObject.getGiverObject() # get the first entity from the predecessor # TODO: each MachineJobShop.getEntity is invoked, # the self.procTime is updated. Have to decide where to assign # the processing time of the assembler activeEntity=MachineJobShop.getEntity(self) # this is kept so that in the next loop it will not try to re-get this Entity firstObtained=activeEntity # check weather the activeEntity is of type Mould if activeEntity.type=='Mould': # and return the mould received return activeEntity # otherwise, collect all the entities to be assembled # read the number of basic and secondary components of the moulds capacity = len(activeEntity.order.getAssemblyComponents()) # clear the active object queue del activeObject.getActiveObjectQueue()[:] # and set the capacity of the internal queue of the assembler activeObject.updateCapacity(capacity) # append the activeEntity to the activeObjectQueue activeObjectQueue = activeObject.getActiveObjectQueue() activeObjectQueue.append(activeEntity) # loop through the basic/secondary components of the order that is currently obtained # all the components are received at the same time for entity in activeEntity.order.getAssemblyComponents(): # continue for the one that is already obtained before if entity is firstObtained: continue self.entityToGet=entity # get the next component activeEntity=MachineJobShop.getEntity(self) # check whether the activeEntity is of type Mould try: if activeEntity.type=='Mould': # and return the mould received raise AssembleMouldError('Having already received an orderComponent the assembler\ is not supposed to receive an object of type Mould') # check if the last component received has the same parent order as the previous one elif not (activeEntity.order is activeObjectQueue[1].order): raise AssembleMouldError('The orderComponents received by the assembler must have the\ same parent order') except AssembleMouldError as mouldError: print 'Mould Assembly Error: {0}'.format(mouldError) return False # perform the assembly-action and return the assembled mould activeEntity = activeObject.assemble() return activeEntity # ======================================================================= # method that updates the capacity according to the componentsList of the # activeEntity's parent order # ======================================================================= def updateCapacity(self,capacity): activeObject = self.getActiveObject() self.capacity = capacity self.Res=simpy.Resource(self.env, self.capacity) # ======================================================================= # assemble method that assembles the components together to a mould (order # and returns the product of the assembly. Furthermore, it resets the capacity # of the internal queue to 1 # ======================================================================= def assemble(self): activeObject = self.getActiveObject() # get the internal queue of the active core object activeObjectQueue=activeObject.getActiveObjectQueue() # assert that all the components are of the same parent order for entity in activeObjectQueue: assert entity.order==activeObjectQueue[0].order,\ 'The components residing in the MouldAssembly internal queue\ are not of the same parent order!' # if we have to create a new Entity (mould) this should be modified # we need the new entity's route, priority, isCritical flag, etc. self.mouldParent = activeObjectQueue[0].order # assert that there is a parent order assert self.mouldParent.type=='Order', 'the type of the assembled to be mould\' s parent is not correct' # delete the contents of the internal queue temp_activeObjectQueue=list(activeObjectQueue) for element in temp_activeObjectQueue: # update their schedule element.schedule[-1]["exitTime"] = self.env.now # remove the elements from the activeObjectQueue and reset the current station of the entity activeObjectQueue.remove(element) element.currentStation=None del temp_activeObjectQueue[:] # after assembling reset the capacity activeObject.updateCapacity(1) #if there is a mould to be assembled try: if self.mouldParent: # find the component which is of type Mould # there must be only one mould component for entity in self.mouldParent.componentsList: entityClass=entity.get('_class', None) if entityClass=='Dream.Mould': self.mouldToBeCreated=entity break # create the mould self.createMould(self.mouldToBeCreated) # check if there is a need for manual processing self.checkForManualOperation(type='Processing',entity=self.mouldToBeCreated) # check if there is a need for manual processing self.checkForManualOperation(type='Setup',entity=self.mouldToBeCreated) # set the created mould as WIP import Globals Globals.setWIP([self.mouldToBeCreated]) # read the activeObjectQueue again as it has been updated by the setWIP() activeObjectQueue=activeObject.getActiveObjectQueue() # reset attributes self.mouldParent = None self.mouldToBeCreated = None # return the assembled mould return activeObjectQueue[0] else: raise AssembleMouldError('There is no mould to be assembled') except AssembleMouldError as mouldError: print 'Mould Assembly Error: {0}'.format(mouldError) # ======================================================================= # creates the mould # ======================================================================= def createMould(self, component): #read attributes from the json or from the orderToBeDecomposed id=component.get('id', 'not found') name=component.get('name', 'not found') try: # dummy variable that holds the routes of the jobs the route from the JSON file is a sequence of dictionaries JSONRoute=component.get('route', []) # variable that holds the argument used in the Job initiation hold None for each entry in the 'route' list route = [x for x in JSONRoute] # copy JSONRoute # assert that the assembler is in the moulds route and update the initial step of the mould's route firstStep = route.pop(0) assert (self.id in firstStep.get('stationIdsList',[])),\ 'the assembler must be in the mould-to-be-created route\' initial step' # normal processing operation processingTime=firstStep['processingTime'] processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # update the activeObject's processing time according to the readings in the mould's route processDistType=processingTime.keys()[0] procTime=float(processingTime[processDistType].get('mean', 0)) processOpType=firstStep.get('operationType',{}).get('Processing','not found') # can be manual/automatic # task_id task_id = firstStep.get('task_id', None) # sequence sequence = firstStep.get('sequence', None) # operator operator = firstStep.get('operator', {}) # technology technology = firstStep.get('technology', None) # quantity quantity = firstStep.get('quantity', None) # setup operation setupTime=firstStep.get('setupTime',None) if setupTime: setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # update the activeObject's processing time according to the readings in the mould's route setupDistType=setupTime.keys()[0] setTime=float(setupTime[setupDistType].get('mean', 0)) setupOpType=firstStep.get('operationType',{}).get('Setup','not found') # can be manual/automatic # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}},\ 'setupTime':{str(setupDistType):{'mean':str(setupTime)}}, 'operationType':{'Processing':processOpType,'Setup':setupOpType}}) else: # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}}, 'operationType':{'Processing':processOpType}}) # if there is task_id then add it to the route if task_id: route[0]["task_id"] = task_id # if there is sequence then add it to the route if sequence: route[0]["sequence"] = sequence # if there is operator then add it to the route if operator: route[0]["operator"] = operator # if there is technology then add it to the route if technology: route[0]["technology"] = technology # if there is quantity then add it to the route if quantity!=None: route[0]["quantity"] = quantity #Below it is to assign an exit if it was not assigned in JSON #have to talk about it with NEX exitAssigned=False for element in route: elementIds = element.get('stationIdsList',[]) for obj in G.ObjList: for elementId in elementIds: if obj.id==elementId and obj.type=='Exit': exitAssigned=True # assign an exit to the route of the mould if not exitAssigned: exitId=None for obj in G.ObjList: if obj.type=='Exit': exitId=obj.id break if exitId: route.append({'stationIdsList':[str(exitId)],'processingTime':{}}) # keep a reference of all extra properties passed to the job extraPropertyDict = {} for key, value in component.items(): if key not in ('_class', 'id'): extraPropertyDict[key] = value # create and initiate the OrderComponent from Mould import Mould M=Mould(id, name, route, \ priority=self.mouldParent.priority, \ order=self.mouldParent,\ dueDate=self.mouldParent.dueDate, \ orderDate=self.mouldParent.orderDate, \ extraPropertyDict=extraPropertyDict,\ isCritical=self.mouldParent.isCritical) # update the mouldToBeCreated self.mouldToBeCreated=M G.JobList.append(M) G.WipList.append(M) G.EntityList.append(M) G.MouldList.append(M) #initialize the component M.initialize() except: # added for testing print 'the mould to be created', component.get('name', 'not found'), 'cannot be created', 'time', self.env.now raise
class Failure(ObjectInterruption): def __init__(self, id='',name='',victim=None, distribution=None, index=0, repairman=None, offshift=False, deteriorationType='constant',**kw): ObjectInterruption.__init__(self,id,name,victim=victim) if distribution: self.distType=distribution.get('distributionType','No') # the distribution that the failure duration follows self.MTTF=distribution.get('MTTF',60) # the MTTF self.MTTR=distribution.get('MTTR',5) # the MTTR self.availability=distribution.get('availability',100) # the availability else: self.distType='No' self.MTTF=60 self.MTTR=5 self.availability=100 self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" # shows how the time to failure is measured # 'constant' means it counts not matter the state of the victim # 'onShift' counts only if the victim is onShift # 'working' counts only working time self.deteriorationType=deteriorationType if(self.distType=="Availability"): # -------------------------------------------------------------- # the following are used if we have availability defined # (as in plant) the erlang is a special case of Gamma. # To model the Mu and sigma (that is given in plant) # as alpha and beta for gamma you should do the following: # beta=(sigma^2)/Mu # alpha=Mu/beta # -------------------------------------------------------------- self.AvailabilityMTTF=self.MTTR*(float(availability)/100)/(1-(float(availability)/100)) self.sigma=0.707106781185547*self.MTTR self.theta=(pow(self.sigma,2))/float(self.MTTR) self.beta=self.theta self.alpha=(float(self.MTTR)/self.theta) self.rngTTF=RandomNumberGenerator(self, "Exp") self.rngTTF.avg=self.AvailabilityMTTF self.rngTTR=RandomNumberGenerator(self, "Erlang") self.rngTTR.alpha=self.alpha self.rngTTR.beta=self.beta else: # -------------------------------------------------------------- # if the distribution is fixed # -------------------------------------------------------------- self.rngTTF=RandomNumberGenerator(self, self.distType) self.rngTTF.mean=self.MTTF self.rngTTR=RandomNumberGenerator(self, self.distType) self.rngTTR.mean=self.MTTR # flag used to identify if the time between failures should be counted while the victim is off-shift self.offshift=offshift def initialize(self): ObjectInterruption.initialize(self) self.victimStartsProcess=self.env.event() self.victimEndsProcess=self.env.event() # ======================================================================= # The run method for the failure which has to served by a repairman # ======================================================================= def run(self): while 1: # if the time that the victim is off-shift should not be counted timeToFailure=self.rngTTF.generateNumber() remainingTimeToFailure=timeToFailure failureNotTriggered=True # if time to failure counts not matter the state of the victim if self.deteriorationType=='constant': yield self.env.timeout(remainingTimeToFailure) # if time to failure counts only in onShift time elif self.deteriorationType=='onShift': while failureNotTriggered: timeRestartedCounting=self.env.now self.isWaitingForVictimOffShift=True self.expectedSignals['victimOffShift']=1 receivedEvent=yield self.env.timeout(remainingTimeToFailure) | self.victimOffShift # the failure should receive a signal if there is a shift-off triggered if self.victimOffShift in receivedEvent: assert self.victim.onShift==False, 'shiftFailure cannot recalculate TTF if the victim is onShift' self.victimOffShift=self.env.event() remainingTimeToFailure=remainingTimeToFailure-(self.env.now-timeRestartedCounting) # wait for the shift to start again self.isWaitingForVictimOnShift=True self.expectedSignals['victimOnShift']=1 yield self.victimOnShift self.isWaitingForVictimOnShift=False self.victimOnShift=self.env.event() assert self.victim.onShift==True, 'the victim of shiftFailure must be onShift to continue counting the TTF' else: self.isWaitingForVictimOffShift=False failureNotTriggered=False # if time to failure counts only in working time elif self.deteriorationType=='working': # wait for victim to start process self.expectedSignals['victimStartsProcess']=1 yield self.victimStartsProcess self.victimStartsProcess=self.env.event() while failureNotTriggered: timeRestartedCounting=self.env.now self.expectedSignals['victimEndsProcess']=1 # wait either for the failure or end of process receivedEvent=yield self.env.timeout(remainingTimeToFailure) | self.victimEndsProcess if self.victimEndsProcess in receivedEvent: self.victimEndsProcess=self.env.event() remainingTimeToFailure=remainingTimeToFailure-(self.env.now-timeRestartedCounting) self.expectedSignals['victimStartsProcess']=1 yield self.victimStartsProcess # wait for victim to start again processing self.victimStartsProcess=self.env.event() else: failureNotTriggered=False # interrupt the victim self.interruptVictim() # interrupt the victim self.victim.Up=False self.victim.timeLastFailure=self.env.now self.outputTrace(self.victim.name,"is down") # update the failure time failTime=self.env.now if(self.repairman and self.repairman!="None"): # if the failure needs a resource to be fixed, # the machine waits until the # resource is available with self.repairman.getResource().request() as request: yield request # update the time that the repair started timeOperationStarted=self.env.now self.repairman.timeLastOperationStarted=self.env.now yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up") self.repairman.totalWorkingTime+=self.env.now-timeOperationStarted continue yield self.env.timeout(self.rngTTR.generateNumber()) # wait until the repairing process is over # add the failure # if victim is off shift add only the fail time before the shift ended if not self.victim.onShift and failTime < self.victim.timeLastShiftEnded: self.victim.totalFailureTime+=self.victim.timeLastShiftEnded-failTime # if the victim was off shift since the start of the failure add nothing elif not self.victim.onShift and failTime >= self.victim.timeLastShiftEnded: pass # if victim was off shift in the start of the fail time, add on elif self.victim.onShift and failTime < self.victim.timeLastShiftStarted: self.victim.totalFailureTime+=self.env.now-self.victim.timeLastShiftStarted # this can happen only if deteriorationType is constant assert self.deteriorationType=='constant', 'object got failure while off-shift and deterioration type not constant' else: self.victim.totalFailureTime+=self.env.now-failTime self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace(self.victim.name,"is up")
def main(): seed = int(input("Wprowadź Z: ")) generator = RandomNumberGenerator(seed) taskNumber = int(input("Wprowadź liczbę zadań: ")) tasks = range(1, taskNumber + 1) machineNumber = int(input("Wprowadź liczbę maszyn: ")) machines = range(1, machineNumber + 1) Pi = [] #Permutacja po uszeregowaniu P = [] # Macierz czas wykonania Nr = [] # Lista zadań do wykonania P_Copy = [] #Macierz czasów wykonania Nr_Copy = [] # Lista zadań do wykonania C = [] # Macierz czasów zakończenia zadań S = [] # Macierz czasów trwania zadań for i in range(1, taskNumber + 1): Pi.append(i) for i in range(0, taskNumber): z = [None] * machineNumber C.append(z) for i in range(0, taskNumber): x = [None] * machineNumber S.append(x) for i in range(0, taskNumber): p = [] for j in range(0, machineNumber): p.append(generator.nextInt(1, 29)) P.append(p) P_Copy.append(p) for i in range(1, taskNumber + 1): Nr.append(i) Nr_Copy.append(i) print("\n") print("Tabu Calculate:") tabu_calculate(taskNumber, machineNumber, C, P, Pi, S) print(f"Pi: {Pi}") print(f"P: {P}") print(f"C: {C}") print(f"Cmax: {calculate_cmax(machineNumber,Pi,P)}") tabu_time_start = datetime.datetime.now() newPi = tabuSearch(taskNumber, machineNumber, P, Pi) tabu_time_end = datetime.datetime.now() - tabu_time_start newP = [] for i in range(0, taskNumber): newP.append(P[newPi[i] - 1]) tabu_calculate(taskNumber, machineNumber, C, newP, newPi, S) C, Cmax = calculate_neh(newP, taskNumber, machineNumber) print(f"Tabu search czas: {tabu_time_end}") print(f"Tabu search po sortowaniu: ") print(f"Pi: {newPi}") print(f"C: {C}") print(f"Cmax: {Cmax}") #lista wszystkich zadan na konkretnych maszynach p_ij_neh = P # permutacja zadan pi_neh = Nr p_kj = [] print("\n") print("NEH:") print("p", p_ij_neh) print("Permutacj naturalna: ") print("pi: ", pi_neh) Cj, Cmax = calculate_neh(p_ij_neh, taskNumber, machineNumber) print("C:", Cj) print("Cmax:", Cmax) neh_time_start = datetime.datetime.now() p_kj = NEH(p_ij_neh.copy(), taskNumber, machineNumber) neh_time_end = datetime.datetime.now() - neh_time_start print(f"NEH czas: {neh_time_end}") print("NEH po sortowaniu: ") print("pkj: ", p_kj) Cj, Cmax = calculate_neh(p_kj, taskNumber, machineNumber) print("C:", Cj) print("Cmax:", Cmax) #lista wszystkich zadan na konkretnych maszynach p_ij_johnson = P # permutacja zadan pi_johnson = Nr # wyswietlenie rozwiazania po wykonaniu algorytmu optymalizacji solution = [] print("\n") print("Johnson:") print(p_ij_johnson) print("Permutacj naturalna: ") print("pi: ", pi_johnson) Cj, Cmax = calculate_johnson(p_ij_johnson, taskNumber, machineNumber) print("C:", Cj) print("Cmax:", Cmax) for task in tasks: solution.append([pi_johnson[task - 1], p_ij_johnson[task - 1]]) johson_time_start = datetime.datetime.now() pi = Johnson(tasks, p_ij_johnson.copy()) johson_time_end = datetime.datetime.now() - johson_time_start print(f"Johson czas: {johson_time_end}") print("Johnson po sortowaniu: ") print("pi: ", pi) sort = {x: i for i, x in enumerate(pi)} solution.sort(key=lambda x: sort[x[0]]) Cj, Cmax = calculate_johnson([row[1] for row in solution], taskNumber, machineNumber) print("C", Cj) print("Cmax:", Cmax)
class MachineJobShop(Machine): @staticmethod def getProcessingTime(processingTime): '''returns the processingTime dictionary updated''' if not processingTime: processingTime = { 'distributionType': 'Fixed', 'mean': 0, } if processingTime['distributionType'] == 'Normal' and\ processingTime.get('max', None) is None: processingTime['max'] = float(processingTime['mean']) + 5 * float(processingTime['stdev']) return processingTime @staticmethod def getSetupTime(setupTime): '''returns the setupTime dictionary updated''' if not setupTime: setupTime = { 'distributionType': 'Fixed', 'mean': 0, } if setupTime['distributionType'] == 'Normal' and\ setupTime.get('max', None) is None: setupTime['max'] = float(setupTime['mean']) + 5 * float(setupTime['stdev']) return setupTime @staticmethod def getLoadTime(loadTime): '''returns the loadTime dictionary updated''' if not loadTime: loadTime = { 'distributionType': 'Fixed', 'mean': 0, } if loadTime['distributionType'] == 'Normal' and\ loadTime.get('max', None) is None: loadTime['max'] = float(loadTime['mean']) + 5 * float(loadTime['stdev']) return loadTime # ======================================================================= # set all the objects in previous and next # ======================================================================= def initialize(self): from Globals import G self.previous=G.ObjList self.next=[] Machine.initialize(self) #run default behaviour # # ======================================================================= # # actions to be carried out when the processing of an Entity ends # # ======================================================================= # def endProcessingActions(self): # # set isProcessing to False # self.isProcessing=False # # add working time # self.totalWorkingTime+=self.env.now-self.timeLastProcessingStarted # # # blocking starts # self.isBlocked=True # self.timeLastBlockageStarted=self.env.now # # activeObject=self.getActiveObject() # activeObjectQueue=activeObject.Res.users # activeEntity=activeObjectQueue[0] # # self.printTrace(activeEntity.name,processEnd=activeObject.objName) # # reset the variables used to handle the interruptions timing # # self.timeRestartingProcessing=0 # self.breakTime=0 # # output to trace that the processing in the Machine self.objName ended # try: # activeObject.outputTrace(activeEntity.name,"ended processing in "+activeObject.objName) # except IndexError: # pass # # import Globals # from Globals import G # # the entity that just got processed is cold again it will get # # hot again by the time it reaches the giver of the next machine # # TODO: Not only Machines require time to process entities # if activeEntity.family=='Job': # # read the list of next stations for the entity in just finished processing # nextObjectIds=activeEntity.remainingRoute[0].get('stationIdsList',[]) # nextObjects = [] # for nextObjectId in nextObjectIds: # nextObject=Globals.findObjectById(nextObjectId) # nextObjects.append(nextObject) # successorsAreMachines=True # for object in nextObjects: # if not object in G.MachineList: # successorsAreMachines=False # break # if not successorsAreMachines: # activeObjectQueue[0].hot = False # # the just processed entity is added to the list of entities # # pending for the next processing # G.pendingEntities.append(activeObjectQueue[0]) # # set the variable that flags an Entity is ready to be disposed # activeObject.waitToDispose=True # #do this so that if it is overtime working it is not counted as off-shift time # if not activeObject.onShift: # activeObject.timeLastShiftEnded=self.env.now # # update the variables keeping track of Entity related attributes of the machine # activeObject.timeLastEntityEnded=self.env.now # this holds the time that the last entity ended processing in Machine # activeObject.nameLastEntityEnded=activeObject.currentEntity.name # this holds the name of the last entity that ended processing in Machine # activeObject.completedJobs+=1 # Machine completed one more Job # # reset flags # self.shouldPreempt=False # self.isProcessingInitialWIP=False # # # TODO: collapse that to Machine # ======================================================================= # gets an entity from the predecessor that the predecessor index points to # ======================================================================= def getEntity(self): activeObject=self.getActiveObject() activeEntity=Machine.getEntity(self) #run the default code # read the processing/setup/load times from the corresponding remainingRoute entry processingTime=activeEntity.remainingRoute[0].get('processingTime',{}) processingTime=self.getProcessingTime(processingTime) self.rng=RandomNumberGenerator(self, **processingTime) self.procTime=self.rng.generateNumber() setupTime=activeEntity.remainingRoute[0].get('setupTime',{}) setupTime=self.getSetupTime(setupTime) self.stpRng=RandomNumberGenerator(self, **setupTime) removedStep = activeEntity.remainingRoute.pop(0) #remove data from the remaining route of the entity return activeEntity #=========================================================================== # update the next list of the object based on the activeEentity #=========================================================================== def updateNext(self,entity=None): activeObject = self.getActiveObject() activeEntity=entity # read the possible receivers - update the next list import Globals # XXX: in the case of MouldAssembler there is no next defined in the route of the entities that are received # the position activeEntity.remainingRoute[1] is out of bound. the next should be updated by the remaining route of the entity to be assembled if len(activeEntity.remainingRoute)>1: nextObjectIds=activeEntity.remainingRoute[1].get('stationIdsList',[]) nextObjects = [] for nextObjectId in nextObjectIds: nextObject = Globals.findObjectById(nextObjectId) nextObjects.append(nextObject) # update the next list of the object for nextObject in nextObjects: # append only if not already in the list if nextObject not in activeObject.next: activeObject.next.append(nextObject) # ======================================================================= # calculates the processing time # ======================================================================= def calculateProcessingTime(self): # this is only for processing of the initial wip if self.isProcessingInitialWIP: # read the processing/setup/load times from the first entry of the full route activeEntity=self.getActiveObjectQueue()[0] processingTime=activeEntity.route[0].get('processingTime',{}) processingTime=self.getProcessingTime(processingTime) self.rng=RandomNumberGenerator(self, **processingTime) self.procTime=self.rng.generateNumber() setupTime=activeEntity.route[0].get('setupTime',{}) setupTime=self.getSetupTime(setupTime) self.stpRng=RandomNumberGenerator(self, **setupTime) return self.procTime #this is the processing time for this unique entity # ======================================================================= # checks if the Queue can accept an entity # it checks also the next station of the Entity # and returns true only if the active object is the next station # ======================================================================= def canAccept(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #return according to the state of the Queue # also check if (if the machine is to be operated) there are available operators if (self.operatorPool!='None' and (any(type=='Load' for type in self.multOperationTypeList))): return self.operatorPool.checkIfResourceIsAvailable()\ and len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRoute(thecaller)\ and not self.entryIsAssignedTo() else: return len(activeObjectQueue)<self.capacity\ and self.checkIfMachineIsUp()\ and self.isInRoute(thecaller)\ and not self.entryIsAssignedTo() #=========================================================================== # method used to check whether the station is in the entity-to-be-received route # TODO: consider giving the activeEntity as attribute # TODO: consider the case when no caller is defined, # postProcessing calls canAccept on next members with no arguments #=========================================================================== def isInRoute(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject # if the caller is not defined then return True. We are only interested in checking whether # the station can accept whatever entity from whichever giver if not thecaller: return True #check it the caller object holds an Entity that requests for current object if len(thecaller.Res.users)>0: # TODO: make sure that the first entity of the callerObject is to be disposed activeEntity=thecaller.Res.users[0] # if the machine's Id is in the list of the entity's next stations if self.id in activeEntity.remainingRoute[0].get('stationIdsList',[]): return True return False # ======================================================================= # checks if the Machine can dispose an entity. # Returns True only to the potential receiver # ======================================================================= def haveToDispose(self, callerObject=None): activeObjectQueue=self.Res.users thecaller=callerObject #if we have only one successor just check if machine waits to dispose and also is up # this is done to achieve better (cpu) processing time if(callerObject==None): return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ #return True if the Machine in the state of disposing and the caller is the receiver return len(activeObjectQueue)>0\ and self.waitToDispose\ and self.checkIfActive()\ and (thecaller in self.next)\ and thecaller.isInRoute(self) # ======================================================================= # method to execute preemption # ======================================================================= def preempt(self): # self.printTrace(self.id,preempted='') activeEntity=self.Res.users[0] #get the active Entity #calculate the remaining processing time #if it is reset then set it as the original processing time if self.resetOnPreemption: remainingProcessingTime=self.procTime #else subtract the time that passed since the entity entered #(may need also failure time if there was. TO BE MELIORATED) else: remainingProcessingTime=self.procTime-(self.env.now-self.timeLastEntityEntered) #update the remaining route of activeEntity activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.id)],\ 'processingTime':\ {'distributionType':'Fixed',\ 'mean':str(remainingProcessingTime)}}) activeEntity.remainingRoute.insert(0, {'stationIdsList':[str(self.lastGiver.id)],\ 'processingTime':\ {'distributionType':'Fixed',\ 'mean':'0'}}) #set the receiver as the object where the active entity was preempted from self.receiver=self.lastGiver self.next=[self.receiver] self.waitToDispose=True #set that I have to dispose self.receiver.timeLastEntityEnded=self.env.now #required to count blockage correctly in the preemptied station # TODO: use a signal and wait for it, reactivation is not recognised as interruption # reactivate(self) if self.expectedSignals['preemptQueue']: self.sendSignal(receiver=self, signal=self.preemptQueue) # TODO: consider the case when a failure has the Station down. The event preempt will not be received now() # but at a later simulation time. #=========================================================================== # extend the default behaviour to check if whether the station # is in the route of the entity to be received #=========================================================================== def canAcceptAndIsRequested(self,callerObject): giverObject=callerObject assert giverObject, 'there must be a caller for canAcceptAndIsRequested' if self.isInRoute(giverObject): if Machine.canAcceptAndIsRequested(self,giverObject): self.readLoadTime(giverObject) return True return False #=========================================================================== # to be called by canAcceptAndIsRequested if it is to return True. # the load timeof the Entity must be read #=========================================================================== def readLoadTime(self,callerObject=None): assert callerObject!=None, 'the caller of readLoadTime cannot be None' thecaller=callerObject thecaller.sortEntities() activeEntity=thecaller.Res.users[0] loadTime=activeEntity.remainingRoute[0].get('loadTime',{}) loadTime=self.getLoadTime(loadTime) self.loadRng=RandomNumberGenerator(self, **loadTime) # ======================================================================= # removes an entity from the Machine # extension to remove possible receivers accordingly # ======================================================================= def removeEntity(self, entity=None): receiverObject=self.receiver activeEntity=Machine.removeEntity(self, entity) #run the default method removeReceiver=True # search in the internalQ. If an entity has the same receiver do not remove for ent in self.Res.users: nextObjectIds=ent.remainingRoute[0].get('stationIdsList',[]) if receiverObject.id in nextObjectIds: removeReceiver=False # if not entity had the same receiver then the receiver will be removed if removeReceiver: self.next.remove(receiverObject) return activeEntity
def createMould(self, component): #read attributes from the json or from the orderToBeDecomposed id = component.get('id', 'not found') name = component.get('name', 'not found') try: # dummy variable that holds the routes of the jobs the route from the JSON file is a sequence of dictionaries JSONRoute = component.get('route', []) # variable that holds the argument used in the Job initiation hold None for each entry in the 'route' list route = [x for x in JSONRoute] # copy JSONRoute # assert that the assembler is in the moulds route and update the initial step of the mould's route firstStep = route.pop(0) assert (self.id in firstStep.get('stationIdsList',[])),\ 'the assembler must be in the mould-to-be-created route\' initial step' # normal processing operation processingTime = firstStep['processingTime'] processingTime = self.getOperationTime(processingTime) self.rng = RandomNumberGenerator(self, processingTime) self.procTime = self.rng.generateNumber() # update the activeObject's processing time according to the readings in the mould's route processDistType = processingTime.keys()[0] procTime = float(processingTime[processDistType].get('mean', 0)) processOpType = firstStep.get('operationType', {}).get( 'Processing', 'not found') # can be manual/automatic # task_id task_id = firstStep.get('task_id', None) # sequence sequence = firstStep.get('sequence', None) # operator operator = firstStep.get('operator', {}) # technology technology = firstStep.get('technology', None) # quantity quantity = firstStep.get('quantity', None) # setup operation setupTime = firstStep.get('setupTime', None) if setupTime: setupTime = self.getOperationTime(setupTime) self.stpRng = RandomNumberGenerator(self, setupTime) # update the activeObject's processing time according to the readings in the mould's route setupDistType = setupTime.keys()[0] setTime = float(setupTime[setupDistType].get('mean', 0)) setupOpType = firstStep.get('operationType', {}).get( 'Setup', 'not found') # can be manual/automatic # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}},\ 'setupTime':{str(setupDistType):{'mean':str(setupTime)}}, 'operationType':{'Processing':processOpType,'Setup':setupOpType}}) else: # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert( 0, { 'stationIdsList': [str(self.id)], 'processingTime': { str(processDistType): { 'mean': str(procTime) } }, 'operationType': { 'Processing': processOpType } }) # if there is task_id then add it to the route if task_id: route[0]["task_id"] = task_id # if there is sequence then add it to the route if sequence: route[0]["sequence"] = sequence # if there is operator then add it to the route if operator: route[0]["operator"] = operator # if there is technology then add it to the route if technology: route[0]["technology"] = technology # if there is quantity then add it to the route if quantity != None: route[0]["quantity"] = quantity #Below it is to assign an exit if it was not assigned in JSON #have to talk about it with NEX exitAssigned = False for element in route: elementIds = element.get('stationIdsList', []) for obj in G.ObjList: for elementId in elementIds: if obj.id == elementId and obj.type == 'Exit': exitAssigned = True # assign an exit to the route of the mould if not exitAssigned: exitId = None for obj in G.ObjList: if obj.type == 'Exit': exitId = obj.id break if exitId: route.append({ 'stationIdsList': [str(exitId)], 'processingTime': {} }) # keep a reference of all extra properties passed to the job extraPropertyDict = {} for key, value in component.items(): if key not in ('_class', 'id'): extraPropertyDict[key] = value # create and initiate the OrderComponent from Mould import Mould M=Mould(id, name, route, \ priority=self.mouldParent.priority, \ order=self.mouldParent,\ dueDate=self.mouldParent.dueDate, \ orderDate=self.mouldParent.orderDate, \ extraPropertyDict=extraPropertyDict,\ isCritical=self.mouldParent.isCritical) # update the mouldToBeCreated self.mouldToBeCreated = M G.JobList.append(M) G.WipList.append(M) G.EntityList.append(M) G.MouldList.append(M) #initialize the component M.initialize() except: # added for testing print 'the mould to be created', component.get( 'name', 'not found'), 'cannot be created', 'time', self.env.now raise
def createMould(self, component): #read attributes from the json or from the orderToBeDecomposed id=component.get('id', 'not found') name=component.get('name', 'not found') try: # dummy variable that holds the routes of the jobs the route from the JSON file is a sequence of dictionaries JSONRoute=component.get('route', []) # variable that holds the argument used in the Job initiation hold None for each entry in the 'route' list route = [x for x in JSONRoute] # copy JSONRoute # assert that the assembler is in the moulds route and update the initial step of the mould's route firstStep = route.pop(0) assert (self.id in firstStep.get('stationIdsList',[])),\ 'the assembler must be in the mould-to-be-created route\' initial step' # normal processing operation processingTime=firstStep['processingTime'] processingTime=self.getOperationTime(processingTime) self.rng=RandomNumberGenerator(self, processingTime) self.procTime=self.rng.generateNumber() # update the activeObject's processing time according to the readings in the mould's route processDistType=processingTime.keys()[0] procTime=float(processingTime[processDistType].get('mean', 0)) processOpType=firstStep.get('operationType',{}).get('Processing','not found') # can be manual/automatic # task_id task_id = firstStep.get('task_id', None) # sequence sequence = firstStep.get('sequence', None) # operator operator = firstStep.get('operator', {}) # technology technology = firstStep.get('technology', None) # quantity quantity = firstStep.get('quantity', None) # setup operation setupTime=firstStep.get('setupTime',None) if setupTime: setupTime=self.getOperationTime(setupTime) self.stpRng=RandomNumberGenerator(self, setupTime) # update the activeObject's processing time according to the readings in the mould's route setupDistType=setupTime.keys()[0] setTime=float(setupTime[setupDistType].get('mean', 0)) setupOpType=firstStep.get('operationType',{}).get('Setup','not found') # can be manual/automatic # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}},\ 'setupTime':{str(setupDistType):{'mean':str(setupTime)}}, 'operationType':{'Processing':processOpType,'Setup':setupOpType}}) else: # update the first step of the route with the activeObjects id as sole element of the stationIdsList route.insert(0, {'stationIdsList':[str(self.id)], 'processingTime':{str(processDistType):{'mean':str(procTime)}}, 'operationType':{'Processing':processOpType}}) # if there is task_id then add it to the route if task_id: route[0]["task_id"] = task_id # if there is sequence then add it to the route if sequence: route[0]["sequence"] = sequence # if there is operator then add it to the route if operator: route[0]["operator"] = operator # if there is technology then add it to the route if technology: route[0]["technology"] = technology # if there is quantity then add it to the route if quantity!=None: route[0]["quantity"] = quantity #Below it is to assign an exit if it was not assigned in JSON #have to talk about it with NEX exitAssigned=False for element in route: elementIds = element.get('stationIdsList',[]) for obj in G.ObjList: for elementId in elementIds: if obj.id==elementId and obj.type=='Exit': exitAssigned=True # assign an exit to the route of the mould if not exitAssigned: exitId=None for obj in G.ObjList: if obj.type=='Exit': exitId=obj.id break if exitId: route.append({'stationIdsList':[str(exitId)],'processingTime':{}}) # keep a reference of all extra properties passed to the job extraPropertyDict = {} for key, value in component.items(): if key not in ('_class', 'id'): extraPropertyDict[key] = value # create and initiate the OrderComponent from Mould import Mould M=Mould(id, name, route, \ priority=self.mouldParent.priority, \ order=self.mouldParent,\ dueDate=self.mouldParent.dueDate, \ orderDate=self.mouldParent.orderDate, \ extraPropertyDict=extraPropertyDict,\ isCritical=self.mouldParent.isCritical) # update the mouldToBeCreated self.mouldToBeCreated=M G.JobList.append(M) G.WipList.append(M) G.EntityList.append(M) G.MouldList.append(M) #initialize the component M.initialize() except: # added for testing print 'the mould to be created', component.get('name', 'not found'), 'cannot be created', 'time', self.env.now raise
class Failure(ObjectInterruption): def __init__(self, victim=None, distribution=None, index=0, repairman=None): #Process.__init__(self) ObjectInterruption.__init__(self,victim) if distribution: self.distType=distribution.get('distributionType','No') # the distribution that the failure duration follows self.MTTF=distribution.get('MTTF',60) # the MTTF self.MTTR=distribution.get('MTTR',5) # the MTTR self.availability=distribution.get('availability',100) # the availability else: self.distType='No' self.MTTF=60 self.MTTR=5 self.availability=100 self.name="F"+str(index) self.repairman=repairman # the resource that may be needed to fix the failure # if now resource is needed this will be "None" self.type="Failure" self.id=0 if(self.distType=="Availability"): # -------------------------------------------------------------- # the following are used if we have availability defined # (as in plant) the erlang is a special case of Gamma. # To model the Mu and sigma (that is given in plant) # as alpha and beta for gamma you should do the following: # beta=(sigma^2)/Mu # alpha=Mu/beta # -------------------------------------------------------------- self.AvailabilityMTTF=self.MTTR*(float(availability)/100)/(1-(float(availability)/100)) self.sigma=0.707106781185547*self.MTTR self.theta=(pow(self.sigma,2))/float(self.MTTR) self.beta=self.theta self.alpha=(float(self.MTTR)/self.theta) self.rngTTF=RandomNumberGenerator(self, "Exp") self.rngTTF.avg=self.AvailabilityMTTF self.rngTTR=RandomNumberGenerator(self, "Erlang") self.rngTTR.alpha=self.alpha self.rngTTR.beta=self.beta else: # -------------------------------------------------------------- # if the distribution is fixed # -------------------------------------------------------------- self.rngTTF=RandomNumberGenerator(self, self.distType) self.rngTTF.mean=self.MTTF self.rngTTR=RandomNumberGenerator(self, self.distType) self.rngTTR.mean=self.MTTR # ======================================================================= # The run method for the failure which has to served by a repairman # ======================================================================= def run(self): while 1: yield hold,self,self.rngTTF.generateNumber() # wait until a failure happens if(len(self.getVictimQueue())>0): # when a Machine gets failure self.interruptVictim() # while in process it is interrupted self.victim.Up=False self.victim.timeLastFailure=now() self.outputTrace("is down") # update the failure time failTime=now() if(self.repairman and self.repairman!="None"): #if the failure needs a resource to be fixed, the machine waits until the #resource is available yield request,self,self.repairman.getResource() # update the time that the repair started timeOperationStarted=now() self.repairman.timeLastOperationStarted=now() yield hold,self,self.rngTTR.generateNumber() # wait until the repairing process is over self.victim.totalFailureTime+=now()-failTime if(len(self.getVictimQueue())>0): self.reactivateVictim() # since repairing is over, the Machine is reactivated self.victim.Up=True self.outputTrace("is up") if(self.repairman and self.repairman!="None"): #if a resource was used, it is now released yield release,self,self.repairman.getResource() self.repairman.totalWorkingTime+=now()-timeOperationStarted