def initialize(self): Machine.initialize(self) # initiate the Broker responsible to control the request/release # initialize the operator pool if any if (self.operatorPool != "None"): self.operatorPool.initialize() self.broker = Broker(self) activate(self.broker, self.broker.run()) for operator in self.operatorPool.operators: operator.coreObjectIds.append(self.id) operator.coreObjects.append(self) # the time that the machine started/ended its wait for the operator self.timeWaitForOperatorStarted = 0 self.timeWaitForOperatorEnded = 0 self.totalTimeWaitingForOperator = 0 # the time that the machine started/ended its wait for the operator self.timeWaitForLoadOperatorStarted = 0 self.timeWaitForLoadOperatorEnded = 0 self.totalTimeWaitingForLoadOperator = 0 # the time that the operator started/ended loading the machine self.timeLoadStarted = 0 self.timeLoadEnded = 0 self.totalLoadTime = 0 # the time that the operator started/ended setting-up the machine self.timeSetupStarted = 0 self.timeSetupEnded = 0 self.totalSetupTime = 0 # Current entity load/setup/loadOperatorwait/operatorWait related times self.operatorWaitTimeCurrentEntity = 0 # holds the time that the machine was waiting for the operator self.loadOperatorWaitTimeCurrentEntity = 0 # holds the time that the machine waits for operator to load the it self.loadTimeCurrentEntity = 0 # holds the time to load the current entity self.setupTimeCurrentEntity = 0 # holds the time to setup the machine before processing the current entity
def initialize(self): Machine.initialize(self) # initiate the Broker responsible to control the request/release # initialize the operator pool if any if self.operatorPool != "None": self.operatorPool.initialize() self.broker = Broker(self) activate(self.broker, self.broker.run()) for operator in self.operatorPool.operators: operator.coreObjectIds.append(self.id) operator.coreObjects.append(self) # the time that the machine started/ended its wait for the operator self.timeWaitForOperatorStarted = 0 self.timeWaitForOperatorEnded = 0 self.totalTimeWaitingForOperator = 0 # the time that the machine started/ended its wait for the operator self.timeWaitForLoadOperatorStarted = 0 self.timeWaitForLoadOperatorEnded = 0 self.totalTimeWaitingForLoadOperator = 0 # the time that the operator started/ended loading the machine self.timeLoadStarted = 0 self.timeLoadEnded = 0 self.totalLoadTime = 0 # the time that the operator started/ended setting-up the machine self.timeSetupStarted = 0 self.timeSetupEnded = 0 self.totalSetupTime = 0 # Current entity load/setup/loadOperatorwait/operatorWait related times self.operatorWaitTimeCurrentEntity = 0 # holds the time that the machine was waiting for the operator self.loadOperatorWaitTimeCurrentEntity = 0 # holds the time that the machine waits for operator to load the it self.loadTimeCurrentEntity = 0 # holds the time to load the current entity self.setupTimeCurrentEntity = 0 # holds the time to setup the machine before processing the current entity
def initialize(self): MachineJobShop.initialize(self) self.type="MachineManagedJob" #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested id = self.id+'_OP' name=self.objName+'_operatorPool' self.operatorPool=OperatorPool(id, name, operatorsList=[]) self.operatorPool.initialize() self.operatorPool.operators=[] #create a Broker self.broker = Broker(self) activate(self.broker,self.broker.run()) #create a Router from Globals import G if len(G.RoutersList)==0: self.router=Router() activate(self.router,self.router.run()) G.RoutersList.append(self.router) # otherwise set the already existing router as the machines Router else: self.router=G.RoutersList[0] # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested self.entityToGet=None
class OperatedMachine(Machine): # ======================================================================= # initialise the id the capacity, of the resource and the distribution # ======================================================================= def __init__( self, id, name, capacity=1, processingTime=None, failureDistribution="No", MTTF=0, MTTR=0, availability=0, repairman="None", operatorPool="None", operationType="None", setupTime=None, loadTime=None, ): Machine.__init__( self, id, name, capacity=capacity, processingTime=processingTime, failureDistribution=failureDistribution, MTTF=MTTF, MTTR=MTTR, availability=availability, repairman=repairman, operatorPool=operatorPool, operationType=operationType, setupTime=setupTime, loadTime=loadTime, ) # type of the machine self.type = "OperatedMachine" # sets the operator resource of the Machine # check if the operatorPool is a List or a OperatorPool type Object # if it is a list then initiate a OperatorPool type object containing # the list of operators provided """ change! if the list is empty create operator pool with empty list """ if type(operatorPool) is list: # and len(operatorPool)>0: id = id + "_OP" name = self.objName + "_operatorPool" self.operatorPool = OperatorPool(id, name, operatorsList=operatorPool) else: self.operatorPool = operatorPool # update the operatorPool coreObjects list if self.operatorPool != "None": self.operatorPool.coreObjectIds.append(self.id) self.operatorPool.coreObjects.append(self) # holds the Operator currently processing the Machine self.currentOperator = None # define if load/setup/removal/processing are performed by the operator self.operationType = operationType # boolean to check weather the machine is being operated self.toBeOperated = False # examine if there are multiple operation types performed by the operator # there can be Setup/Processing operationType # or the combination of both (MT-Load-Setup-Processing) self.multOperationTypeList = [] if self.operationType.startswith("MT"): OTlist = operationType.split("-") self.operationType = OTlist.pop(0) self.multOperationTypeList = OTlist else: self.multOperationTypeList.append(self.operationType) # lists to hold statistics of multiple runs self.WaitingForOperator = [] self.WaitingForLoadOperator = [] self.Loading = [] self.SettingUp = [] # ======================================================================= # initialize the machine # ======================================================================= def initialize(self): Machine.initialize(self) # initiate the Broker responsible to control the request/release # initialize the operator pool if any if self.operatorPool != "None": self.operatorPool.initialize() self.broker = Broker(self) activate(self.broker, self.broker.run()) for operator in self.operatorPool.operators: operator.coreObjectIds.append(self.id) operator.coreObjects.append(self) # the time that the machine started/ended its wait for the operator self.timeWaitForOperatorStarted = 0 self.timeWaitForOperatorEnded = 0 self.totalTimeWaitingForOperator = 0 # the time that the machine started/ended its wait for the operator self.timeWaitForLoadOperatorStarted = 0 self.timeWaitForLoadOperatorEnded = 0 self.totalTimeWaitingForLoadOperator = 0 # the time that the operator started/ended loading the machine self.timeLoadStarted = 0 self.timeLoadEnded = 0 self.totalLoadTime = 0 # the time that the operator started/ended setting-up the machine self.timeSetupStarted = 0 self.timeSetupEnded = 0 self.totalSetupTime = 0 # Current entity load/setup/loadOperatorwait/operatorWait related times self.operatorWaitTimeCurrentEntity = 0 # holds the time that the machine was waiting for the operator self.loadOperatorWaitTimeCurrentEntity = 0 # holds the time that the machine waits for operator to load the it self.loadTimeCurrentEntity = 0 # holds the time to load the current entity self.setupTimeCurrentEntity = 0 # holds the time to setup the machine before processing the current entity # ======================================================================= # the main process of the machine # ======================================================================= def run(self): # execute all through simulation time while 1: # wait until the machine can accept an entity and one predecessor requests it # canAcceptAndIsRequested is invoked to check when the machine requested to receive an entity yield waituntil, self, self.canAcceptAndIsRequested # here or in the get entity (apart from the loatTimeCurrentEntity) # in case they are placed inside the getEntity then the initialize of # the corresponding variables should be moved to the initialize() of the CoreObject self.operatorWaitTimeCurrentEntity = 0 self.loadOperatorWaitTimeCurrentEntity = 0 self.loadTimeCurrentEntity = 0 self.setupTimeCurrentEntity = 0 # ======= request a resource if (self.operatorPool != "None") and any(type == "Load" for type in self.multOperationTypeList): # when it's ready to accept (canAcceptAndIsRequested) then inform the broker # machines waits to be operated (waits for the operator) self.requestOperator() self.timeWaitForLoadOperatorStarted = self.env.now # wait until the Broker has waited times equal to loadTime (if any) yield waituntil, self, self.broker.brokerIsSet self.timeWaitForLoadOperatorEnded = self.env.now self.loadOperatorWaitTimeCurrentEntity += ( self.timeWaitForLoadOperatorEnded - self.timeWaitForLoadOperatorStarted ) self.totalTimeWaitingForLoadOperator += self.loadOperatorWaitTimeCurrentEntity # ======= Load the machine if the Load is defined as one of the Operators' operation types if any(type == "Load" for type in self.multOperationTypeList) and self.isOperated(): self.timeLoadStarted = self.env.now yield hold, self, self.calculateLoadTime() # if self.interrupted(): There is the issue of failure during the Loading self.timeLoadEnded = self.env.now self.loadTimeCurrentEntity = self.timeLoadEnded - self.timeLoadStarted self.totalLoadTime += self.loadTimeCurrentEntity # ======= release a resource if the only operation type is Load if ( (self.operatorPool != "None") and any(type == "Load" for type in self.multOperationTypeList) and not any(type == "Processing" or type == "Setup" for type in self.multOperationTypeList) and self.isOperated() ): # after getting the entity release the operator # machine has to release the operator self.releaseOperator() # wait until the Broker has finished processing yield waituntil, self, self.broker.brokerIsSet # get the entity # if there was loading time then we must solve the problem of getting an entity # from an unidentified giver or not getting an entity at all as the giver # may fall in failure mode self.currentEntity = self.getEntity() # set the currentEntity as the Entity just received and initialize the timer timeLastEntityEntered self.nameLastEntityEntered = ( self.currentEntity.name ) # this holds the name of the last entity that got into Machine self.timeLastEntityEntered = self.env.now # this holds the last time that an entity got into Machine # variables dedicated to hold the processing times, the time when the Entity entered, # and the processing time left timeEntered = self.env.now # timeEntered dummy Timer that holds the time the last Entity Entered # ======= request a resource if it is not already assigned an Operator if ( (self.operatorPool != "None") and any(type == "Processing" or type == "Setup" for type in self.multOperationTypeList) and not self.isOperated() ): # when it's ready to accept (canAcceptAndIsRequested) then inform the broker # machines waits to be operated (waits for the operator) self.requestOperator() self.timeWaitForOperatorStarted = self.env.now # wait until the Broker has waited times equal to loadTime (if any) yield waituntil, self, self.broker.brokerIsSet self.timeWaitForOperatorEnded = self.env.now self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted self.totalProcessingTimeInCurrentEntity = ( self.calculateProcessingTime() ) # get the processing time, tinMStarts holds the processing time of the machine tinM = self.totalProcessingTimeInCurrentEntity # timer to hold the processing time left # ======= setup the machine if the Setup is defined as one of the Operators' operation types # in plantSim the setup is performed when the machine has to process a new type of Entity and only once if any(type == "Setup" for type in self.multOperationTypeList) and self.isOperated(): self.timeSetupStarted = self.env.now yield hold, self, self.calculateSetupTime() # if self.interrupted(): There is the issue of failure during the setup self.timeSetupEnded = self.env.now self.setupTimeCurrentEntity = self.timeSetupEnded - self.timeSetupStarted self.totalSetupTime += self.setupTimeCurrentEntity # ======= release a resource if the only operation type is Setup if ( (self.operatorPool != "None") and self.isOperated() and any(type == "Setup" or type == "Load" for type in self.multOperationTypeList) and not any(type == "Processing" for type in self.multOperationTypeList) ): # after getting the entity release the operator # machine has to release the operator self.releaseOperator() # print self.objName, 'operator released', self.env.now # wait until the Broker has finished processing yield waituntil, self, self.broker.brokerIsSet # variables used to flag any interruptions and the end of the processing interruption = False processingEndedFlag = True # timers to follow up the failure time of the machine while on current Entity failureTime = 0 # dummy variable keeping track of the failure time # might be feasible to avoid it self.downTimeInCurrentEntity = 0 # holds the total time that the # object was down while holding current entity # this loop is repeated until the processing time is expired with no failure # check when the processingEndedFlag switched to false while processingEndedFlag: # tBefore : dummy variable to keep track of the time that the processing starts after # every interruption tBefore = self.env.now # wait for the processing time left tinM, if no interruption occurs then change the # processingEndedFlag and exit loop, # else (if interrupted()) set interruption flag to true (only if tinM==0), # and recalculate the processing time left tinM, # passivate while waiting for repair. yield hold, self, tinM # getting processed for remaining processing time tinM if self.interrupted(): # if a failure occurs while processing the machine is interrupted. # output to trace that the Machine (self.objName) got interrupted self.outputTrace(self.getActiveObjectQueue()[0].name, "Interrupted at " + self.objName) # recalculate the processing time left tinM tinM = tinM - (self.env.now - tBefore) if ( tinM == 0 ): # sometimes the failure may happen exactly at the time that the processing would finish # this may produce disagreement with the simul8 because in both SimPy and Simul8 # it seems to be random which happens 1st # this should not appear often to stochastic models though where times are random interruption = True # passivate the Machine for as long as there is no repair # start counting the down time at breatTime dummy variable breakTime = self.env.now # dummy variable that the interruption happened # =============== release the operator if there is failure if ( (self.operatorPool != "None") and self.isOperated() and any(type == "Processing" for type in self.multOperationTypeList) ): self.releaseOperator() # print self.objName, 'operator released due to failure', self.env.now yield waituntil, self, self.broker.brokerIsSet # if there is a failure in the machine it is passivated yield passivate, self # use the timers to count the time that Machine is down and related self.downTimeProcessingCurrentEntity += ( self.env.now - breakTime ) # count the time that Machine is down while processing this Entity self.downTimeInCurrentEntity += ( self.env.now - breakTime ) # count the time that Machine is down while on currentEntity self.timeLastFailureEnded = self.env.now # set the timeLastFailureEnded failureTime += self.env.now - breakTime # dummy variable keeping track of the failure time # output to trace that the Machine self.objName was passivated for the current failure time self.outputTrace( self.getActiveObjectQueue()[0].name, "passivated in " + self.objName + " for " + str(self.env.now - breakTime), ) # =============== request a resource after the repair if ( (self.operatorPool != "None") and any(type == "Processing" for type in self.multOperationTypeList) and not interruption ): self.timeWaitForOperatorStarted = self.env.now self.requestOperator() yield waituntil, self, self.broker.brokerIsSet self.timeWaitForOperatorEnded = self.env.now self.operatorWaitTimeCurrentEntity += ( self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted ) # if no interruption occurred the processing in M1 is ended else: processingEndedFlag = False # output to trace that the processing in the Machine self.objName ended self.outputTrace(self.getActiveObjectQueue()[0].name, "ended processing in " + self.objName) # =============== release resource after the end of processing if ( (self.operatorPool != "None") and any(type == "Processing" for type in self.multOperationTypeList) and not interruption ): self.releaseOperator() yield waituntil, self, self.broker.brokerIsSet # set the variable that flags an Entity is ready to be disposed self.waitToDispose = True # update the total working time self.totalWorkingTime += ( self.totalProcessingTimeInCurrentEntity ) # the total processing time for this entity # is what the distribution initially gave # update the variables keeping track of Entity related attributes of the machine self.timeLastEntityEnded = ( self.env.now ) # this holds the time that the last entity ended processing in Machine self.nameLastEntityEnded = ( self.currentEntity.name ) # this holds the name of the last entity that ended processing in Machine self.completedJobs += 1 # Machine completed one more Job # re-initialize the downTimeProcessingCurrentEntity. # a new machine is about to enter self.downTimeProcessingCurrentEntity = 0 # dummy variable requests the successor object now reqTime = self.env.now # entity has ended processing in Machine and requests for the next object # initialize the timer downTimeInTryingToReleaseCurrentEntity, we have to count how much time # the Entity will wait for the next successor to be able to accept (canAccept) self.downTimeInTryingToReleaseCurrentEntity = 0 while 1: # wait until the next Object is available or machine has failure yield waituntil, self, self.ifCanDisposeOrHaveFailure # if Next object available break if self.Up: break # if M1 had failure, we want to wait until it is fixed and also count the failure time. else: failTime = self.env.now # dummy variable holding the time failure happened # passivate until machine is up yield waituntil, self, self.checkIfMachineIsUp failureTime += ( self.env.now - failTime ) # count the failure while on current entity time with failureTime variable # calculate the time the Machine was down while trying to dispose the current Entity, # and the total down time while on current Entity self.downTimeInTryingToReleaseCurrentEntity += self.env.now - failTime self.downTimeInCurrentEntity += ( self.env.now - failTime ) # already updated from failures during processing # update the timeLastFailureEnded self.timeLastFailureEnded = self.env.now # dummy variable holding the total time the Entity spent in the Machine # count the time the Machine was blocked subtracting the failureTime # and the processing time from the totalTime spent in the Machine self.totalTimeInCurrentEntity = self.env.now - timeEntered # ======================================================================= # checks if the Machine can accept an entity # it checks also who called it and returns TRUE only to the predecessor # that will give the entity. # ======================================================================= def canAccept(self, callerObject=None): # get active and giver objects activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() giverObject = self.getGiverObject() # if we have only one predecessor just check if there is a place and the machine is up # this is done to achieve better (cpu) processing time # then we can also use it as a filter for a yield method if len(activeObject.previous) == 1 or callerObject == None: if activeObject.operatorPool != "None" and any( type == "Load" for type in activeObject.multOperationTypeList ): return ( activeObject.operatorPool.checkIfResourceIsAvailable() and activeObject.Up and len(activeObjectQueue) < activeObject.capacity ) else: return activeObject.Up and len(activeObjectQueue) < activeObject.capacity thecaller = callerObject # return True ONLY if the length of the activeOjbectQue is smaller than # the object capacity, and the callerObject is not None but the giverObject if activeObject.operatorPool != "None" and any(type == "Load" for type in activeObject.multOperationTypeList): return ( activeObject.operatorPool.checkIfResourceIsAvailable() and activeObject.Up and len(activeObjectQueue) < activeObject.capacity ) else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators return activeObject.Up and len(activeObjectQueue) < activeObject.capacity # while if the set up is performed before the (automatic) loading of the machine then the availability of the # operator is requested # return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity # ======================================================================= # checks if the Machine can accept an entity and there is an entity in # some possible giver waiting for it # also updates the giver to the one that is to be taken # ======================================================================= def canAcceptAndIsRequested(self): # get active and giver objects activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() giverObject = self.getGiverObject() # if we have only one predecessor just check if there is a place, # the machine is up and the predecessor has an entity to dispose # if the machine has to compete for an Operator that loads the entities onto it # check if the predecessor if blocked by an other Machine # if not then the machine has to block the predecessor giverObject to avoid conflicts # with other competing machines if len(activeObject.previous) == 1: if activeObject.operatorPool != "None" and any( type == "Load" for type in activeObject.multOperationTypeList ): if ( activeObject.operatorPool.checkIfResourceIsAvailable() and activeObject.Up and len(activeObjectQueue) < activeObject.capacity and giverObject.haveToDispose(activeObject) and not giverObject.exitIsAssigned() ): activeObject.giver.assignExit() return True else: return False else: # the operator performs no load and the entity is received by the machine while there is # no need for operators presence. The operator needs to be present only where the load Type # operation is assigned return ( activeObject.Up and len(activeObjectQueue) < activeObject.capacity and giverObject.haveToDispose(activeObject) ) # if the set-up performance needs be first performed before the transfer of the entity to # the machine then the presence of an operator to setup the machine before the getEntity() # is requested # return (activeObject.operatorPool=='None'\ # or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ # and giverObject.haveToDispose() # dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject) isRequested = False # is requested is dummyVariable checking if it is requested to accept an item maxTimeWaiting = 0 # dummy variable counting the time a predecessor is blocked # loop through the possible givers to see which have to dispose and which is the one blocked for longer for object in activeObject.previous: if object.haveToDispose(activeObject): # and not object.exitIsAssigned()): isRequested = True # if the possible giver has entities to dispose of if ( object.downTimeInTryingToReleaseCurrentEntity > 0 ): # and the possible giver has been down while trying to give away the Entity timeWaiting = ( self.env.now - object.timeLastFailureEnded ) # the timeWaiting dummy variable counts the time end of the last failure of the giver object else: timeWaiting = ( self.env.now - object.timeLastEntityEnded ) # in any other case, it holds the time since the end of the Entity processing # if more than one possible givers have to dispose take the part from the one that is blocked longer if timeWaiting >= maxTimeWaiting: activeObject.giver = object # set the giver maxTimeWaiting = timeWaiting if activeObject.operatorPool != "None" and any(type == "Load" for type in activeObject.multOperationTypeList): if ( activeObject.operatorPool.checkIfResourceIsAvailable() and activeObject.Up and len(activeObjectQueue) < activeObject.capacity and isRequested and not activeObject.giver.exitIsAssigned() ): activeObject.giver.assignExit() return True else: return False else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators return activeObject.Up and len(activeObjectQueue) < activeObject.capacity and isRequested # while if the set up is performed before the (automatic) loading of the machine then the availability of the # operator is requested # return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested # ======================================================================= # calculates the setup time # ======================================================================= def calculateSetupTime(self): return self.stpRng.generateNumber() # ======================================================================= # calculates the Load time # ======================================================================= def calculateLoadTime(self): return self.loadRng.generateNumber() # ======================================================================= # prepare the machine to be operated # ======================================================================= def requestOperator(self): self.broker.invokeBroker() self.toBeOperated = True # ======================================================================= # prepare the machine to be released # ======================================================================= def releaseOperator(self): self.broker.invokeBroker() self.toBeOperated = False # ======================================================================= # check if the machine is currently operated by an operator # ======================================================================= def isOperated(self): return self.toBeOperated # ======================================================================= # check if the machine is already set-up # ======================================================================= def isSetUp(self): return self.setUp # ======================================================================= # request that the machine is set-up by an operator # ======================================================================= def requestSetup(self): self.setUp = False # ======================================================================= # actions to be taken after the simulation ends # ======================================================================= def postProcessing(self, MaxSimtime=None): if MaxSimtime == None: from Globals import G MaxSimtime = G.maxSimTime activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() alreadyAdded = False # a flag that shows if the blockage time has already been added # checks all the successors. If no one can accept an Entity then the machine might be blocked mightBeBlocked = True for nextObject in self.next: if nextObject.canAccept(): mightBeBlocked = False # if there is an entity that finished processing in a Machine but did not get to reach # the following Object till the end of simulation, # we have to add this blockage to the percentage of blockage in Machine # we should exclude the failure time in current entity though! # if (len(self.Res.activeQ)>0) and (len(self.next[0].Res.activeQ)>0) and ((self.nameLastEntityEntered == self.nameLastEntityEnded)): if ( (len(activeObjectQueue) > 0) and (mightBeBlocked) and ((activeObject.nameLastEntityEntered == activeObject.nameLastEntityEnded)) ): # be careful here, might have to reconsider activeObject.totalBlockageTime += self.env.now - ( activeObject.timeLastEntityEnded + activeObject.downTimeInTryingToReleaseCurrentEntity ) if activeObject.Up == False: activeObject.totalBlockageTime -= self.env.now - activeObject.timeLastFailure alreadyAdded = True # if Machine is currently processing an entity we should count this working time if ( (len(activeObject.getActiveObjectQueue()) > 0) and (not (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered)) and (not (activeObject.operationType == "Processing" and (activeObject.currentOperator == None))) ): # if Machine is down we should add this last failure time to the time that it has been down in current entity if self.Up == False: # if(len(activeObjectQueue)>0) and (self.Up==False): activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure activeObject.totalWorkingTime += ( self.env.now - activeObject.timeLastEntityEntered - activeObject.downTimeProcessingCurrentEntity - activeObject.operatorWaitTimeCurrentEntity - activeObject.setupTimeCurrentEntity ) activeObject.totalTimeWaitingForOperator += activeObject.operatorWaitTimeCurrentEntity elif ( (len(activeObject.getActiveObjectQueue()) > 0) and (not (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered)) and (activeObject.currentOperator == None) ): # needs further research as the time of failure while waiting for operator is not counted yet if self.Up == False: activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure activeObject.totalTimeWaitingForOperator += ( self.env.now - activeObject.timeWaitForOperatorStarted - activeObject.downTimeProcessingCurrentEntity ) # if Machine is down we have to add this failure time to its total failure time # we also need to add the last blocking time to total blockage time if activeObject.Up == False: activeObject.totalFailureTime += self.env.now - activeObject.timeLastFailure # we add the value only if it hasn't already been added # if((len(self.next[0].Res.activeQ)>0) and (self.nameLastEntityEnded==self.nameLastEntityEntered) and (not alreadyAdded)): if ( (mightBeBlocked) and (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered) and (not alreadyAdded) ): activeObject.totalBlockageTime += ( (self.env.now - activeObject.timeLastEntityEnded) - (self.env.now - activeObject.timeLastFailure) - activeObject.downTimeInTryingToReleaseCurrentEntity ) # Machine was idle when it was not in any other state activeObject.totalWaitingTime = ( MaxSimtime - activeObject.totalWorkingTime - activeObject.totalBlockageTime - activeObject.totalFailureTime ) if ( activeObject.totalBlockageTime < 0 and activeObject.totalBlockageTime > -0.00001 ): # to avoid some effects of getting negative cause of rounding precision self.totalBlockageTime = 0 if ( activeObject.totalWaitingTime < 0 and activeObject.totalWaitingTime > -0.00001 ): # to avoid some effects of getting negative cause of rounding precision self.totalWaitingTime = 0 activeObject.Failure.append(100 * self.totalFailureTime / MaxSimtime) activeObject.Blockage.append(100 * self.totalBlockageTime / MaxSimtime) activeObject.Waiting.append(100 * self.totalWaitingTime / MaxSimtime) activeObject.Working.append(100 * self.totalWorkingTime / MaxSimtime) activeObject.WaitingForOperator.append(100 * self.totalTimeWaitingForOperator / MaxSimtime) activeObject.WaitingForLoadOperator.append(100 * self.totalTimeWaitingForLoadOperator / MaxSimtime) activeObject.Loading.append(100 * self.totalLoadTime / MaxSimtime) activeObject.SettingUp.append(100 * self.totalSetupTime / MaxSimtime)
def createBroker(self): #create a Broker self.broker = Broker(self)
class MachineManagedJob(MachineJobShop): # ======================================================================= # initialise the MachineManagedJob # ======================================================================= def initialize(self): MachineJobShop.initialize(self) self.type="MachineManagedJob" # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested self.entityToGet=None #=========================================================================== # create an operatorPool if needed #=========================================================================== def createOperatorPool(self,operatorPool): #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested id = self.id+'_OP' name=self.objName+'_operatorPool' self.operatorPool=OperatorPool(id, name, operatorsList=[]) from Globals import G G.OperatorPoolsList.append(self.operatorPool) #=========================================================================== # create broker if needed #=========================================================================== def createBroker(self): #create a Broker self.broker = Broker(self) #=========================================================================== # create router if needed #=========================================================================== def createRouter(self): #create a Router from Globals import G if not G.Router: self.router=RouterManaged() G.Router=self.router # otherwise set the already existing router as the machines Router else: self.router=G.Router #=========================================================================== # initialize broker if needed #=========================================================================== def initializeOperatorPool(self): self.operatorPool.initialize() self.operatorPool.operators=[] #=========================================================================== # initialize broker if needed #=========================================================================== def initializeBroker(self): self.broker.initialize() self.env.process(self.broker.run()) #=========================================================================== # initialize router if needed #=========================================================================== def initializeRouter(self): if not self.router.isInitialized: self.router.initialize() if not self.router.isActivated: self.env.process(self.router.run()) self.router.isActivated=True # ======================================================================= # checks if the Queue can accept an entity # TODO: cannot check here if the station in the route of the entity that will be received (if any) # as the giver (QueueManagedJob) will be sorted from giver.haveToDispose in self.canAcceptAndIsRequested method # ======================================================================= def canAccept(self, callerObject=None): activeObject=self.getActiveObject() activeObjectQueue=activeObject.getActiveObjectQueue() #return according to the state of the Queue return len(activeObjectQueue)<activeObject.capacity\ and activeObject.checkIfMachineIsUp()\ and not activeObject.entryIsAssignedTo() # ======================================================================= # checks if the Queue can accept an specific Entity # it checks also the next station of the Entity # and returns true only if the active object is the next station # ======================================================================= def canAcceptEntity(self, callerEntity=None): activeObject=self.getActiveObject() activeObjectQueue=activeObject.getActiveObjectQueue() thecallerentity=callerEntity if (thecallerentity!=None): # if the machine's Id is in the list of the entity's next stations if activeObject.id in thecallerentity.remainingRoute[0].get('stationIdsList',[]): #return according to the state of the Queue return len(activeObjectQueue)<activeObject.capacity\ and activeObject.checkIfMachineIsUp() return False # ======================================================================= # checks if the Machine can accept an entity and there is an entity in # some possible giver waiting for it # also updates the giver to the one that is to be taken # ======================================================================= def canAcceptAndIsRequested(self,callerObject=None): # get active and giver objects activeObject=self.getActiveObject() activeObjectQueue=self.getActiveObjectQueue() # giverObject=activeObject.getGiverObject() giverObject=callerObject assert giverObject, 'there must be a caller for canAcceptAndIsRequested' giverObjectQueue=giverObject.getActiveObjectQueue() # if the multOperationTypeList of the machine contains Load or Setup if (activeObject.operatorPool!='None' and (any(type=='Load' for type in activeObject.multOperationTypeList)\ or any(type=='Setup' for type in activeObject.multOperationTypeList))): if giverObject.haveToDispose(activeObject): if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity\ and activeObject.checkOperator(giverObject): if not giverObject.exitIsAssignedTo(): giverObject.assignExitTo(activeObject) elif giverObject.exitIsAssignedTo()!=activeObject: return False # update entityToGet activeObject.entityToGet=giverObjectQueue[0] #make the operators List so that it holds only the manager of the current order activeObject.operatorPool.operators=[giverObjectQueue[0].manager] # read the load time of the machine activeObject.readLoadTime(giverObject) return True else: return False # if the multOperationTypeList contains only Processing elif (activeObject.operatorPool!='None' and any(type=='Processing' for type in activeObject.multOperationTypeList)): if giverObject.haveToDispose(activeObject): # the operator must not be available for the object to receive the entity # the exit of the giver should not be assigned # the manager must not be available for the entity to be delivered # the operator to the machine while he is not needed for receiving the entity if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity: # the entityToGet should be updated activeObject.entityToGet=giverObjectQueue[0] #make the operators List so that it holds only the manager of the current order activeObject.operatorPool.operators=[giverObjectQueue[0].manager] # read the load time of the machine activeObject.readLoadTime(giverObject) return True else: return False else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity and giverObject.haveToDispose(activeObject): # update entityToGet activeObject.entityToGet=giverObject.getActiveObjectQueue()[0] activeObject.readLoadTime(giverObject) return activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity and giverObject.haveToDispose(activeObject) # ======================================================================= # to be called by canAcceptAndIsRequested and check for the operator # ======================================================================= def checkOperator(self,callerObject=None): #, candidateEntity=None): assert callerObject!=None, 'checkOperator must have a caller for MachineManagedJob' activeObject=self.getActiveObject() # giverObject=activeObject.getGiverObject() giverObject=callerObject giverObjectQueue=giverObject.getActiveObjectQueue() if giverObjectQueue[0].manager: manager=giverObjectQueue[0].manager # TODO: consider using a caller in this case return manager.checkIfResourceIsAvailable(activeObject) else: return True # if candidateEntity: # if candidateEntity.manager: # manager=candidateEntity.manager # return manager.checkIfResourceIsAvailable() # else: # return True # return False # ======================================================================= # identifies the Entity to be obtained so that # getEntity gives it to removeEntity as argument # ======================================================================= def identifyEntityToGet(self): # ToDecide # maybe we should work this way in all CoreObjects??? return self.entityToGet
class OperatedMachine(Machine): # ======================================================================= # initialise the id the capacity, of the resource and the distribution # ======================================================================= def __init__(self, id, name, capacity=1, processingTime=None, failureDistribution='No', MTTF=0, MTTR=0, availability=0, repairman='None',\ operatorPool='None',operationType='None', setupTime=None, loadTime=None): Machine.__init__( self, id, name, capacity=capacity, processingTime=processingTime, failureDistribution=failureDistribution, MTTF=MTTF, MTTR=MTTR, availability=availability, repairman=repairman, operatorPool=operatorPool, operationType=operationType, setupTime=setupTime, loadTime=loadTime, ) # type of the machine self.type = "OperatedMachine" # sets the operator resource of the Machine # check if the operatorPool is a List or a OperatorPool type Object # if it is a list then initiate a OperatorPool type object containing # the list of operators provided ''' change! if the list is empty create operator pool with empty list ''' if (type(operatorPool) is list): #and len(operatorPool)>0: id = id + '_OP' name = self.objName + '_operatorPool' self.operatorPool = OperatorPool(id, name, operatorsList=operatorPool) else: self.operatorPool = operatorPool # update the operatorPool coreObjects list if self.operatorPool != 'None': self.operatorPool.coreObjectIds.append(self.id) self.operatorPool.coreObjects.append(self) # holds the Operator currently processing the Machine self.currentOperator = None # define if load/setup/removal/processing are performed by the operator self.operationType = operationType # boolean to check weather the machine is being operated self.toBeOperated = False # examine if there are multiple operation types performed by the operator # there can be Setup/Processing operationType # or the combination of both (MT-Load-Setup-Processing) self.multOperationTypeList = [] if self.operationType.startswith("MT"): OTlist = operationType.split('-') self.operationType = OTlist.pop(0) self.multOperationTypeList = OTlist else: self.multOperationTypeList.append(self.operationType) # lists to hold statistics of multiple runs self.WaitingForOperator = [] self.WaitingForLoadOperator = [] self.Loading = [] self.SettingUp = [] # ======================================================================= # initialize the machine # ======================================================================= def initialize(self): Machine.initialize(self) # initiate the Broker responsible to control the request/release # initialize the operator pool if any if (self.operatorPool != "None"): self.operatorPool.initialize() self.broker = Broker(self) activate(self.broker, self.broker.run()) for operator in self.operatorPool.operators: operator.coreObjectIds.append(self.id) operator.coreObjects.append(self) # the time that the machine started/ended its wait for the operator self.timeWaitForOperatorStarted = 0 self.timeWaitForOperatorEnded = 0 self.totalTimeWaitingForOperator = 0 # the time that the machine started/ended its wait for the operator self.timeWaitForLoadOperatorStarted = 0 self.timeWaitForLoadOperatorEnded = 0 self.totalTimeWaitingForLoadOperator = 0 # the time that the operator started/ended loading the machine self.timeLoadStarted = 0 self.timeLoadEnded = 0 self.totalLoadTime = 0 # the time that the operator started/ended setting-up the machine self.timeSetupStarted = 0 self.timeSetupEnded = 0 self.totalSetupTime = 0 # Current entity load/setup/loadOperatorwait/operatorWait related times self.operatorWaitTimeCurrentEntity = 0 # holds the time that the machine was waiting for the operator self.loadOperatorWaitTimeCurrentEntity = 0 # holds the time that the machine waits for operator to load the it self.loadTimeCurrentEntity = 0 # holds the time to load the current entity self.setupTimeCurrentEntity = 0 # holds the time to setup the machine before processing the current entity # ======================================================================= # the main process of the machine # ======================================================================= def run(self): # execute all through simulation time while 1: # wait until the machine can accept an entity and one predecessor requests it # canAcceptAndIsRequested is invoked to check when the machine requested to receive an entity yield waituntil, self, self.canAcceptAndIsRequested # here or in the get entity (apart from the loatTimeCurrentEntity) # in case they are placed inside the getEntity then the initialize of # the corresponding variables should be moved to the initialize() of the CoreObject self.operatorWaitTimeCurrentEntity = 0 self.loadOperatorWaitTimeCurrentEntity = 0 self.loadTimeCurrentEntity = 0 self.setupTimeCurrentEntity = 0 # ======= request a resource if (self.operatorPool != "None") and any( type == 'Load' for type in self.multOperationTypeList): # when it's ready to accept (canAcceptAndIsRequested) then inform the broker # machines waits to be operated (waits for the operator) self.requestOperator() self.timeWaitForLoadOperatorStarted = self.env.now # wait until the Broker has waited times equal to loadTime (if any) yield waituntil, self, self.broker.brokerIsSet self.timeWaitForLoadOperatorEnded = self.env.now self.loadOperatorWaitTimeCurrentEntity += self.timeWaitForLoadOperatorEnded - self.timeWaitForLoadOperatorStarted self.totalTimeWaitingForLoadOperator += self.loadOperatorWaitTimeCurrentEntity # ======= Load the machine if the Load is defined as one of the Operators' operation types if any(type == "Load" for type in self.multOperationTypeList) and self.isOperated(): self.timeLoadStarted = self.env.now yield hold, self, self.calculateLoadTime() # if self.interrupted(): There is the issue of failure during the Loading self.timeLoadEnded = self.env.now self.loadTimeCurrentEntity = self.timeLoadEnded - self.timeLoadStarted self.totalLoadTime += self.loadTimeCurrentEntity # ======= release a resource if the only operation type is Load if (self.operatorPool!="None")\ and any(type=="Load" for type in self.multOperationTypeList)\ and not any(type=="Processing" or type=="Setup" for type in self.multOperationTypeList)\ and self.isOperated(): # after getting the entity release the operator # machine has to release the operator self.releaseOperator() # wait until the Broker has finished processing yield waituntil, self, self.broker.brokerIsSet # get the entity # if there was loading time then we must solve the problem of getting an entity # from an unidentified giver or not getting an entity at all as the giver # may fall in failure mode self.currentEntity = self.getEntity() # set the currentEntity as the Entity just received and initialize the timer timeLastEntityEntered self.nameLastEntityEntered = self.currentEntity.name # this holds the name of the last entity that got into Machine self.timeLastEntityEntered = self.env.now #this holds the last time that an entity got into Machine # variables dedicated to hold the processing times, the time when the Entity entered, # and the processing time left timeEntered = self.env.now # timeEntered dummy Timer that holds the time the last Entity Entered # ======= request a resource if it is not already assigned an Operator if(self.operatorPool!="None")\ and any(type=="Processing" or type=="Setup" for type in self.multOperationTypeList)\ and not self.isOperated(): # when it's ready to accept (canAcceptAndIsRequested) then inform the broker # machines waits to be operated (waits for the operator) self.requestOperator() self.timeWaitForOperatorStarted = self.env.now # wait until the Broker has waited times equal to loadTime (if any) yield waituntil, self, self.broker.brokerIsSet self.timeWaitForOperatorEnded = self.env.now self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted self.totalProcessingTimeInCurrentEntity = self.calculateProcessingTime( ) # get the processing time, tinMStarts holds the processing time of the machine tinM = self.totalProcessingTimeInCurrentEntity # timer to hold the processing time left # ======= setup the machine if the Setup is defined as one of the Operators' operation types # in plantSim the setup is performed when the machine has to process a new type of Entity and only once if any(type == "Setup" for type in self.multOperationTypeList) and self.isOperated(): self.timeSetupStarted = self.env.now yield hold, self, self.calculateSetupTime() # if self.interrupted(): There is the issue of failure during the setup self.timeSetupEnded = self.env.now self.setupTimeCurrentEntity = self.timeSetupEnded - self.timeSetupStarted self.totalSetupTime += self.setupTimeCurrentEntity # ======= release a resource if the only operation type is Setup if (self.operatorPool!="None")\ and self.isOperated()\ and any(type=="Setup" or type=="Load" for type in self.multOperationTypeList)\ and not any(type=="Processing" for type in self.multOperationTypeList): # after getting the entity release the operator # machine has to release the operator self.releaseOperator() # print self.objName, 'operator released', self.env.now # wait until the Broker has finished processing yield waituntil, self, self.broker.brokerIsSet # variables used to flag any interruptions and the end of the processing interruption = False processingEndedFlag = True # timers to follow up the failure time of the machine while on current Entity failureTime = 0 # dummy variable keeping track of the failure time # might be feasible to avoid it self.downTimeInCurrentEntity = 0 #holds the total time that the #object was down while holding current entity # this loop is repeated until the processing time is expired with no failure # check when the processingEndedFlag switched to false while processingEndedFlag: # tBefore : dummy variable to keep track of the time that the processing starts after # every interruption tBefore = self.env.now # wait for the processing time left tinM, if no interruption occurs then change the # processingEndedFlag and exit loop, # else (if interrupted()) set interruption flag to true (only if tinM==0), # and recalculate the processing time left tinM, # passivate while waiting for repair. yield hold, self, tinM # getting processed for remaining processing time tinM if self.interrupted( ): # if a failure occurs while processing the machine is interrupted. # output to trace that the Machine (self.objName) got interrupted self.outputTrace(self.getActiveObjectQueue()[0].name, "Interrupted at " + self.objName) # recalculate the processing time left tinM tinM = tinM - (self.env.now - tBefore) if ( tinM == 0 ): # sometimes the failure may happen exactly at the time that the processing would finish # this may produce disagreement with the simul8 because in both SimPy and Simul8 # it seems to be random which happens 1st # this should not appear often to stochastic models though where times are random interruption = True # passivate the Machine for as long as there is no repair # start counting the down time at breatTime dummy variable breakTime = self.env.now # dummy variable that the interruption happened # =============== release the operator if there is failure if (self.operatorPool!="None")\ and self.isOperated()\ and any(type=="Processing" for type in self.multOperationTypeList): self.releaseOperator() # print self.objName, 'operator released due to failure', self.env.now yield waituntil, self, self.broker.brokerIsSet # if there is a failure in the machine it is passivated yield passivate, self # use the timers to count the time that Machine is down and related self.downTimeProcessingCurrentEntity += self.env.now - breakTime # count the time that Machine is down while processing this Entity self.downTimeInCurrentEntity += self.env.now - breakTime # count the time that Machine is down while on currentEntity self.timeLastFailureEnded = self.env.now # set the timeLastFailureEnded failureTime += self.env.now - breakTime # dummy variable keeping track of the failure time # output to trace that the Machine self.objName was passivated for the current failure time self.outputTrace( self.getActiveObjectQueue()[0].name, "passivated in " + self.objName + " for " + str(self.env.now - breakTime)) # =============== request a resource after the repair if (self.operatorPool!="None")\ and any(type=="Processing" for type in self.multOperationTypeList)\ and not interruption: self.timeWaitForOperatorStarted = self.env.now self.requestOperator() yield waituntil, self, self.broker.brokerIsSet self.timeWaitForOperatorEnded = self.env.now self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted # if no interruption occurred the processing in M1 is ended else: processingEndedFlag = False # output to trace that the processing in the Machine self.objName ended self.outputTrace(self.getActiveObjectQueue()[0].name, "ended processing in " + self.objName) # =============== release resource after the end of processing if (self.operatorPool!='None')\ and any(type=="Processing" for type in self.multOperationTypeList)\ and not interruption: self.releaseOperator() yield waituntil, self, self.broker.brokerIsSet # set the variable that flags an Entity is ready to be disposed self.waitToDispose = True # update the total working time self.totalWorkingTime += self.totalProcessingTimeInCurrentEntity # the total processing time for this entity # is what the distribution initially gave # update the variables keeping track of Entity related attributes of the machine self.timeLastEntityEnded = self.env.now # this holds the time that the last entity ended processing in Machine self.nameLastEntityEnded = self.currentEntity.name # this holds the name of the last entity that ended processing in Machine self.completedJobs += 1 # Machine completed one more Job # re-initialize the downTimeProcessingCurrentEntity. # a new machine is about to enter self.downTimeProcessingCurrentEntity = 0 # dummy variable requests the successor object now reqTime = self.env.now # entity has ended processing in Machine and requests for the next object # initialize the timer downTimeInTryingToReleaseCurrentEntity, we have to count how much time # the Entity will wait for the next successor to be able to accept (canAccept) self.downTimeInTryingToReleaseCurrentEntity = 0 while 1: # wait until the next Object is available or machine has failure yield waituntil, self, self.ifCanDisposeOrHaveFailure # if Next object available break if self.Up: break # if M1 had failure, we want to wait until it is fixed and also count the failure time. else: failTime = self.env.now # dummy variable holding the time failure happened # passivate until machine is up yield waituntil, self, self.checkIfMachineIsUp failureTime += self.env.now - failTime # count the failure while on current entity time with failureTime variable # calculate the time the Machine was down while trying to dispose the current Entity, # and the total down time while on current Entity self.downTimeInTryingToReleaseCurrentEntity += self.env.now - failTime self.downTimeInCurrentEntity += self.env.now - failTime # already updated from failures during processing # update the timeLastFailureEnded self.timeLastFailureEnded = self.env.now # dummy variable holding the total time the Entity spent in the Machine # count the time the Machine was blocked subtracting the failureTime # and the processing time from the totalTime spent in the Machine self.totalTimeInCurrentEntity = self.env.now - timeEntered # ======================================================================= # checks if the Machine can accept an entity # it checks also who called it and returns TRUE only to the predecessor # that will give the entity. # ======================================================================= def canAccept(self, callerObject=None): # get active and giver objects activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() giverObject = self.getGiverObject() # if we have only one predecessor just check if there is a place and the machine is up # this is done to achieve better (cpu) processing time # then we can also use it as a filter for a yield method if (len(activeObject.previous) == 1 or callerObject == None): if (activeObject.operatorPool != 'None' and any(type == 'Load' for type in activeObject.multOperationTypeList)): return activeObject.operatorPool.checkIfResourceIsAvailable()\ and activeObject.Up\ and len(activeObjectQueue)<activeObject.capacity else: return activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ thecaller = callerObject # return True ONLY if the length of the activeOjbectQue is smaller than # the object capacity, and the callerObject is not None but the giverObject if (activeObject.operatorPool != 'None' and any(type == 'Load' for type in activeObject.multOperationTypeList)): return activeObject.operatorPool.checkIfResourceIsAvailable()\ and activeObject.Up\ and len(activeObjectQueue)<activeObject.capacity else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators return activeObject.Up and len( activeObjectQueue) < activeObject.capacity # while if the set up is performed before the (automatic) loading of the machine then the availability of the # operator is requested # return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity # ======================================================================= # checks if the Machine can accept an entity and there is an entity in # some possible giver waiting for it # also updates the giver to the one that is to be taken # ======================================================================= def canAcceptAndIsRequested(self): # get active and giver objects activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() giverObject = self.getGiverObject() # if we have only one predecessor just check if there is a place, # the machine is up and the predecessor has an entity to dispose # if the machine has to compete for an Operator that loads the entities onto it # check if the predecessor if blocked by an other Machine # if not then the machine has to block the predecessor giverObject to avoid conflicts # with other competing machines if (len(activeObject.previous) == 1): if (activeObject.operatorPool != 'None' and any(type == 'Load' for type in activeObject.multOperationTypeList)): if activeObject.operatorPool.checkIfResourceIsAvailable()\ and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ and giverObject.haveToDispose(activeObject) and not giverObject.exitIsAssigned(): activeObject.giver.assignExit() return True else: return False else: # the operator performs no load and the entity is received by the machine while there is # no need for operators presence. The operator needs to be present only where the load Type # operation is assigned return activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ and giverObject.haveToDispose(activeObject) # if the set-up performance needs be first performed before the transfer of the entity to # the machine then the presence of an operator to setup the machine before the getEntity() # is requested # return (activeObject.operatorPool=='None'\ # or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ # and giverObject.haveToDispose() # dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject) isRequested = False # is requested is dummyVariable checking if it is requested to accept an item maxTimeWaiting = 0 # dummy variable counting the time a predecessor is blocked # loop through the possible givers to see which have to dispose and which is the one blocked for longer for object in activeObject.previous: if (object.haveToDispose(activeObject) ): # and not object.exitIsAssigned()): isRequested = True # if the possible giver has entities to dispose of if ( object.downTimeInTryingToReleaseCurrentEntity > 0 ): # and the possible giver has been down while trying to give away the Entity timeWaiting = self.env.now - object.timeLastFailureEnded # the timeWaiting dummy variable counts the time end of the last failure of the giver object else: timeWaiting = self.env.now - object.timeLastEntityEnded # in any other case, it holds the time since the end of the Entity processing #if more than one possible givers have to dispose take the part from the one that is blocked longer if (timeWaiting >= maxTimeWaiting): activeObject.giver = object # set the giver maxTimeWaiting = timeWaiting if (activeObject.operatorPool != 'None' and any(type == 'Load' for type in activeObject.multOperationTypeList)): if activeObject.operatorPool.checkIfResourceIsAvailable()\ and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ and isRequested and not activeObject.giver.exitIsAssigned(): activeObject.giver.assignExit() return True else: return False else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators return activeObject.Up and len( activeObjectQueue) < activeObject.capacity and isRequested # while if the set up is performed before the (automatic) loading of the machine then the availability of the # operator is requested # return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\ # and activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested # ======================================================================= # calculates the setup time # ======================================================================= def calculateSetupTime(self): return self.stpRng.generateNumber() # ======================================================================= # calculates the Load time # ======================================================================= def calculateLoadTime(self): return self.loadRng.generateNumber() # ======================================================================= # prepare the machine to be operated # ======================================================================= def requestOperator(self): self.broker.invokeBroker() self.toBeOperated = True # ======================================================================= # prepare the machine to be released # ======================================================================= def releaseOperator(self): self.broker.invokeBroker() self.toBeOperated = False # ======================================================================= # check if the machine is currently operated by an operator # ======================================================================= def isOperated(self): return self.toBeOperated # ======================================================================= # check if the machine is already set-up # ======================================================================= def isSetUp(self): return self.setUp # ======================================================================= # request that the machine is set-up by an operator # ======================================================================= def requestSetup(self): self.setUp = False # ======================================================================= # actions to be taken after the simulation ends # ======================================================================= def postProcessing(self, MaxSimtime=None): if MaxSimtime == None: from Globals import G MaxSimtime = G.maxSimTime activeObject = self.getActiveObject() activeObjectQueue = self.getActiveObjectQueue() alreadyAdded = False # a flag that shows if the blockage time has already been added # checks all the successors. If no one can accept an Entity then the machine might be blocked mightBeBlocked = True for nextObject in self.next: if nextObject.canAccept(): mightBeBlocked = False # if there is an entity that finished processing in a Machine but did not get to reach # the following Object till the end of simulation, # we have to add this blockage to the percentage of blockage in Machine # we should exclude the failure time in current entity though! # if (len(self.Res.activeQ)>0) and (len(self.next[0].Res.activeQ)>0) and ((self.nameLastEntityEntered == self.nameLastEntityEnded)): if (len(activeObjectQueue)>0) and (mightBeBlocked)\ and ((activeObject.nameLastEntityEntered == activeObject.nameLastEntityEnded)): # be careful here, might have to reconsider activeObject.totalBlockageTime += self.env.now - ( activeObject.timeLastEntityEnded + activeObject.downTimeInTryingToReleaseCurrentEntity) if activeObject.Up == False: activeObject.totalBlockageTime -= self.env.now - activeObject.timeLastFailure alreadyAdded = True #if Machine is currently processing an entity we should count this working time if(len(activeObject.getActiveObjectQueue())>0)\ and (not (activeObject.nameLastEntityEnded==activeObject.nameLastEntityEntered))\ and (not (activeObject.operationType=='Processing' and (activeObject.currentOperator==None))): #if Machine is down we should add this last failure time to the time that it has been down in current entity if self.Up == False: # if(len(activeObjectQueue)>0) and (self.Up==False): activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure activeObject.totalWorkingTime+=self.env.now-activeObject.timeLastEntityEntered\ -activeObject.downTimeProcessingCurrentEntity\ -activeObject.operatorWaitTimeCurrentEntity\ -activeObject.setupTimeCurrentEntity activeObject.totalTimeWaitingForOperator += activeObject.operatorWaitTimeCurrentEntity elif(len(activeObject.getActiveObjectQueue())>0)\ and (not (activeObject.nameLastEntityEnded==activeObject.nameLastEntityEntered))\ and (activeObject.currentOperator==None): # needs further research as the time of failure while waiting for operator is not counted yet if self.Up == False: activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure activeObject.totalTimeWaitingForOperator+=self.env.now-activeObject.timeWaitForOperatorStarted\ -activeObject.downTimeProcessingCurrentEntity # if Machine is down we have to add this failure time to its total failure time # we also need to add the last blocking time to total blockage time if (activeObject.Up == False): activeObject.totalFailureTime += self.env.now - activeObject.timeLastFailure # we add the value only if it hasn't already been added #if((len(self.next[0].Res.activeQ)>0) and (self.nameLastEntityEnded==self.nameLastEntityEntered) and (not alreadyAdded)): if ((mightBeBlocked) and (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered) and (not alreadyAdded)): activeObject.totalBlockageTime += ( self.env.now - activeObject.timeLastEntityEnded) - ( self.env.now - activeObject.timeLastFailure ) - activeObject.downTimeInTryingToReleaseCurrentEntity #Machine was idle when it was not in any other state activeObject.totalWaitingTime = MaxSimtime - activeObject.totalWorkingTime - activeObject.totalBlockageTime - activeObject.totalFailureTime if activeObject.totalBlockageTime < 0 and activeObject.totalBlockageTime > -0.00001: #to avoid some effects of getting negative cause of rounding precision self.totalBlockageTime = 0 if activeObject.totalWaitingTime < 0 and activeObject.totalWaitingTime > -0.00001: #to avoid some effects of getting negative cause of rounding precision self.totalWaitingTime = 0 activeObject.Failure.append(100 * self.totalFailureTime / MaxSimtime) activeObject.Blockage.append(100 * self.totalBlockageTime / MaxSimtime) activeObject.Waiting.append(100 * self.totalWaitingTime / MaxSimtime) activeObject.Working.append(100 * self.totalWorkingTime / MaxSimtime) activeObject.WaitingForOperator.append( 100 * self.totalTimeWaitingForOperator / MaxSimtime) activeObject.WaitingForLoadOperator.append( 100 * self.totalTimeWaitingForLoadOperator / MaxSimtime) activeObject.Loading.append(100 * self.totalLoadTime / MaxSimtime) activeObject.SettingUp.append(100 * self.totalSetupTime / MaxSimtime)
class MachineManagedJob(MachineJobShop): # ======================================================================= # initialise the MachineManagedJob # ======================================================================= def initialize(self): MachineJobShop.initialize(self) self.type="MachineManagedJob" #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested id = self.id+'_OP' name=self.objName+'_operatorPool' self.operatorPool=OperatorPool(id, name, operatorsList=[]) self.operatorPool.initialize() self.operatorPool.operators=[] #create a Broker self.broker = Broker(self) activate(self.broker,self.broker.run()) #create a Router from Globals import G if len(G.RoutersList)==0: self.router=Router() activate(self.router,self.router.run()) G.RoutersList.append(self.router) # otherwise set the already existing router as the machines Router else: self.router=G.RoutersList[0] # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested self.entityToGet=None # ======================================================================= # 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): activeObject=self.getActiveObject() activeObjectQueue=activeObject.getActiveObjectQueue() thecaller=callerObject if (thecaller!=None): #check it the caller object holds an Entity that requests for current object if len(thecaller.getActiveObjectQueue())>0: # TODO: make sure that the first entity of the callerObject is to be disposed activeEntity=thecaller.getActiveObjectQueue()[0] # if the machine's Id is in the list of the entity's next stations if activeObject.id in activeEntity.remainingRoute[0].get('stationIdsList',[]): #return according to the state of the Queue return len(activeObject.getActiveObjectQueue())<activeObject.capacity\ and activeObject.Up return False # ======================================================================= # checks if the Machine can accept an entity and there is an entity in # some possible giver waiting for it # also updates the giver to the one that is to be taken # ======================================================================= def canAcceptAndIsRequested(self): # get active and giver objects activeObject=self.getActiveObject() activeObjectQueue=self.getActiveObjectQueue() giverObject=self.getGiverObject() # dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject) isRequested=False # is requested is dummyVariable checking if it is requested to accept an item maxTimeWaiting=0 # dummy variable counting the time a predecessor is blocked # loop through the possible givers to see which have to dispose and which is the one blocked for longer for object in activeObject.previous: if(object.haveToDispose(activeObject) and object.receiver==self):# and not object.exitIsAssigned()): isRequested=True # if the possible giver has entities to dispose of if(object.downTimeInTryingToReleaseCurrentEntity>0):# and the possible giver has been down while trying to give away the Entity timeWaiting=now()-object.timeLastFailureEnded # the timeWaiting dummy variable counts the time end of the last failure of the giver object else: timeWaiting=now()-object.timeLastEntityEnded # in any other case, it holds the time since the end of the Entity processing #if more than one possible givers have to dispose take the part from the one that is blocked longer if(timeWaiting>=maxTimeWaiting): activeObject.giver=object # set the giver maxTimeWaiting=timeWaiting if (activeObject.operatorPool!='None' and (any(type=='Load' for type in activeObject.multOperationTypeList)\ or any(type=='Setup' for type in activeObject.multOperationTypeList))): if isRequested: # TODO: check whether this entity is the one to be hand in # to be used in operatorPreemptive activeObject.requestingEntity=activeObject.giver.getActiveObjectQueue()[0] # TODO: update the object requesting the operator activeObject.operatorPool.requestingObject=activeObject.giver # TODO: update the last object calling the operatorPool activeObject.operatorPool.receivingObject=activeObject if activeObject.Up and len(activeObjectQueue)<activeObject.capacity\ and self.checkOperator()\ and not activeObject.giver.exitIsAssigned(): activeObject.giver.assignExit() # if the activeObject is not in manager's activeCallersList of the entityToGet if self not in activeObject.giver.getActiveObjectQueue()[0].manager.activeCallersList: # append it to the activeCallerList of the manager of the entity to be received activeObject.giver.getActiveObjectQueue()[0].manager.activeCallersList.append(self) # update entityToGet self.entityToGet=activeObject.giver.getActiveObjectQueue()[0] #make the operators List so that it holds only the manager of the current order activeObject.operatorPool.operators=[activeObject.giver.getActiveObjectQueue()[0].manager] # # set the variable operatorAssignedTo to activeObject, the operator is then blocked # activeObject.operatorPool.operators[0].operatorAssignedTo=activeObject # # TESTING # print now(), activeObject.operatorPool.operators[0].objName, 'got assigned to', activeObject.id # read the load time of the machine self.readLoadTime() return True else: return False else: # the operator doesn't have to be present for the loading of the machine as the load operation # is not assigned to operators if activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested: # update entityToGet self.entityToGet=self.giver.getActiveObjectQueue()[0] return activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested # ======================================================================= # to be called by canAcceptAndIsRequested and check for the operator # ======================================================================= def checkOperator(self): if self.giver.getActiveObjectQueue()[0].manager: manager=self.giver.getActiveObjectQueue()[0].manager # print '' # print 'Entity',self.giver.getActiveObjectQueue()[0].id # print 'manager',manager.id return manager.checkIfResourceIsAvailable() else: return True # ======================================================================= # identifies the Entity to be obtained so that # getEntity gives it to removeEntity as argument # ======================================================================= def identifyEntityToGet(self): # ToDecide # maybe we should work this way in all CoreObjects??? return self.entityToGet # ======================================================================= # checks if the object is ready to receive an Entity # ======================================================================= def isReadyToGet(self): # check if the entity that is about to be obtained has a manager (this should be true for this object) if self.entityToGet.manager: manager=self.entityToGet.manager if len(manager.activeCallersList)>0: manager.sortEntities() # sort the callers of the manager to be used for scheduling rules # return true if the manager is available return manager.checkIfResourceIsAvailable() else: return True # ======================================================================= # prepare the machine to be released # ======================================================================= def releaseOperator(self): self.outputTrace(self.currentOperator.objName, "released from "+ self.objName) # # TESTING # print now(), self.id, 'will release operator', self.operatorPool.operators[0].objName # set the flag operatorAssignedTo to None self.operatorPool.operators[0].operatorAssignedTo=None self.broker.invokeBroker() self.toBeOperated = False