Ejemplo n.º 1
0
 def initialize(self):
     Machine.initialize(self)
     # initiate the Broker responsible to control the request/release
     # initialize the operator pool if any
     if (self.operatorPool != "None"):
         self.operatorPool.initialize()
         self.broker = Broker(self)
         activate(self.broker, self.broker.run())
         for operator in self.operatorPool.operators:
             operator.coreObjectIds.append(self.id)
             operator.coreObjects.append(self)
     # the time that the machine started/ended its wait for the operator
     self.timeWaitForOperatorStarted = 0
     self.timeWaitForOperatorEnded = 0
     self.totalTimeWaitingForOperator = 0
     # the time that the machine started/ended its wait for the operator
     self.timeWaitForLoadOperatorStarted = 0
     self.timeWaitForLoadOperatorEnded = 0
     self.totalTimeWaitingForLoadOperator = 0
     # the time that the operator started/ended loading the machine
     self.timeLoadStarted = 0
     self.timeLoadEnded = 0
     self.totalLoadTime = 0
     # the time that the operator started/ended setting-up the machine
     self.timeSetupStarted = 0
     self.timeSetupEnded = 0
     self.totalSetupTime = 0
     # Current entity load/setup/loadOperatorwait/operatorWait related times
     self.operatorWaitTimeCurrentEntity = 0  # holds the time that the machine was waiting for the operator
     self.loadOperatorWaitTimeCurrentEntity = 0  # holds the time that the machine waits for operator to load the it
     self.loadTimeCurrentEntity = 0  # holds the time to load the current entity
     self.setupTimeCurrentEntity = 0  # holds the time to setup the machine before processing the current entity
Ejemplo n.º 2
0
 def initialize(self):
     Machine.initialize(self)
     # initiate the Broker responsible to control the request/release
     # initialize the operator pool if any
     if self.operatorPool != "None":
         self.operatorPool.initialize()
         self.broker = Broker(self)
         activate(self.broker, self.broker.run())
         for operator in self.operatorPool.operators:
             operator.coreObjectIds.append(self.id)
             operator.coreObjects.append(self)
     # the time that the machine started/ended its wait for the operator
     self.timeWaitForOperatorStarted = 0
     self.timeWaitForOperatorEnded = 0
     self.totalTimeWaitingForOperator = 0
     # the time that the machine started/ended its wait for the operator
     self.timeWaitForLoadOperatorStarted = 0
     self.timeWaitForLoadOperatorEnded = 0
     self.totalTimeWaitingForLoadOperator = 0
     # the time that the operator started/ended loading the machine
     self.timeLoadStarted = 0
     self.timeLoadEnded = 0
     self.totalLoadTime = 0
     # the time that the operator started/ended setting-up the machine
     self.timeSetupStarted = 0
     self.timeSetupEnded = 0
     self.totalSetupTime = 0
     # Current entity load/setup/loadOperatorwait/operatorWait related times
     self.operatorWaitTimeCurrentEntity = 0  # holds the time that the machine was waiting for the operator
     self.loadOperatorWaitTimeCurrentEntity = 0  # holds the time that the machine waits for operator to load the it
     self.loadTimeCurrentEntity = 0  # holds the time to load the current entity
     self.setupTimeCurrentEntity = 0  # holds the time to setup the machine before processing the current entity
Ejemplo n.º 3
0
 def initialize(self):
     MachineJobShop.initialize(self)
     self.type="MachineManagedJob"
     #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested
     id = self.id+'_OP'
     name=self.objName+'_operatorPool'
     self.operatorPool=OperatorPool(id, name, operatorsList=[])
     self.operatorPool.initialize()
     self.operatorPool.operators=[]
     #create a Broker
     self.broker = Broker(self)
     activate(self.broker,self.broker.run())
     #create a Router
     from Globals import G
     if len(G.RoutersList)==0:
         self.router=Router()
         activate(self.router,self.router.run())
         G.RoutersList.append(self.router)
     # otherwise set the already existing router as the machines Router
     else:
         self.router=G.RoutersList[0]
     # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested
     self.entityToGet=None
