Example #1
0
 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
Example #2
0
 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
Example #3
0
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        
Example #4
0
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 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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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")
Example #10
0
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
Example #11
0
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.Router:
            # 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
Example #12
0
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                                
Example #13
0
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")
Example #14
0
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
Example #15
0
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")
Example #16
0
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")
Example #17
0
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
Example #18
0
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
Example #19
0
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