Ejemplo n.º 4
0
class OperatedMachine(Machine):
    # =======================================================================
    # initialise the id the capacity, of the resource and the distribution
    # =======================================================================
    def __init__(
        self,
        id,
        name,
        capacity=1,
        processingTime=None,
        failureDistribution="No",
        MTTF=0,
        MTTR=0,
        availability=0,
        repairman="None",
        operatorPool="None",
        operationType="None",
        setupTime=None,
        loadTime=None,
    ):
        Machine.__init__(
            self,
            id,
            name,
            capacity=capacity,
            processingTime=processingTime,
            failureDistribution=failureDistribution,
            MTTF=MTTF,
            MTTR=MTTR,
            availability=availability,
            repairman=repairman,
            operatorPool=operatorPool,
            operationType=operationType,
            setupTime=setupTime,
            loadTime=loadTime,
        )

        # type of the machine
        self.type = "OperatedMachine"
        # sets the operator resource of the Machine
        #     check if the operatorPool is a List or a OperatorPool type Object
        #     if it is a list then initiate a OperatorPool type object containing
        #     the list of operators provided
        """
            change! if the  list is empty create operator pool with empty list
        """
        if type(operatorPool) is list:  # and len(operatorPool)>0:
            id = id + "_OP"
            name = self.objName + "_operatorPool"
            self.operatorPool = OperatorPool(id, name, operatorsList=operatorPool)
        else:
            self.operatorPool = operatorPool
        # update the operatorPool coreObjects list
        if self.operatorPool != "None":
            self.operatorPool.coreObjectIds.append(self.id)
            self.operatorPool.coreObjects.append(self)
        # holds the Operator currently processing the Machine
        self.currentOperator = None
        # define if load/setup/removal/processing are performed by the operator
        self.operationType = operationType
        # boolean to check weather the machine is being operated
        self.toBeOperated = False

        # examine if there are multiple operation types performed by the operator
        #     there can be Setup/Processing operationType
        #     or the combination of both (MT-Load-Setup-Processing)
        self.multOperationTypeList = []
        if self.operationType.startswith("MT"):
            OTlist = operationType.split("-")
            self.operationType = OTlist.pop(0)
            self.multOperationTypeList = OTlist
        else:
            self.multOperationTypeList.append(self.operationType)
        #     lists to hold statistics of multiple runs
        self.WaitingForOperator = []
        self.WaitingForLoadOperator = []
        self.Loading = []
        self.SettingUp = []

    # =======================================================================
    # initialize the machine
    # =======================================================================
    def initialize(self):
        Machine.initialize(self)
        # initiate the Broker responsible to control the request/release
        # initialize the operator pool if any
        if self.operatorPool != "None":
            self.operatorPool.initialize()
            self.broker = Broker(self)
            activate(self.broker, self.broker.run())
            for operator in self.operatorPool.operators:
                operator.coreObjectIds.append(self.id)
                operator.coreObjects.append(self)
        # the time that the machine started/ended its wait for the operator
        self.timeWaitForOperatorStarted = 0
        self.timeWaitForOperatorEnded = 0
        self.totalTimeWaitingForOperator = 0
        # the time that the machine started/ended its wait for the operator
        self.timeWaitForLoadOperatorStarted = 0
        self.timeWaitForLoadOperatorEnded = 0
        self.totalTimeWaitingForLoadOperator = 0
        # the time that the operator started/ended loading the machine
        self.timeLoadStarted = 0
        self.timeLoadEnded = 0
        self.totalLoadTime = 0
        # the time that the operator started/ended setting-up the machine
        self.timeSetupStarted = 0
        self.timeSetupEnded = 0
        self.totalSetupTime = 0
        # Current entity load/setup/loadOperatorwait/operatorWait related times
        self.operatorWaitTimeCurrentEntity = 0  # holds the time that the machine was waiting for the operator
        self.loadOperatorWaitTimeCurrentEntity = 0  # holds the time that the machine waits for operator to load the it
        self.loadTimeCurrentEntity = 0  # holds the time to load the current entity
        self.setupTimeCurrentEntity = 0  # holds the time to setup the machine before processing the current entity

    # =======================================================================
    # the main process of the machine
    # =======================================================================
    def run(self):
        # execute all through simulation time
        while 1:
            # wait until the machine can accept an entity and one predecessor requests it
            # canAcceptAndIsRequested is invoked to check when the machine requested to receive an entity
            yield waituntil, self, self.canAcceptAndIsRequested

            # here or in the get entity (apart from the loatTimeCurrentEntity)
            # in case they are placed inside the getEntity then the initialize of
            # the corresponding variables should be moved to the initialize() of the CoreObject
            self.operatorWaitTimeCurrentEntity = 0
            self.loadOperatorWaitTimeCurrentEntity = 0
            self.loadTimeCurrentEntity = 0
            self.setupTimeCurrentEntity = 0

            # ======= request a resource
            if (self.operatorPool != "None") and any(type == "Load" for type in self.multOperationTypeList):
                # when it's ready to accept (canAcceptAndIsRequested) then inform the broker
                # machines waits to be operated (waits for the operator)
                self.requestOperator()
                self.timeWaitForLoadOperatorStarted = self.env.now
                # wait until the Broker has waited times equal to loadTime (if any)
                yield waituntil, self, self.broker.brokerIsSet
                self.timeWaitForLoadOperatorEnded = self.env.now
                self.loadOperatorWaitTimeCurrentEntity += (
                    self.timeWaitForLoadOperatorEnded - self.timeWaitForLoadOperatorStarted
                )
                self.totalTimeWaitingForLoadOperator += self.loadOperatorWaitTimeCurrentEntity

            # ======= Load the machine if the Load is defined as one of the Operators' operation types
            if any(type == "Load" for type in self.multOperationTypeList) and self.isOperated():
                self.timeLoadStarted = self.env.now
                yield hold, self, self.calculateLoadTime()
                # if self.interrupted(): There is the issue of failure during the Loading
                self.timeLoadEnded = self.env.now
                self.loadTimeCurrentEntity = self.timeLoadEnded - self.timeLoadStarted
                self.totalLoadTime += self.loadTimeCurrentEntity

            # ======= release a resource if the only operation type is Load
            if (
                (self.operatorPool != "None")
                and any(type == "Load" for type in self.multOperationTypeList)
                and not any(type == "Processing" or type == "Setup" for type in self.multOperationTypeList)
                and self.isOperated()
            ):
                # after getting the entity release the operator
                # machine has to release the operator
                self.releaseOperator()
                # wait until the Broker has finished processing
                yield waituntil, self, self.broker.brokerIsSet

            # get the entity
            # if there was loading time then we must solve the problem of getting an entity
            # from an unidentified giver or not getting an entity at all as the giver
            # may fall in failure mode
            self.currentEntity = self.getEntity()

            # set the currentEntity as the Entity just received and initialize the timer timeLastEntityEntered
            self.nameLastEntityEntered = (
                self.currentEntity.name
            )  # this holds the name of the last entity that got into Machine
            self.timeLastEntityEntered = self.env.now  # this holds the last time that an entity got into Machine
            # variables dedicated to hold the processing times, the time when the Entity entered,
            # and the processing time left
            timeEntered = self.env.now  # timeEntered dummy Timer that holds the time the last Entity Entered

            # ======= request a resource if it is not already assigned an Operator
            if (
                (self.operatorPool != "None")
                and any(type == "Processing" or type == "Setup" for type in self.multOperationTypeList)
                and not self.isOperated()
            ):
                # when it's ready to accept (canAcceptAndIsRequested) then inform the broker
                # machines waits to be operated (waits for the operator)
                self.requestOperator()
                self.timeWaitForOperatorStarted = self.env.now
                # wait until the Broker has waited times equal to loadTime (if any)
                yield waituntil, self, self.broker.brokerIsSet
                self.timeWaitForOperatorEnded = self.env.now
                self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted

            self.totalProcessingTimeInCurrentEntity = (
                self.calculateProcessingTime()
            )  # get the processing time, tinMStarts holds the processing time of the machine
            tinM = self.totalProcessingTimeInCurrentEntity  # timer to hold the processing time left

            # ======= setup the machine if the Setup is defined as one of the Operators' operation types
            # in plantSim the setup is performed when the machine has to process a new type of Entity and only once
            if any(type == "Setup" for type in self.multOperationTypeList) and self.isOperated():
                self.timeSetupStarted = self.env.now
                yield hold, self, self.calculateSetupTime()
                # if self.interrupted(): There is the issue of failure during the setup
                self.timeSetupEnded = self.env.now
                self.setupTimeCurrentEntity = self.timeSetupEnded - self.timeSetupStarted
                self.totalSetupTime += self.setupTimeCurrentEntity

            # ======= release a resource if the only operation type is Setup
            if (
                (self.operatorPool != "None")
                and self.isOperated()
                and any(type == "Setup" or type == "Load" for type in self.multOperationTypeList)
                and not any(type == "Processing" for type in self.multOperationTypeList)
            ):
                # after getting the entity release the operator
                # machine has to release the operator
                self.releaseOperator()
                #                 print self.objName, 'operator released', self.env.now
                # wait until the Broker has finished processing
                yield waituntil, self, self.broker.brokerIsSet

            # variables used to flag any interruptions and the end of the processing
            interruption = False
            processingEndedFlag = True
            # timers to follow up the failure time of the machine while on current Entity
            failureTime = 0  # dummy variable keeping track of the failure time
            # might be feasible to avoid it
            self.downTimeInCurrentEntity = 0  # holds the total time that the
            # object was down while holding current entity
            # this loop is repeated until the processing time is expired with no failure
            # check when the processingEndedFlag switched to false
            while processingEndedFlag:
                # tBefore : dummy variable to keep track of the time that the processing starts after
                #           every interruption
                tBefore = self.env.now
                # wait for the processing time left tinM, if no interruption occurs then change the
                # processingEndedFlag and exit loop,
                # else (if interrupted()) set interruption flag to true (only if tinM==0),
                # and recalculate the processing time left tinM,
                # passivate while waiting for repair.
                yield hold, self, tinM  # getting processed for remaining processing time tinM
                if self.interrupted():  # if a failure occurs while processing the machine is interrupted.
                    # output to trace that the Machine (self.objName) got interrupted
                    self.outputTrace(self.getActiveObjectQueue()[0].name, "Interrupted at " + self.objName)
                    # recalculate the processing time left tinM
                    tinM = tinM - (self.env.now - tBefore)
                    if (
                        tinM == 0
                    ):  # sometimes the failure may happen exactly at the time that the processing would finish
                        # this may produce disagreement with the simul8 because in both SimPy and Simul8
                        # it seems to be random which happens 1st
                        # this should not appear often to stochastic models though where times are random
                        interruption = True
                    # passivate the Machine for as long as there is no repair
                    # start counting the down time at breatTime dummy variable
                    breakTime = self.env.now  # dummy variable that the interruption happened

                    # =============== release the operator if there is failure
                    if (
                        (self.operatorPool != "None")
                        and self.isOperated()
                        and any(type == "Processing" for type in self.multOperationTypeList)
                    ):
                        self.releaseOperator()
                        #                         print self.objName, 'operator released due to failure', self.env.now
                        yield waituntil, self, self.broker.brokerIsSet

                    # if there is a failure in the machine it is passivated
                    yield passivate, self
                    # use the timers to count the time that Machine is down and related
                    self.downTimeProcessingCurrentEntity += (
                        self.env.now - breakTime
                    )  # count the time that Machine is down while processing this Entity
                    self.downTimeInCurrentEntity += (
                        self.env.now - breakTime
                    )  # count the time that Machine is down while on currentEntity
                    self.timeLastFailureEnded = self.env.now  # set the timeLastFailureEnded
                    failureTime += self.env.now - breakTime  # dummy variable keeping track of the failure time
                    # output to trace that the Machine self.objName was passivated for the current failure time
                    self.outputTrace(
                        self.getActiveObjectQueue()[0].name,
                        "passivated in " + self.objName + " for " + str(self.env.now - breakTime),
                    )

                    # =============== request a resource after the repair
                    if (
                        (self.operatorPool != "None")
                        and any(type == "Processing" for type in self.multOperationTypeList)
                        and not interruption
                    ):
                        self.timeWaitForOperatorStarted = self.env.now
                        self.requestOperator()
                        yield waituntil, self, self.broker.brokerIsSet
                        self.timeWaitForOperatorEnded = self.env.now
                        self.operatorWaitTimeCurrentEntity += (
                            self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted
                        )

                # if no interruption occurred the processing in M1 is ended
                else:
                    processingEndedFlag = False
            # output to trace that the processing in the Machine self.objName ended
            self.outputTrace(self.getActiveObjectQueue()[0].name, "ended processing in " + self.objName)

            # =============== release resource after the end of processing
            if (
                (self.operatorPool != "None")
                and any(type == "Processing" for type in self.multOperationTypeList)
                and not interruption
            ):
                self.releaseOperator()
                yield waituntil, self, self.broker.brokerIsSet

            # set the variable that flags an Entity is ready to be disposed
            self.waitToDispose = True
            # update the total working time
            self.totalWorkingTime += (
                self.totalProcessingTimeInCurrentEntity
            )  # the total processing time for this entity
            # is what the distribution initially gave

            # update the variables keeping track of Entity related attributes of the machine
            self.timeLastEntityEnded = (
                self.env.now
            )  # this holds the time that the last entity ended processing in Machine
            self.nameLastEntityEnded = (
                self.currentEntity.name
            )  # this holds the name of the last entity that ended processing in Machine
            self.completedJobs += 1  # Machine completed one more Job
            # re-initialize the downTimeProcessingCurrentEntity.
            # a new machine is about to enter
            self.downTimeProcessingCurrentEntity = 0

            # dummy variable requests the successor object now
            reqTime = self.env.now  # entity has ended processing in Machine and requests for the next object
            # initialize the timer downTimeInTryingToReleaseCurrentEntity, we have to count how much time
            # the Entity will wait for the next successor to be able to accept (canAccept)
            self.downTimeInTryingToReleaseCurrentEntity = 0

            while 1:
                # wait until the next Object is available or machine has failure
                yield waituntil, self, self.ifCanDisposeOrHaveFailure

                # if Next object available break
                if self.Up:
                    break
                # if M1 had failure, we want to wait until it is fixed and also count the failure time.
                else:
                    failTime = self.env.now  # dummy variable holding the time failure happened
                    # passivate until machine is up
                    yield waituntil, self, self.checkIfMachineIsUp
                    failureTime += (
                        self.env.now - failTime
                    )  # count the failure while on current entity time with failureTime variable
                    # calculate the time the Machine was down while trying to dispose the current Entity,
                    # and the total down time while on current Entity
                    self.downTimeInTryingToReleaseCurrentEntity += self.env.now - failTime
                    self.downTimeInCurrentEntity += (
                        self.env.now - failTime
                    )  # already updated from failures during processing
                    # update the timeLastFailureEnded
                    self.timeLastFailureEnded = self.env.now

            # dummy variable holding the total time the Entity spent in the Machine
            # count the time the Machine was blocked subtracting the failureTime
            #    and the processing time from the totalTime spent in the Machine
            self.totalTimeInCurrentEntity = self.env.now - timeEntered

    # =======================================================================
    # checks if the Machine can accept an entity
    # it checks also who called it and returns TRUE only to the predecessor
    # that will give the entity.
    # =======================================================================
    def canAccept(self, callerObject=None):
        # get active and giver objects
        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()
        giverObject = self.getGiverObject()

        # if we have only one predecessor just check if there is a place and the machine is up
        # this is done to achieve better (cpu) processing time
        # then we can also use it as a filter for a yield method
        if len(activeObject.previous) == 1 or callerObject == None:
            if activeObject.operatorPool != "None" and any(
                type == "Load" for type in activeObject.multOperationTypeList
            ):
                return (
                    activeObject.operatorPool.checkIfResourceIsAvailable()
                    and activeObject.Up
                    and len(activeObjectQueue) < activeObject.capacity
                )
            else:
                return activeObject.Up and len(activeObjectQueue) < activeObject.capacity
        thecaller = callerObject
        # return True ONLY if the length of the activeOjbectQue is smaller than
        # the object capacity, and the callerObject is not None but the giverObject
        if activeObject.operatorPool != "None" and any(type == "Load" for type in activeObject.multOperationTypeList):
            return (
                activeObject.operatorPool.checkIfResourceIsAvailable()
                and activeObject.Up
                and len(activeObjectQueue) < activeObject.capacity
            )
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            return activeObject.Up and len(activeObjectQueue) < activeObject.capacity
            # while if the set up is performed before the (automatic) loading of the machine then the availability of the
            # operator is requested

    #             return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\
    #                and activeObject.Up and len(activeObjectQueue)<activeObject.capacity

    # =======================================================================
    # checks if the Machine can accept an entity and there is an entity in
    # some possible giver waiting for it
    # also updates the giver to the one that is to be taken
    # =======================================================================
    def canAcceptAndIsRequested(self):
        # get active and giver objects
        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()
        giverObject = self.getGiverObject()
        # if we have only one predecessor just check if there is a place,
        # the machine is up and the predecessor has an entity to dispose
        # if the machine has to compete for an Operator that loads the entities onto it
        # check if the predecessor if blocked by an other Machine
        # if not then the machine has to block the predecessor giverObject to avoid conflicts
        # with other competing machines
        if len(activeObject.previous) == 1:
            if activeObject.operatorPool != "None" and any(
                type == "Load" for type in activeObject.multOperationTypeList
            ):
                if (
                    activeObject.operatorPool.checkIfResourceIsAvailable()
                    and activeObject.Up
                    and len(activeObjectQueue) < activeObject.capacity
                    and giverObject.haveToDispose(activeObject)
                    and not giverObject.exitIsAssigned()
                ):
                    activeObject.giver.assignExit()
                    return True
                else:
                    return False
            else:
                # the operator performs no load and the entity is received by the machine while there is
                # no need for operators presence. The operator needs to be present only where the load Type
                # operation is assigned
                return (
                    activeObject.Up
                    and len(activeObjectQueue) < activeObject.capacity
                    and giverObject.haveToDispose(activeObject)
                )
                # if the set-up performance needs be first performed before the transfer of the entity to
                # the machine then the presence of an operator to setup the machine before the getEntity()
                # is requested
        #                 return (activeObject.operatorPool=='None'\
        #                         or activeObject.operatorPool.checkIfResourceIsAvailable())\
        #                         and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
        #                         and giverObject.haveToDispose()

        # dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject)
        isRequested = False  # is requested is dummyVariable checking if it is requested to accept an item
        maxTimeWaiting = 0  # dummy variable counting the time a predecessor is blocked

        # loop through the possible givers to see which have to dispose and which is the one blocked for longer
        for object in activeObject.previous:
            if object.haveToDispose(activeObject):  # and not object.exitIsAssigned()):
                isRequested = True  # if the possible giver has entities to dispose of
                if (
                    object.downTimeInTryingToReleaseCurrentEntity > 0
                ):  # and the possible giver has been down while trying to give away the Entity
                    timeWaiting = (
                        self.env.now - object.timeLastFailureEnded
                    )  # the timeWaiting dummy variable counts the time end of the last failure of the giver object
                else:
                    timeWaiting = (
                        self.env.now - object.timeLastEntityEnded
                    )  # in any other case, it holds the time since the end of the Entity processing

                # if more than one possible givers have to dispose take the part from the one that is blocked longer
                if timeWaiting >= maxTimeWaiting:
                    activeObject.giver = object  # set the giver
                    maxTimeWaiting = timeWaiting

        if activeObject.operatorPool != "None" and any(type == "Load" for type in activeObject.multOperationTypeList):
            if (
                activeObject.operatorPool.checkIfResourceIsAvailable()
                and activeObject.Up
                and len(activeObjectQueue) < activeObject.capacity
                and isRequested
                and not activeObject.giver.exitIsAssigned()
            ):
                activeObject.giver.assignExit()
                return True
            else:
                return False
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            return activeObject.Up and len(activeObjectQueue) < activeObject.capacity and isRequested
            # while if the set up is performed before the (automatic) loading of the machine then the availability of the
            # operator is requested

    #             return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\
    #                 and activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested

    # =======================================================================
    #                       calculates the setup time
    # =======================================================================
    def calculateSetupTime(self):
        return self.stpRng.generateNumber()

    # =======================================================================
    #                        calculates the Load time
    # =======================================================================
    def calculateLoadTime(self):
        return self.loadRng.generateNumber()

    # =======================================================================
    #                   prepare the machine to be operated
    # =======================================================================
    def requestOperator(self):
        self.broker.invokeBroker()
        self.toBeOperated = True

    # =======================================================================
    #                   prepare the machine to be released
    # =======================================================================
    def releaseOperator(self):
        self.broker.invokeBroker()
        self.toBeOperated = False

    # =======================================================================
    #       check if the machine is currently operated by an operator
    # =======================================================================
    def isOperated(self):
        return self.toBeOperated

    # =======================================================================
    #               check if the machine is already set-up
    # =======================================================================
    def isSetUp(self):
        return self.setUp

    # =======================================================================
    #          request that the machine is set-up by an operator
    # =======================================================================
    def requestSetup(self):
        self.setUp = False

    # =======================================================================
    # actions to be taken after the simulation ends
    # =======================================================================
    def postProcessing(self, MaxSimtime=None):
        if MaxSimtime == None:
            from Globals import G

            MaxSimtime = G.maxSimTime

        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()

        alreadyAdded = False  # a flag that shows if the blockage time has already been added

        # checks all the successors. If no one can accept an Entity then the machine might be blocked
        mightBeBlocked = True
        for nextObject in self.next:
            if nextObject.canAccept():
                mightBeBlocked = False

        # if there is an entity that finished processing in a Machine but did not get to reach
        # the following Object till the end of simulation,
        # we have to add this blockage to the percentage of blockage in Machine
        # we should exclude the failure time in current entity though!
        # if (len(self.Res.activeQ)>0) and (len(self.next[0].Res.activeQ)>0) and ((self.nameLastEntityEntered == self.nameLastEntityEnded)):
        if (
            (len(activeObjectQueue) > 0)
            and (mightBeBlocked)
            and ((activeObject.nameLastEntityEntered == activeObject.nameLastEntityEnded))
        ):
            # be careful here, might have to reconsider
            activeObject.totalBlockageTime += self.env.now - (
                activeObject.timeLastEntityEnded + activeObject.downTimeInTryingToReleaseCurrentEntity
            )
            if activeObject.Up == False:
                activeObject.totalBlockageTime -= self.env.now - activeObject.timeLastFailure
                alreadyAdded = True

        # if Machine is currently processing an entity we should count this working time
        if (
            (len(activeObject.getActiveObjectQueue()) > 0)
            and (not (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered))
            and (not (activeObject.operationType == "Processing" and (activeObject.currentOperator == None)))
        ):
            # if Machine is down we should add this last failure time to the time that it has been down in current entity
            if self.Up == False:
                #             if(len(activeObjectQueue)>0) and (self.Up==False):
                activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure
            activeObject.totalWorkingTime += (
                self.env.now
                - activeObject.timeLastEntityEntered
                - activeObject.downTimeProcessingCurrentEntity
                - activeObject.operatorWaitTimeCurrentEntity
                - activeObject.setupTimeCurrentEntity
            )
            activeObject.totalTimeWaitingForOperator += activeObject.operatorWaitTimeCurrentEntity
        elif (
            (len(activeObject.getActiveObjectQueue()) > 0)
            and (not (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered))
            and (activeObject.currentOperator == None)
        ):
            # needs further research as the time of failure while waiting for operator is not counted yet
            if self.Up == False:
                activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure
            activeObject.totalTimeWaitingForOperator += (
                self.env.now - activeObject.timeWaitForOperatorStarted - activeObject.downTimeProcessingCurrentEntity
            )

        # if Machine is down we have to add this failure time to its total failure time
        # we also need to add the last blocking time to total blockage time
        if activeObject.Up == False:
            activeObject.totalFailureTime += self.env.now - activeObject.timeLastFailure
            # we add the value only if it hasn't already been added
            # if((len(self.next[0].Res.activeQ)>0) and (self.nameLastEntityEnded==self.nameLastEntityEntered) and (not alreadyAdded)):
            if (
                (mightBeBlocked)
                and (activeObject.nameLastEntityEnded == activeObject.nameLastEntityEntered)
                and (not alreadyAdded)
            ):
                activeObject.totalBlockageTime += (
                    (self.env.now - activeObject.timeLastEntityEnded)
                    - (self.env.now - activeObject.timeLastFailure)
                    - activeObject.downTimeInTryingToReleaseCurrentEntity
                )

        # Machine was idle when it was not in any other state
        activeObject.totalWaitingTime = (
            MaxSimtime - activeObject.totalWorkingTime - activeObject.totalBlockageTime - activeObject.totalFailureTime
        )

        if (
            activeObject.totalBlockageTime < 0 and activeObject.totalBlockageTime > -0.00001
        ):  # to avoid some effects of getting negative cause of rounding precision
            self.totalBlockageTime = 0

        if (
            activeObject.totalWaitingTime < 0 and activeObject.totalWaitingTime > -0.00001
        ):  # to avoid some effects of getting negative cause of rounding precision
            self.totalWaitingTime = 0

        activeObject.Failure.append(100 * self.totalFailureTime / MaxSimtime)
        activeObject.Blockage.append(100 * self.totalBlockageTime / MaxSimtime)
        activeObject.Waiting.append(100 * self.totalWaitingTime / MaxSimtime)
        activeObject.Working.append(100 * self.totalWorkingTime / MaxSimtime)
        activeObject.WaitingForOperator.append(100 * self.totalTimeWaitingForOperator / MaxSimtime)
        activeObject.WaitingForLoadOperator.append(100 * self.totalTimeWaitingForLoadOperator / MaxSimtime)
        activeObject.Loading.append(100 * self.totalLoadTime / MaxSimtime)
        activeObject.SettingUp.append(100 * self.totalSetupTime / MaxSimtime)
Ejemplo n.º 5
0
 def createBroker(self):
     #create a Broker
     self.broker = Broker(self)
Ejemplo n.º 6
0
class MachineManagedJob(MachineJobShop):

    # =======================================================================
    # initialise the MachineManagedJob
    # =======================================================================
    def initialize(self):
        MachineJobShop.initialize(self)
        self.type="MachineManagedJob"
        # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested
        self.entityToGet=None
    
    #===========================================================================
    # create an operatorPool if needed
    #===========================================================================
    def createOperatorPool(self,operatorPool):
        #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested
        id = self.id+'_OP'
        name=self.objName+'_operatorPool'
        self.operatorPool=OperatorPool(id, name, operatorsList=[])
        from Globals import G
        G.OperatorPoolsList.append(self.operatorPool)
    
    #===========================================================================
    # create broker if needed
    #===========================================================================
    def createBroker(self):
        #create a Broker
        self.broker = Broker(self)
    
    #===========================================================================
    # create router if needed
    #===========================================================================
    def createRouter(self):
        #create a Router
        from Globals import G
        if not G.Router:
            self.router=RouterManaged()
            G.Router=self.router          
        # otherwise set the already existing router as the machines Router
        else:
            self.router=G.Router
            
    #===========================================================================
    # initialize broker if needed
    #===========================================================================
    def initializeOperatorPool(self):
        self.operatorPool.initialize()
        self.operatorPool.operators=[]
    
    #===========================================================================
    # initialize broker if needed
    #===========================================================================
    def initializeBroker(self):
        self.broker.initialize()
        self.env.process(self.broker.run())
                
    #===========================================================================
    # initialize router if needed
    #===========================================================================
    def initializeRouter(self):
        if not self.router.isInitialized:
            self.router.initialize()
        if not self.router.isActivated:
            self.env.process(self.router.run())
            self.router.isActivated=True
    
    # =======================================================================
    # checks if the Queue can accept an entity       
    # TODO: cannot check here if the station in the route of the entity that will be received (if any)
    # as the giver (QueueManagedJob) will be sorted from giver.haveToDispose in self.canAcceptAndIsRequested method
    # ======================================================================= 
    def canAccept(self, callerObject=None):
        activeObject=self.getActiveObject()
        activeObjectQueue=activeObject.getActiveObjectQueue()
        #return according to the state of the Queue
        return len(activeObjectQueue)<activeObject.capacity\
                    and activeObject.checkIfMachineIsUp()\
                    and not activeObject.entryIsAssignedTo()
    
    # =======================================================================
    # checks if the Queue can accept an specific Entity       
    # it checks also the next station of the Entity 
    # and returns true only if the active object is the next station
    # ======================================================================= 
    def canAcceptEntity(self, callerEntity=None):
        activeObject=self.getActiveObject()
        activeObjectQueue=activeObject.getActiveObjectQueue()
        thecallerentity=callerEntity
        if (thecallerentity!=None):
            # if the machine's Id is in the list of the entity's next stations
            if activeObject.id in thecallerentity.remainingRoute[0].get('stationIdsList',[]):
                #return according to the state of the Queue
                return len(activeObjectQueue)<activeObject.capacity\
                        and activeObject.checkIfMachineIsUp()
        return False

    # =======================================================================
    # checks if the Machine can accept an entity and there is an entity in 
    # some possible giver waiting for it
    # also updates the giver to the one that is to be taken
    # =======================================================================
    def canAcceptAndIsRequested(self,callerObject=None):
        # get active and giver objects
        activeObject=self.getActiveObject()
        activeObjectQueue=self.getActiveObjectQueue()
#         giverObject=activeObject.getGiverObject()
        giverObject=callerObject
        assert giverObject, 'there must be a caller for canAcceptAndIsRequested'
        giverObjectQueue=giverObject.getActiveObjectQueue()
        # if the multOperationTypeList of the machine contains Load or Setup
        if (activeObject.operatorPool!='None' and (any(type=='Load' for type in activeObject.multOperationTypeList)\
                                                or any(type=='Setup' for type in activeObject.multOperationTypeList))):
            if giverObject.haveToDispose(activeObject):
                if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity\
                    and activeObject.checkOperator(giverObject):
                    if not giverObject.exitIsAssignedTo():
                        giverObject.assignExitTo(activeObject)
                    elif giverObject.exitIsAssignedTo()!=activeObject:
                        return False
                    # update entityToGet
                    activeObject.entityToGet=giverObjectQueue[0]
                    #make the operators List so that it holds only the manager of the current order
                    activeObject.operatorPool.operators=[giverObjectQueue[0].manager]
                    # read the load time of the machine
                    activeObject.readLoadTime(giverObject)
                    return True
            else:
                return False
        # if the multOperationTypeList contains only Processing
        elif (activeObject.operatorPool!='None' and any(type=='Processing' for type in activeObject.multOperationTypeList)):
            if giverObject.haveToDispose(activeObject):
                # the operator must not be available for the object to receive the entity
                #     the exit of the giver should not be assigned
                #     the manager must not be available for the entity to be delivered
                #        the operator to the machine while he is not needed for receiving the entity
                if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity:
                    # the entityToGet should be updated
                    activeObject.entityToGet=giverObjectQueue[0]
                    #make the operators List so that it holds only the manager of the current order
                    activeObject.operatorPool.operators=[giverObjectQueue[0].manager]
                    # read the load time of the machine
                    activeObject.readLoadTime(giverObject)
                    return True
            else:
                return False
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            if activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity and giverObject.haveToDispose(activeObject):
                # update entityToGet
                activeObject.entityToGet=giverObject.getActiveObjectQueue()[0]
                activeObject.readLoadTime(giverObject)
            return activeObject.checkIfActive() and len(activeObjectQueue)<activeObject.capacity and giverObject.haveToDispose(activeObject)

    # =======================================================================
    # to be called by canAcceptAndIsRequested and check for the operator
    # =======================================================================    
    def checkOperator(self,callerObject=None): #, candidateEntity=None):
        assert callerObject!=None, 'checkOperator must have a caller for MachineManagedJob'
        activeObject=self.getActiveObject()
#         giverObject=activeObject.getGiverObject()
        giverObject=callerObject
        giverObjectQueue=giverObject.getActiveObjectQueue()
        if giverObjectQueue[0].manager:
            manager=giverObjectQueue[0].manager
            # TODO: consider using a caller in this case
            return manager.checkIfResourceIsAvailable(activeObject)
        else:
            return True 
#         if candidateEntity:
#             if candidateEntity.manager:
#                 manager=candidateEntity.manager
#                 return manager.checkIfResourceIsAvailable()
#             else:
#                 return True
#         return False 
        
    # =======================================================================
    #             identifies the Entity to be obtained so that 
    #            getEntity gives it to removeEntity as argument
    # =======================================================================    
    def identifyEntityToGet(self):
        # ToDecide
        # maybe we should work this way in all CoreObjects???
        return self.entityToGet
Ejemplo n.º 7
0
class OperatedMachine(Machine):
    # =======================================================================
    # initialise the id the capacity, of the resource and the distribution
    # =======================================================================
    def __init__(self, id, name, capacity=1, processingTime=None,
                  failureDistribution='No', MTTF=0, MTTR=0, availability=0, repairman='None',\
                  operatorPool='None',operationType='None',
                  setupTime=None, loadTime=None):
        Machine.__init__(
            self,
            id,
            name,
            capacity=capacity,
            processingTime=processingTime,
            failureDistribution=failureDistribution,
            MTTF=MTTF,
            MTTR=MTTR,
            availability=availability,
            repairman=repairman,
            operatorPool=operatorPool,
            operationType=operationType,
            setupTime=setupTime,
            loadTime=loadTime,
        )

        # type of the machine
        self.type = "OperatedMachine"
        # sets the operator resource of the Machine
        #     check if the operatorPool is a List or a OperatorPool type Object
        #     if it is a list then initiate a OperatorPool type object containing
        #     the list of operators provided
        '''
            change! if the  list is empty create operator pool with empty list
        '''
        if (type(operatorPool) is list):  #and len(operatorPool)>0:
            id = id + '_OP'
            name = self.objName + '_operatorPool'
            self.operatorPool = OperatorPool(id,
                                             name,
                                             operatorsList=operatorPool)
        else:
            self.operatorPool = operatorPool
        # update the operatorPool coreObjects list
        if self.operatorPool != 'None':
            self.operatorPool.coreObjectIds.append(self.id)
            self.operatorPool.coreObjects.append(self)
        # holds the Operator currently processing the Machine
        self.currentOperator = None
        # define if load/setup/removal/processing are performed by the operator
        self.operationType = operationType
        # boolean to check weather the machine is being operated
        self.toBeOperated = False

        # examine if there are multiple operation types performed by the operator
        #     there can be Setup/Processing operationType
        #     or the combination of both (MT-Load-Setup-Processing)
        self.multOperationTypeList = []
        if self.operationType.startswith("MT"):
            OTlist = operationType.split('-')
            self.operationType = OTlist.pop(0)
            self.multOperationTypeList = OTlist
        else:
            self.multOperationTypeList.append(self.operationType)
        #     lists to hold statistics of multiple runs
        self.WaitingForOperator = []
        self.WaitingForLoadOperator = []
        self.Loading = []
        self.SettingUp = []

    # =======================================================================
    # initialize the machine
    # =======================================================================
    def initialize(self):
        Machine.initialize(self)
        # initiate the Broker responsible to control the request/release
        # initialize the operator pool if any
        if (self.operatorPool != "None"):
            self.operatorPool.initialize()
            self.broker = Broker(self)
            activate(self.broker, self.broker.run())
            for operator in self.operatorPool.operators:
                operator.coreObjectIds.append(self.id)
                operator.coreObjects.append(self)
        # the time that the machine started/ended its wait for the operator
        self.timeWaitForOperatorStarted = 0
        self.timeWaitForOperatorEnded = 0
        self.totalTimeWaitingForOperator = 0
        # the time that the machine started/ended its wait for the operator
        self.timeWaitForLoadOperatorStarted = 0
        self.timeWaitForLoadOperatorEnded = 0
        self.totalTimeWaitingForLoadOperator = 0
        # the time that the operator started/ended loading the machine
        self.timeLoadStarted = 0
        self.timeLoadEnded = 0
        self.totalLoadTime = 0
        # the time that the operator started/ended setting-up the machine
        self.timeSetupStarted = 0
        self.timeSetupEnded = 0
        self.totalSetupTime = 0
        # Current entity load/setup/loadOperatorwait/operatorWait related times
        self.operatorWaitTimeCurrentEntity = 0  # holds the time that the machine was waiting for the operator
        self.loadOperatorWaitTimeCurrentEntity = 0  # holds the time that the machine waits for operator to load the it
        self.loadTimeCurrentEntity = 0  # holds the time to load the current entity
        self.setupTimeCurrentEntity = 0  # holds the time to setup the machine before processing the current entity

    # =======================================================================
    # the main process of the machine
    # =======================================================================
    def run(self):
        # execute all through simulation time
        while 1:
            # wait until the machine can accept an entity and one predecessor requests it
            # canAcceptAndIsRequested is invoked to check when the machine requested to receive an entity
            yield waituntil, self, self.canAcceptAndIsRequested

            # here or in the get entity (apart from the loatTimeCurrentEntity)
            # in case they are placed inside the getEntity then the initialize of
            # the corresponding variables should be moved to the initialize() of the CoreObject
            self.operatorWaitTimeCurrentEntity = 0
            self.loadOperatorWaitTimeCurrentEntity = 0
            self.loadTimeCurrentEntity = 0
            self.setupTimeCurrentEntity = 0

            # ======= request a resource
            if (self.operatorPool != "None") and any(
                    type == 'Load' for type in self.multOperationTypeList):
                # when it's ready to accept (canAcceptAndIsRequested) then inform the broker
                # machines waits to be operated (waits for the operator)
                self.requestOperator()
                self.timeWaitForLoadOperatorStarted = self.env.now
                # wait until the Broker has waited times equal to loadTime (if any)
                yield waituntil, self, self.broker.brokerIsSet
                self.timeWaitForLoadOperatorEnded = self.env.now
                self.loadOperatorWaitTimeCurrentEntity += self.timeWaitForLoadOperatorEnded - self.timeWaitForLoadOperatorStarted
                self.totalTimeWaitingForLoadOperator += self.loadOperatorWaitTimeCurrentEntity

    # ======= Load the machine if the Load is defined as one of the Operators' operation types
            if any(type == "Load" for type in
                   self.multOperationTypeList) and self.isOperated():
                self.timeLoadStarted = self.env.now
                yield hold, self, self.calculateLoadTime()
                # if self.interrupted(): There is the issue of failure during the Loading
                self.timeLoadEnded = self.env.now
                self.loadTimeCurrentEntity = self.timeLoadEnded - self.timeLoadStarted
                self.totalLoadTime += self.loadTimeCurrentEntity

    # ======= release a resource if the only operation type is Load
            if (self.operatorPool!="None")\
                 and any(type=="Load" for type in self.multOperationTypeList)\
                 and not any(type=="Processing" or type=="Setup" for type in self.multOperationTypeList)\
                 and self.isOperated():
                # after getting the entity release the operator
                # machine has to release the operator
                self.releaseOperator()
                # wait until the Broker has finished processing
                yield waituntil, self, self.broker.brokerIsSet

            # get the entity
            # if there was loading time then we must solve the problem of getting an entity
            # from an unidentified giver or not getting an entity at all as the giver
            # may fall in failure mode
            self.currentEntity = self.getEntity()

            # set the currentEntity as the Entity just received and initialize the timer timeLastEntityEntered
            self.nameLastEntityEntered = self.currentEntity.name  # this holds the name of the last entity that got into Machine
            self.timeLastEntityEntered = self.env.now  #this holds the last time that an entity got into Machine
            # variables dedicated to hold the processing times, the time when the Entity entered,
            # and the processing time left
            timeEntered = self.env.now  # timeEntered dummy Timer that holds the time the last Entity Entered

            # ======= request a resource if it is not already assigned an Operator
            if(self.operatorPool!="None")\
                 and any(type=="Processing" or type=="Setup" for type in self.multOperationTypeList)\
                 and not self.isOperated():
                # when it's ready to accept (canAcceptAndIsRequested) then inform the broker
                # machines waits to be operated (waits for the operator)
                self.requestOperator()
                self.timeWaitForOperatorStarted = self.env.now
                # wait until the Broker has waited times equal to loadTime (if any)
                yield waituntil, self, self.broker.brokerIsSet
                self.timeWaitForOperatorEnded = self.env.now
                self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted

            self.totalProcessingTimeInCurrentEntity = self.calculateProcessingTime(
            )  # get the processing time, tinMStarts holds the processing time of the machine
            tinM = self.totalProcessingTimeInCurrentEntity  # timer to hold the processing time left

            # ======= setup the machine if the Setup is defined as one of the Operators' operation types
            # in plantSim the setup is performed when the machine has to process a new type of Entity and only once
            if any(type == "Setup" for type in
                   self.multOperationTypeList) and self.isOperated():
                self.timeSetupStarted = self.env.now
                yield hold, self, self.calculateSetupTime()
                # if self.interrupted(): There is the issue of failure during the setup
                self.timeSetupEnded = self.env.now
                self.setupTimeCurrentEntity = self.timeSetupEnded - self.timeSetupStarted
                self.totalSetupTime += self.setupTimeCurrentEntity

    # ======= release a resource if the only operation type is Setup
            if (self.operatorPool!="None")\
                and self.isOperated()\
                and any(type=="Setup" or type=="Load" for type in self.multOperationTypeList)\
                and not any(type=="Processing" for type in self.multOperationTypeList):
                # after getting the entity release the operator
                # machine has to release the operator
                self.releaseOperator()
                #                 print self.objName, 'operator released', self.env.now
                # wait until the Broker has finished processing
                yield waituntil, self, self.broker.brokerIsSet

            # variables used to flag any interruptions and the end of the processing
            interruption = False
            processingEndedFlag = True
            # timers to follow up the failure time of the machine while on current Entity
            failureTime = 0  # dummy variable keeping track of the failure time
            # might be feasible to avoid it
            self.downTimeInCurrentEntity = 0  #holds the total time that the
            #object was down while holding current entity
            # this loop is repeated until the processing time is expired with no failure
            # check when the processingEndedFlag switched to false
            while processingEndedFlag:
                # tBefore : dummy variable to keep track of the time that the processing starts after
                #           every interruption
                tBefore = self.env.now
                # wait for the processing time left tinM, if no interruption occurs then change the
                # processingEndedFlag and exit loop,
                # else (if interrupted()) set interruption flag to true (only if tinM==0),
                # and recalculate the processing time left tinM,
                # passivate while waiting for repair.
                yield hold, self, tinM  # getting processed for remaining processing time tinM
                if self.interrupted(
                ):  # if a failure occurs while processing the machine is interrupted.
                    # output to trace that the Machine (self.objName) got interrupted
                    self.outputTrace(self.getActiveObjectQueue()[0].name,
                                     "Interrupted at " + self.objName)
                    # recalculate the processing time left tinM
                    tinM = tinM - (self.env.now - tBefore)
                    if (
                            tinM == 0
                    ):  # sometimes the failure may happen exactly at the time that the processing would finish
                        # this may produce disagreement with the simul8 because in both SimPy and Simul8
                        # it seems to be random which happens 1st
                        # this should not appear often to stochastic models though where times are random
                        interruption = True
                    # passivate the Machine for as long as there is no repair
                    # start counting the down time at breatTime dummy variable
                    breakTime = self.env.now  # dummy variable that the interruption happened

                    # =============== release the operator if there is failure
                    if (self.operatorPool!="None")\
                        and self.isOperated()\
                        and any(type=="Processing" for type in self.multOperationTypeList):
                        self.releaseOperator()
                        #                         print self.objName, 'operator released due to failure', self.env.now
                        yield waituntil, self, self.broker.brokerIsSet

                    # if there is a failure in the machine it is passivated
                    yield passivate, self
                    # use the timers to count the time that Machine is down and related
                    self.downTimeProcessingCurrentEntity += self.env.now - breakTime  # count the time that Machine is down while processing this Entity
                    self.downTimeInCurrentEntity += self.env.now - breakTime  # count the time that Machine is down while on currentEntity
                    self.timeLastFailureEnded = self.env.now  # set the timeLastFailureEnded
                    failureTime += self.env.now - breakTime  # dummy variable keeping track of the failure time
                    # output to trace that the Machine self.objName was passivated for the current failure time
                    self.outputTrace(
                        self.getActiveObjectQueue()[0].name, "passivated in " +
                        self.objName + " for " + str(self.env.now - breakTime))

                    # =============== request a resource after the repair
                    if (self.operatorPool!="None")\
                        and any(type=="Processing" for type in self.multOperationTypeList)\
                        and not interruption:
                        self.timeWaitForOperatorStarted = self.env.now
                        self.requestOperator()
                        yield waituntil, self, self.broker.brokerIsSet
                        self.timeWaitForOperatorEnded = self.env.now
                        self.operatorWaitTimeCurrentEntity += self.timeWaitForOperatorEnded - self.timeWaitForOperatorStarted

                # if no interruption occurred the processing in M1 is ended
                else:
                    processingEndedFlag = False
            # output to trace that the processing in the Machine self.objName ended
            self.outputTrace(self.getActiveObjectQueue()[0].name,
                             "ended processing in " + self.objName)

            # =============== release resource after the end of processing
            if (self.operatorPool!='None')\
                and any(type=="Processing" for type in self.multOperationTypeList)\
                and not interruption:
                self.releaseOperator()
                yield waituntil, self, self.broker.brokerIsSet

            # set the variable that flags an Entity is ready to be disposed
            self.waitToDispose = True
            # update the total working time
            self.totalWorkingTime += self.totalProcessingTimeInCurrentEntity  # the total processing time for this entity
            # is what the distribution initially gave

            # update the variables keeping track of Entity related attributes of the machine
            self.timeLastEntityEnded = self.env.now  # this holds the time that the last entity ended processing in Machine
            self.nameLastEntityEnded = self.currentEntity.name  # this holds the name of the last entity that ended processing in Machine
            self.completedJobs += 1  # Machine completed one more Job
            # re-initialize the downTimeProcessingCurrentEntity.
            # a new machine is about to enter
            self.downTimeProcessingCurrentEntity = 0

            # dummy variable requests the successor object now
            reqTime = self.env.now  # entity has ended processing in Machine and requests for the next object
            # initialize the timer downTimeInTryingToReleaseCurrentEntity, we have to count how much time
            # the Entity will wait for the next successor to be able to accept (canAccept)
            self.downTimeInTryingToReleaseCurrentEntity = 0

            while 1:
                # wait until the next Object is available or machine has failure
                yield waituntil, self, self.ifCanDisposeOrHaveFailure

                # if Next object available break
                if self.Up:
                    break
                # if M1 had failure, we want to wait until it is fixed and also count the failure time.
                else:
                    failTime = self.env.now  # dummy variable holding the time failure happened
                    # passivate until machine is up
                    yield waituntil, self, self.checkIfMachineIsUp
                    failureTime += self.env.now - failTime  # count the failure while on current entity time with failureTime variable
                    # calculate the time the Machine was down while trying to dispose the current Entity,
                    # and the total down time while on current Entity
                    self.downTimeInTryingToReleaseCurrentEntity += self.env.now - failTime
                    self.downTimeInCurrentEntity += self.env.now - failTime  # already updated from failures during processing
                    # update the timeLastFailureEnded
                    self.timeLastFailureEnded = self.env.now

            # dummy variable holding the total time the Entity spent in the Machine
            # count the time the Machine was blocked subtracting the failureTime
            #    and the processing time from the totalTime spent in the Machine
            self.totalTimeInCurrentEntity = self.env.now - timeEntered

    # =======================================================================
    # checks if the Machine can accept an entity
    # it checks also who called it and returns TRUE only to the predecessor
    # that will give the entity.
    # =======================================================================

    def canAccept(self, callerObject=None):
        # get active and giver objects
        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()
        giverObject = self.getGiverObject()

        # if we have only one predecessor just check if there is a place and the machine is up
        # this is done to achieve better (cpu) processing time
        # then we can also use it as a filter for a yield method
        if (len(activeObject.previous) == 1 or callerObject == None):
            if (activeObject.operatorPool != 'None'
                    and any(type == 'Load'
                            for type in activeObject.multOperationTypeList)):
                return activeObject.operatorPool.checkIfResourceIsAvailable()\
                        and activeObject.Up\
                        and len(activeObjectQueue)<activeObject.capacity
            else:
                return activeObject.Up and len(activeObjectQueue)<activeObject.capacity\

        thecaller = callerObject
        # return True ONLY if the length of the activeOjbectQue is smaller than
        # the object capacity, and the callerObject is not None but the giverObject
        if (activeObject.operatorPool != 'None'
                and any(type == 'Load'
                        for type in activeObject.multOperationTypeList)):
            return activeObject.operatorPool.checkIfResourceIsAvailable()\
                and activeObject.Up\
                and len(activeObjectQueue)<activeObject.capacity
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            return activeObject.Up and len(
                activeObjectQueue) < activeObject.capacity
            # while if the set up is performed before the (automatic) loading of the machine then the availability of the
            # operator is requested
#             return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\
#                and activeObject.Up and len(activeObjectQueue)<activeObject.capacity

# =======================================================================
# checks if the Machine can accept an entity and there is an entity in
# some possible giver waiting for it
# also updates the giver to the one that is to be taken
# =======================================================================

    def canAcceptAndIsRequested(self):
        # get active and giver objects
        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()
        giverObject = self.getGiverObject()
        # if we have only one predecessor just check if there is a place,
        # the machine is up and the predecessor has an entity to dispose
        # if the machine has to compete for an Operator that loads the entities onto it
        # check if the predecessor if blocked by an other Machine
        # if not then the machine has to block the predecessor giverObject to avoid conflicts
        # with other competing machines
        if (len(activeObject.previous) == 1):
            if (activeObject.operatorPool != 'None'
                    and any(type == 'Load'
                            for type in activeObject.multOperationTypeList)):
                if activeObject.operatorPool.checkIfResourceIsAvailable()\
                    and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
                    and giverObject.haveToDispose(activeObject) and not giverObject.exitIsAssigned():
                    activeObject.giver.assignExit()
                    return True
                else:
                    return False
            else:
                # the operator performs no load and the entity is received by the machine while there is
                # no need for operators presence. The operator needs to be present only where the load Type
                # operation is assigned
                return activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
                        and giverObject.haveToDispose(activeObject)
                # if the set-up performance needs be first performed before the transfer of the entity to
                # the machine then the presence of an operator to setup the machine before the getEntity()
                # is requested
#                 return (activeObject.operatorPool=='None'\
#                         or activeObject.operatorPool.checkIfResourceIsAvailable())\
#                         and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
#                         and giverObject.haveToDispose()

# dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject)
        isRequested = False  # is requested is dummyVariable checking if it is requested to accept an item
        maxTimeWaiting = 0  # dummy variable counting the time a predecessor is blocked

        # loop through the possible givers to see which have to dispose and which is the one blocked for longer
        for object in activeObject.previous:
            if (object.haveToDispose(activeObject)
                ):  # and not object.exitIsAssigned()):
                isRequested = True  # if the possible giver has entities to dispose of
                if (
                        object.downTimeInTryingToReleaseCurrentEntity > 0
                ):  # and the possible giver has been down while trying to give away the Entity
                    timeWaiting = self.env.now - object.timeLastFailureEnded  # the timeWaiting dummy variable counts the time end of the last failure of the giver object
                else:
                    timeWaiting = self.env.now - object.timeLastEntityEnded  # in any other case, it holds the time since the end of the Entity processing

                #if more than one possible givers have to dispose take the part from the one that is blocked longer
                if (timeWaiting >= maxTimeWaiting):
                    activeObject.giver = object  # set the giver
                    maxTimeWaiting = timeWaiting

        if (activeObject.operatorPool != 'None'
                and any(type == 'Load'
                        for type in activeObject.multOperationTypeList)):
            if activeObject.operatorPool.checkIfResourceIsAvailable()\
                and activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
                and isRequested and not activeObject.giver.exitIsAssigned():
                activeObject.giver.assignExit()
                return True
            else:
                return False
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            return activeObject.Up and len(
                activeObjectQueue) < activeObject.capacity and isRequested
            # while if the set up is performed before the (automatic) loading of the machine then the availability of the
            # operator is requested
#             return (activeObject.operatorPool=='None' or activeObject.operatorPool.checkIfResourceIsAvailable())\
#                 and activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested

# =======================================================================
#                       calculates the setup time
# =======================================================================

    def calculateSetupTime(self):
        return self.stpRng.generateNumber()

    # =======================================================================
    #                        calculates the Load time
    # =======================================================================
    def calculateLoadTime(self):
        return self.loadRng.generateNumber()

    # =======================================================================
    #                   prepare the machine to be operated
    # =======================================================================
    def requestOperator(self):
        self.broker.invokeBroker()
        self.toBeOperated = True

    # =======================================================================
    #                   prepare the machine to be released
    # =======================================================================
    def releaseOperator(self):
        self.broker.invokeBroker()
        self.toBeOperated = False

    # =======================================================================
    #       check if the machine is currently operated by an operator
    # =======================================================================
    def isOperated(self):
        return self.toBeOperated

    # =======================================================================
    #               check if the machine is already set-up
    # =======================================================================
    def isSetUp(self):
        return self.setUp

    # =======================================================================
    #          request that the machine is set-up by an operator
    # =======================================================================
    def requestSetup(self):
        self.setUp = False

    # =======================================================================
    # actions to be taken after the simulation ends
    # =======================================================================
    def postProcessing(self, MaxSimtime=None):
        if MaxSimtime == None:
            from Globals import G
            MaxSimtime = G.maxSimTime

        activeObject = self.getActiveObject()
        activeObjectQueue = self.getActiveObjectQueue()

        alreadyAdded = False  # a flag that shows if the blockage time has already been added

        # checks all the successors. If no one can accept an Entity then the machine might be blocked
        mightBeBlocked = True
        for nextObject in self.next:
            if nextObject.canAccept():
                mightBeBlocked = False

        # if there is an entity that finished processing in a Machine but did not get to reach
        # the following Object till the end of simulation,
        # we have to add this blockage to the percentage of blockage in Machine
        # we should exclude the failure time in current entity though!
        # if (len(self.Res.activeQ)>0) and (len(self.next[0].Res.activeQ)>0) and ((self.nameLastEntityEntered == self.nameLastEntityEnded)):
        if (len(activeObjectQueue)>0) and (mightBeBlocked)\
             and ((activeObject.nameLastEntityEntered == activeObject.nameLastEntityEnded)):
            # be careful here, might have to reconsider
            activeObject.totalBlockageTime += self.env.now - (
                activeObject.timeLastEntityEnded +
                activeObject.downTimeInTryingToReleaseCurrentEntity)
            if activeObject.Up == False:
                activeObject.totalBlockageTime -= self.env.now - activeObject.timeLastFailure
                alreadyAdded = True

        #if Machine is currently processing an entity we should count this working time
        if(len(activeObject.getActiveObjectQueue())>0)\
            and (not (activeObject.nameLastEntityEnded==activeObject.nameLastEntityEntered))\
            and (not (activeObject.operationType=='Processing' and (activeObject.currentOperator==None))):
            #if Machine is down we should add this last failure time to the time that it has been down in current entity
            if self.Up == False:
                #             if(len(activeObjectQueue)>0) and (self.Up==False):
                activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure
            activeObject.totalWorkingTime+=self.env.now-activeObject.timeLastEntityEntered\
                                                -activeObject.downTimeProcessingCurrentEntity\
                                                -activeObject.operatorWaitTimeCurrentEntity\
                                                -activeObject.setupTimeCurrentEntity
            activeObject.totalTimeWaitingForOperator += activeObject.operatorWaitTimeCurrentEntity
        elif(len(activeObject.getActiveObjectQueue())>0)\
            and (not (activeObject.nameLastEntityEnded==activeObject.nameLastEntityEntered))\
            and (activeObject.currentOperator==None):
            # needs further research as the time of failure while waiting for operator is not counted yet
            if self.Up == False:
                activeObject.downTimeProcessingCurrentEntity += self.env.now - activeObject.timeLastFailure
            activeObject.totalTimeWaitingForOperator+=self.env.now-activeObject.timeWaitForOperatorStarted\
                                                           -activeObject.downTimeProcessingCurrentEntity

        # if Machine is down we have to add this failure time to its total failure time
        # we also need to add the last blocking time to total blockage time
        if (activeObject.Up == False):
            activeObject.totalFailureTime += self.env.now - activeObject.timeLastFailure
            # we add the value only if it hasn't already been added
            #if((len(self.next[0].Res.activeQ)>0) and (self.nameLastEntityEnded==self.nameLastEntityEntered) and (not alreadyAdded)):
            if ((mightBeBlocked) and (activeObject.nameLastEntityEnded
                                      == activeObject.nameLastEntityEntered)
                    and (not alreadyAdded)):
                activeObject.totalBlockageTime += (
                    self.env.now - activeObject.timeLastEntityEnded) - (
                        self.env.now - activeObject.timeLastFailure
                    ) - activeObject.downTimeInTryingToReleaseCurrentEntity

        #Machine was idle when it was not in any other state
        activeObject.totalWaitingTime = MaxSimtime - activeObject.totalWorkingTime - activeObject.totalBlockageTime - activeObject.totalFailureTime

        if activeObject.totalBlockageTime < 0 and activeObject.totalBlockageTime > -0.00001:  #to avoid some effects of getting negative cause of rounding precision
            self.totalBlockageTime = 0

        if activeObject.totalWaitingTime < 0 and activeObject.totalWaitingTime > -0.00001:  #to avoid some effects of getting negative cause of rounding precision
            self.totalWaitingTime = 0

        activeObject.Failure.append(100 * self.totalFailureTime / MaxSimtime)
        activeObject.Blockage.append(100 * self.totalBlockageTime / MaxSimtime)
        activeObject.Waiting.append(100 * self.totalWaitingTime / MaxSimtime)
        activeObject.Working.append(100 * self.totalWorkingTime / MaxSimtime)
        activeObject.WaitingForOperator.append(
            100 * self.totalTimeWaitingForOperator / MaxSimtime)
        activeObject.WaitingForLoadOperator.append(
            100 * self.totalTimeWaitingForLoadOperator / MaxSimtime)
        activeObject.Loading.append(100 * self.totalLoadTime / MaxSimtime)
        activeObject.SettingUp.append(100 * self.totalSetupTime / MaxSimtime)
Ejemplo n.º 8
0
class MachineManagedJob(MachineJobShop):

    # =======================================================================
    # initialise the MachineManagedJob
    # =======================================================================
    def initialize(self):
        MachineJobShop.initialize(self)
        self.type="MachineManagedJob"
        #create an empty Operator Pool. This will be updated by canAcceptAndIsRequested
        id = self.id+'_OP'
        name=self.objName+'_operatorPool'
        self.operatorPool=OperatorPool(id, name, operatorsList=[])
        self.operatorPool.initialize()
        self.operatorPool.operators=[]
        #create a Broker
        self.broker = Broker(self)
        activate(self.broker,self.broker.run())
        #create a Router
        from Globals import G
        if len(G.RoutersList)==0:
            self.router=Router()
            activate(self.router,self.router.run())
            G.RoutersList.append(self.router)
        # otherwise set the already existing router as the machines Router
        else:
            self.router=G.RoutersList[0]
        # holds the Entity that is to be obtained and will be updated by canAcceptAndIsRequested
        self.entityToGet=None

        
    # =======================================================================
    # checks if the Queue can accept an entity       
    # it checks also the next station of the Entity 
    # and returns true only if the active object is the next station
    # ======================================================================= 
    def canAccept(self, callerObject=None):
        activeObject=self.getActiveObject()
        activeObjectQueue=activeObject.getActiveObjectQueue()
        thecaller=callerObject
        if (thecaller!=None):
            #check it the caller object holds an Entity that requests for current object
            if len(thecaller.getActiveObjectQueue())>0:
                # TODO: make sure that the first entity of the callerObject is to be disposed
                activeEntity=thecaller.getActiveObjectQueue()[0]
                # if the machine's Id is in the list of the entity's next stations
                if activeObject.id in activeEntity.remainingRoute[0].get('stationIdsList',[]):
                    #return according to the state of the Queue
                    return len(activeObject.getActiveObjectQueue())<activeObject.capacity\
                        and activeObject.Up
        return False

    # =======================================================================
    # checks if the Machine can accept an entity and there is an entity in 
    # some possible giver waiting for it
    # also updates the giver to the one that is to be taken
    # =======================================================================
    def canAcceptAndIsRequested(self):
        # get active and giver objects
        activeObject=self.getActiveObject()
        activeObjectQueue=self.getActiveObjectQueue()
        giverObject=self.getGiverObject()
    
        # dummy variables that help prioritise the objects requesting to give objects to the Machine (activeObject)
        isRequested=False                                           # is requested is dummyVariable checking if it is requested to accept an item
        maxTimeWaiting=0                                            # dummy variable counting the time a predecessor is blocked
        
        # loop through the possible givers to see which have to dispose and which is the one blocked for longer
        for object in activeObject.previous:
            if(object.haveToDispose(activeObject) and object.receiver==self):# and not object.exitIsAssigned()):
                isRequested=True                                    # if the possible giver has entities to dispose of
                if(object.downTimeInTryingToReleaseCurrentEntity>0):# and the possible giver has been down while trying to give away the Entity
                    timeWaiting=now()-object.timeLastFailureEnded   # the timeWaiting dummy variable counts the time end of the last failure of the giver object
                else:
                    timeWaiting=now()-object.timeLastEntityEnded    # in any other case, it holds the time since the end of the Entity processing
                
                #if more than one possible givers have to dispose take the part from the one that is blocked longer
                if(timeWaiting>=maxTimeWaiting): 
                    activeObject.giver=object                 # set the giver
                    maxTimeWaiting=timeWaiting    
        
        if (activeObject.operatorPool!='None' and (any(type=='Load' for type in activeObject.multOperationTypeList)\
                                                or any(type=='Setup' for type in activeObject.multOperationTypeList))):
            if isRequested:
                # TODO:  check whether this entity is the one to be hand in
                #     to be used in operatorPreemptive
                activeObject.requestingEntity=activeObject.giver.getActiveObjectQueue()[0]
                # TODO:  update the object requesting the operator
                activeObject.operatorPool.requestingObject=activeObject.giver
                # TODO:  update the last object calling the operatorPool
                activeObject.operatorPool.receivingObject=activeObject
                              
                if activeObject.Up and len(activeObjectQueue)<activeObject.capacity\
                    and self.checkOperator()\
                    and not activeObject.giver.exitIsAssigned():
                    activeObject.giver.assignExit()
                    # if the activeObject is not in manager's activeCallersList of the entityToGet
                    if self not in activeObject.giver.getActiveObjectQueue()[0].manager.activeCallersList:
                        # append it to the activeCallerList of the manager of the entity to be received
                        activeObject.giver.getActiveObjectQueue()[0].manager.activeCallersList.append(self)
                        # update entityToGet
                        self.entityToGet=activeObject.giver.getActiveObjectQueue()[0]
                    #make the operators List so that it holds only the manager of the current order
                    activeObject.operatorPool.operators=[activeObject.giver.getActiveObjectQueue()[0].manager]
#                     # set the variable operatorAssignedTo to activeObject, the operator is then blocked
#                     activeObject.operatorPool.operators[0].operatorAssignedTo=activeObject
#                     # TESTING
#                     print now(), activeObject.operatorPool.operators[0].objName, 'got assigned to', activeObject.id
                    # read the load time of the machine
                    self.readLoadTime()
                    return True
            else:
                return False
        else:
            # the operator doesn't have to be present for the loading of the machine as the load operation
            # is not assigned to operators
            if activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested:
                # update entityToGet
                self.entityToGet=self.giver.getActiveObjectQueue()[0]
            return activeObject.Up and len(activeObjectQueue)<activeObject.capacity and isRequested 

    # =======================================================================
    # to be called by canAcceptAndIsRequested and check for the operator
    # =======================================================================    
    def checkOperator(self):
        if self.giver.getActiveObjectQueue()[0].manager:
            manager=self.giver.getActiveObjectQueue()[0].manager
#             print ''
#             print 'Entity',self.giver.getActiveObjectQueue()[0].id
#             print 'manager',manager.id
            return manager.checkIfResourceIsAvailable()
        else:
            return True    
        
    # =======================================================================
    #             identifies the Entity to be obtained so that 
    #            getEntity gives it to removeEntity as argument
    # =======================================================================    
    def identifyEntityToGet(self):
        # ToDecide
        # maybe we should work this way in all CoreObjects???
        return self.entityToGet
    
    # =======================================================================
    # checks if the object is ready to receive an Entity
    # =======================================================================    
    def isReadyToGet(self):
        # check if the entity that is about to be obtained has a manager (this should be true for this object)
        if self.entityToGet.manager:
            manager=self.entityToGet.manager
            if len(manager.activeCallersList)>0:
                manager.sortEntities()      # sort the callers of the manager to be used for scheduling rules
                # return true if the manager is available
                return manager.checkIfResourceIsAvailable()
        else:
            return True
        

    # =======================================================================
    #                   prepare the machine to be released
    # =======================================================================
    def releaseOperator(self):
        self.outputTrace(self.currentOperator.objName, "released from "+ self.objName)
#         # TESTING
#         print now(), self.id, 'will release operator', self.operatorPool.operators[0].objName
        # set the flag operatorAssignedTo to None
        self.operatorPool.operators[0].operatorAssignedTo=None
        self.broker.invokeBroker()
        self.toBeOperated = False