Router now handles all operator assignement. Need to simplified and commented properly

parent 5b91c6cd
...@@ -25,7 +25,8 @@ Created on 19 Feb 2013 ...@@ -25,7 +25,8 @@ Created on 19 Feb 2013
''' '''
Models an Interruption that schedules the operation of the machines by different managers Models an Interruption that schedules the operation of the machines by different managers
''' '''
from SimPy.Globals import sim
from SimPy.Simulation import Simulation
from SimPy.Simulation import Process, Resource, SimEvent from SimPy.Simulation import Process, Resource, SimEvent
from ObjectInterruption import ObjectInterruption from ObjectInterruption import ObjectInterruption
from SimPy.Simulation import waituntil, now, hold, request, release, waitevent from SimPy.Simulation import waituntil, now, hold, request, release, waitevent
...@@ -47,7 +48,7 @@ class Router(ObjectInterruption): ...@@ -47,7 +48,7 @@ class Router(ObjectInterruption):
ObjectInterruption.__init__(self) ObjectInterruption.__init__(self)
self.type = "Router" self.type = "Router"
# signal used to initiate the generator of the Router # signal used to initiate the generator of the Router
self.startCycle=SimEvent('startCycle') self.isCalled=SimEvent('RouterIsCalled')
self.isInitialized=False self.isInitialized=False
self.candidateOperators=[] self.candidateOperators=[]
self.multipleCriterionList=[] self.multipleCriterionList=[]
...@@ -55,6 +56,12 @@ class Router(ObjectInterruption): ...@@ -55,6 +56,12 @@ class Router(ObjectInterruption):
# boolean flag to check whether the Router should perform sorting on operators and on pendingEntities # boolean flag to check whether the Router should perform sorting on operators and on pendingEntities
self.sorting=sorting self.sorting=sorting
self.conflictingOperators=[] self.conflictingOperators=[]
# list of objects to be signalled by the Router
self.toBeSignalled=[]
# flag to notify whether the router is already invoked
self.invoked=False
# flag to notify whether the router is dealing with managed or simple entities
self.managed=False
#=========================================================================== #===========================================================================
# the initialize method # the initialize method
...@@ -73,6 +80,9 @@ class Router(ObjectInterruption): ...@@ -73,6 +80,9 @@ class Router(ObjectInterruption):
# flag used to check if the Router is initialised # flag used to check if the Router is initialised
self.isInitialized=True self.isInitialized=True
self.conflictingOperators=[] self.conflictingOperators=[]
self.toBeSignalled=[]
self.invoked=False
self.managed=False
# ======================================================================= # =======================================================================
# the run method # the run method
...@@ -84,182 +94,118 @@ class Router(ObjectInterruption): ...@@ -84,182 +94,118 @@ class Router(ObjectInterruption):
returns canAcceptAndIsRequested (inPositionToGet is True) returns canAcceptAndIsRequested (inPositionToGet is True)
''' '''
def run(self): def run(self):
from Globals import G, findObjectById from Globals import G
# find out whether we are dealing with managed entities
if G.EntityList:
for entity in G.EntityList:
if entity.manager:
self.managed=True
break
while 1: while 1:
# wait until the router is called # wait until the router is called
yield waitevent, self, self.startCycle yield waitevent, self, self.isCalled
self.victim=findObjectById(self.startCycle.signalparam) # print '=-'*15
# yield waituntil,self,self.isCalled # print 'router received event'
# when the router is called for the first time wait till all the entities # wait till there are no more events, the machines must be blocked
# finished all their moves in stations of non-Machine-type while 1:
# before they can enter again a type-Machine object # print Simulation.allEventNotices(sim)
yield waituntil, self,self.entitiesFinishedMoving if now() in Simulation.allEventTimes(sim):
# update the objects to be served list (pendingObjects) # print 'there are MORE events for now'
self.pendingObjects=[object for object in G.MachineList if object.inPositionToGet] yield hold, self, 0
else:
#=================================================================== # print 'there are NO more events for now'
# # TESTING break
# print now(), '================================================================================' # print '=-'*15
# print ' the pending objects are ', [str(object.id) for object in self.pendingObjects] # after the events are over, assign the operators to machines for loading or simple processing
#=================================================================== # read the pendingEntities currentStations, these are the stations (queues) that may be signalled
# the activeCallers list is updated each time the canAcceptAndIsRequested returns true even if the machine is not signalled
# update the calledOperators list
self.calledOperators=[operator for operator in G.OperatorsList if len(operator.activeCallersList)] # find the pending objects
self.findPendingObjects()
#=================================================================== # find the pending entities
# # TESTING self.findPendingEntities()
# print ' (calledOperators, activeCallers, callerEntities): ', [(str(operator.id),\ # find the operators that can start working now
# [str(x.id) for x in operator.activeCallersList],\
# [str(x.giver.getActiveObjectQueue()[0].id)for x in operator.activeCallersList])\
# for operator in self.calledOperators]
#===================================================================
# find the operators that can start working now even if they are not called
self.findCandidateOperators() self.findCandidateOperators()
#===================================================================
# # TESTING
# print ' {} the candidateOperators ',
# print [str(op.id) for op in self.candidateOperators]
# print [str(entity.id) for entity in G.pendingEntities]
#===================================================================
# sort the pendingEntities list # sort the pendingEntities list
if self.sorting: if self.sorting:
self.sortPendingEntities() self.sortPendingEntities()
#===================================================================
# # TESTING
# print [str(entity.id) for entity in G.pendingEntities]
# if G.pendingEntities:
# print ' {} the pending entities that can proceed are: ',
# print [str(entity.id) for entity in G.pendingEntities if entity.canProceed]
#===================================================================
# find the operators candidateEntities # find the operators candidateEntities
self.findCandidateEntities() self.findCandidateEntities()
#===================================================================
# # TESTING
# print ' {} candidate entities for each candidateOperator ',
# print [(str(operator.id),[str(candidateEntity.id) for candidateEntity in operator.candidateEntities],)\
# for operator in self.candidateOperators]
#===================================================================
# find the entity that will occupy the resource, and the station that will receive it (if any available) # find the entity that will occupy the resource, and the station that will receive it (if any available)
# entities that are already in stations have already a receiver
self.findCandidateReceivers() self.findCandidateReceivers()
# assign operators to stations
self.assignOperators()
# if an exit of an object is assigned to one station, while the operator to operate
# the moving entity is assigned to a different, unAssign the exit
#------------------------------------------------------------------------------
if not self.managed:
for operator in [x for x in self.candidateOperators if x.isAssignedTo()]:
if not operator.isAssignedTo() in self.pendingObjects:
for object in [x for x in operator.isAssignedTo().previous if x.exitIsAssignedTo()]:
if object.exitIsAssignedTo()!=operator.isAssignedTo():
object.unAssignExit()
#------------------------------------------------------------------------------
else:
for operator in [x for x in self.candidateOperators if x.isAssignedTo()]:
if not operator.isAssignedTo() in self.pendingObjects:
if operator.candidateEntity.currentStation.exitIsAssignedTo():
if operator.isAssignedTo()!=operator.candidateEntity.currentStation.exitIsAssignedTo():
operator.candidateEntity.currentStation.unAssignExit()
# if an object cannot proceed with getEntity, unAssign the exit of its giver
for object in self.pendingQueues:
if not object in self.toBeSignalled:
object.unAssignExit()
# signal the stations that ought to be signalled
self.signalOperatedStations()
#=================================================================== #===================================================================
# # TESTING # # testing
# print ' {} (candidateOperator, candidateEntity, candidateReceiver) ', # print 'router exiting'
# print [(str(op.id), str(op.candidateEntity.id), str(op.candidateEntity.candidateReceiver.id))\ # print '=-'*20
# for op in self.candidateOperators if op.candidateEntity.candidateReceiver]
#=================================================================== #===================================================================
self.exit()
# sort the givers for the operators that will process the entities #===========================================================================
self.sortGiverQueue() # assigning operators to machines
#===========================================================================
def assignOperators(self):
#------------------------------------------------------------------------------
# for all the operators that are requested # for all the operators that are requested
for operator in self.calledOperators: for operator in self.candidateOperators:
priorityObject=None
# check if the candidateReceivers are inPositionToGet and if they are already called
try:
receiverIsActive=(operator.candidateEntity.candidateReceiver in operator.activeCallersList\
and operator.candidateEntity.candidateReceiver in self.pendingObjects )
except:
receiverIsActive=True
#===============================================================
# # TESTING
# print ' calledOperator', operator.id,
# print 'will receive?',operator.checkIfResourceIsAvailable() and receiverIsActive
#===============================================================
# check if the candidateOperators are available, if the are requested and reside in the pendingObjects list # check if the candidateOperators are available, if the are requested and reside in the pendingObjects list
if operator.checkIfResourceIsAvailable() and \ if operator.checkIfResourceIsAvailable():
receiverIsActive: # if the router deals with managed entities
# sort the activeCallersList of the operator #------------------------------------------------------------------------------
operator.sortActiveCallers() if not self.managed:
# find the activeCaller that has priority # if the operator is not conflicting
priorityObject=next(x for x in operator.activeCallersList if x in self.pendingObjects) if not operator in self.conflictingOperators:
# assign an operator to the priorityObject
#=========================================================== #=======================================================
# # TESTING # # testing
# print [str(caller.id) for caller in operator.activeCallersList] # print 'router will assign', operator.id, 'to', operator.candidateStation.id
# print ' the PRIORITY object is', priorityObject.id #=======================================================
#=========================================================== operator.assignTo(operator.candidateStation)
self.toBeSignalled.append(operator.candidateStation)
#------------------------------------------------------------------------------
else:
# and if the priorityObject is indeed pending # and if the priorityObject is indeed pending
if priorityObject in self.pendingObjects: if (operator.candidateEntity.currentStation in self.pendingObjects) and (not operator in self.conflictingOperators):
# assign an operator to the priorityObject # assign an operator to the priorityObject
operator.operatorAssignedTo=priorityObject
#======================================================= #=======================================================
# # TESTING # # testing
# print operator.id, 'got assigned to', priorityObject.id # print 'router will assign', operator.id, 'to', operator.candidateEntity.candidateReceiver.id
#======================================================= #=======================================================
operator.assignTo(operator.candidateEntity.candidateReceiver)
# and let it proceed withGetEntity self.toBeSignalled.append(operator.candidateEntity.currentStation)
priorityObject.canProceedWithGetEntity=True
priorityObject.inPositionToGet=False
# if the are not called and they are not in the pendingObjects list clear their activeCallersList
elif not receiverIsActive:
operator.activeCallersList=[]
# if an object cannot proceed with getEntity, unAssign the exit of its giver
for object in self.pendingObjects:
if not object.canProceedWithGetEntity:
object.giver.unAssignExit()
#=================================================================== #===================================================================
# # TESTING # # testing
# print ' these objects will proceed with getting entities', # print 'router found objects to be signalled'
# print [str(object.id) for object in self.pendingObjects if object.canProceedWithGetEntity] # print [str(object.id) for object in self.toBeSignalled]
# print [str(object.exitIsAssignedTo().id) for object in self.toBeSignalled if object.exitIsAssignedTo()]
#=================================================================== #===================================================================
self.exit()
#===========================================================================
# have the entities that have ended their processing when the router
# got first called finished their moves through queues?
#===========================================================================
def entitiesFinishedMoving(self):
# check if the entities waiting to be disposed from different Machines
# the first time the Router is called, have reached the last queue (if any)
# before the next Machine in their route
from Globals import G
# pending entities are entities about to enter an other machine, updated by endProcessingActions()
# if there are any pending entities
if len(G.pendingEntities):
# local variable
allEntitiesMoved=False
# for each one of them
for entity in G.pendingEntities:
# if they are residing in a machine which waits to dispose and is functional
if entity.currentStation in G.MachineList:
if entity.currentStation.checkIfMachineIsUp()\
and entity.currentStation.waitToDispose:
# if the next step in the entity's route is machine with Load operationType then continue
if (not (entity.currentStation.receiver in G.MachineList)\
and entity.currentStation.receiver.canAccept()\
or\
((entity.currentStation.receiver.type in G.MachineList)\
and not any(type=='Load' for type in entity.currentStation.receiver.multOperationTypeList))):
return False
# if the entity is in a Queue
elif entity.currentStation in G.QueueList:
# if the hot flag of the entity is raised
if entity.hot:
allEntitiesMoved=True
# return True
else:
return False
elif entity.currentStation in G.OrderDecompositionList:
return False
# TODO: this list can check all the available object in G.objList
# if no entity returned False then return True
if allEntitiesMoved:
return True
return True
# ======================================================================= # =======================================================================
# return control to the Machine.run # return control to the Machine.run
# ======================================================================= # =======================================================================
...@@ -268,49 +214,126 @@ class Router(ObjectInterruption): ...@@ -268,49 +214,126 @@ class Router(ObjectInterruption):
# reset the variables that are used from the Router # reset the variables that are used from the Router
for operator in self.candidateOperators: for operator in self.candidateOperators:
operator.candidateEntities=[] operator.candidateEntities=[]
operator.candidateStations=[]
operator.candidateStation=None
operator.candidateEntity=None operator.candidateEntity=None
for entity in G.pendingEntities: for entity in G.pendingEntities:
entity.canProceed=False entity.canProceed=False
entity.candidateReceivers=[] entity.candidateReceivers=[]
entity.candidateReceiver=None entity.candidateReceiver=None
del self.candidateOperators[:] del self.candidateOperators[:]
del self.calledOperators[:]
del self.pendingObjects[:] del self.pendingObjects[:]
del self.pendingMachines[:]
del self.pendingQueues[:]
del self.toBeSignalled[:]
del self.multipleCriterionList[:] del self.multipleCriterionList[:]
del self.conflictingOperators[:] del self.conflictingOperators[:]
self.schedulingRule='WT' self.schedulingRule='WT'
self.invoked=False
ObjectInterruption.exit(self)
# self.victim.routerCycleOver.signal('router has implemented its logic')
#===========================================================================
# signal stations that wait for load operators
#===========================================================================
def signalOperatedStations(self):
# print 'router trying to signal pendingObjects'
from Globals import G
for operator in self.candidateOperators:
station=operator.isAssignedTo()
if station:
# if the router deals with simple entities
#------------------------------------------------------------------------------
if not self.managed:
assert station in self.toBeSignalled, 'the station must be in toBeSignalled list'
if station.broker.waitForOperator:
# signal this station's broker that the resource is available
#===========================================================
# # testing
# print now(), 'router signalling broker of', operator.isAssignedTo().id
#===========================================================
station.broker.resourceAvailable.signal(now())
else:
# signal the queue proceeding the station
if station.canAccept()\
and any(type=='Load' for type in station.multOperationTypeList):
#=======================================================
# # testing
# print now(), 'router signalling', operator.isAssignedTo().id
#=======================================================
station.loadOperatorAvailable.signal(now())
# in case the router deals with managed entities
#------------------------------------------------------------------------------
else:
if station in self.pendingMachines and station in self.toBeSignalled:
# signal this station's broker that the resource is available
#===========================================================
# # testing
# print now(), 'router signalling broker of', operator.isAssignedTo().id
#===========================================================
operator.isAssignedTo().broker.resourceAvailable.signal(now())
elif (not station in self.pendingMachines) or (not station in self.toBeSignalled):
# signal the queue proceeding the station
assert operator.candidateEntity.currentStation in self.toBeSignalled, 'the candidateEntity currentStation is not picked by the Router'
assert operator.candidateEntity.currentStation in G.QueueList, 'the candidateEntity currentStation to receive signal from Router is not a queue'
if operator.candidateEntity.candidateReceiver.canAccept()\
and any(type=='Load' for type in operator.candidateEntity.candidateReceiver.multOperationTypeList):
#=======================================================
# # testing
# print now(), 'router signalling queue', operator.candidateEntity.currentStation.id
#=======================================================
operator.candidateEntity.currentStation.loadOperatorAvailable.signal(now())
#===========================================================================
# clear the pending lists of the router
#===========================================================================
def clearPending(self):
self.pendingQueues=[]
self.pendingMachines=[]
self.pendingObjects=[]
#===========================================================================
# find the stations that can be signalled by the router
#===========================================================================
def findPendingObjects(self):
from Globals import G
self.clearPending()
for entity in G.pendingEntities:
for machine in entity.currentStation.next:
if any(type=='Load' for type in machine.multOperationTypeList):
self.pendingQueues.append(entity.currentStation)
self.pendingObjects.append(entity.currentStation)
break
self.pendingMachines=[machine for machine in G.MachineList if machine.broker.waitForOperator]
self.pendingObjects=self.pendingQueues+self.pendingMachines
#======================================================================= #=======================================================================
# Sort pendingEntities # # testing
# TODO: sorting them according to the operators schedulingRule # print 'router found pending objects'
# print [object.id for object in self.pendingObjects]
#======================================================================= #=======================================================================
def sortPendingEntities(self):
# TODO: to be used for sorting of operators
# there must be also a schedulingRule property for the Router
# there must also be a way to have multiple criteria for the operators (eg MC-Priority-WT)
# WT may be needed to be applied everywhere
# TODO: move that piece of code elsewhere, it doesn't look nice here. and there is not point in doing it here
# maybe it's better in findCandidateOperators method
if self.candidateOperators:
from Globals import G
candidateList=G.pendingEntities
self.activeQSorter(criterion=self.schedulingRule,candList=candidateList)
#===========================================================================
# finding the entities that require manager now
#===========================================================================
def findPendingEntities(self):
from Globals import G
self.pending=[] # list of entities that are pending
for machine in self.pendingMachines:
self.pending.append(machine.currentEntity)
for entity in G.pendingEntities:
for machine in entity.currentStation.next:
if any(type=='Load' for type in machine.multOperationTypeList):
self.pending.append(entity)
break
# find out which type of entities are we dealing with, managed entities or not
if self.pending:
if self.pending[0].manager:
self.managed=True
#======================================================================= #=======================================================================
# Sort candidateOperators # # testing
# TODO: consider if there must be an argument set for the schedulingRules of the Router # print 'found pending entities'
# TODO: consider if the scheduling rule for the operators must be global for all of them # print [entity.id for entity in self.pending if not entity.type=='Part']
#======================================================================= #=======================================================================
def sortOperators(self):
# TODO: there must be criteria for sorting the cadidateOperators
#if we have sorting according to multiple criteria we have to call the sorter many times
# TODO: find out what happens in case of multiple criteria
if self.candidateOperators:
candidateList=self.candidateOperators
self.activeQSorter(criterion=self.schedulingRule,candList=candidateList)
#======================================================================== #========================================================================
# Find candidate Operators # Find candidate Operators
...@@ -321,13 +344,40 @@ class Router(ObjectInterruption): ...@@ -321,13 +344,40 @@ class Router(ObjectInterruption):
# . the candidate receivers of the entities (the stations the operators will be working at) # . the candidate receivers of the entities (the stations the operators will be working at)
#======================================================================== #========================================================================
def findCandidateOperators(self): def findCandidateOperators(self):
#TODO: here check the case of no managed entities (normal machines)
from Globals import G from Globals import G
# if we are not dealing with managed entities
#------------------------------------------------------------------------------
if not self.managed:
# if there are pendingEntities
if self.pendingObjects:
for object in self.pendingObjects:
if object in self.pendingMachines:
if object.operatorPool.checkIfResourceIsAvailable():
candidateOperator=object.operatorPool.findAvailableOperator()
# TODO: this way no sorting is performed
if not candidateOperator in self.candidateOperators:
self.candidateOperators.append(candidateOperator)
candidateOperator.candidateStations.append(object)
elif object in self.pendingQueues:
for nextobject in object.next:
if nextobject.canAccept(object):
candidateOperator=nextobject.operatorPool.findAvailableOperator()
if not candidateOperator in self.candidateOperators:
self.candidateOperators.append(candidateOperator)
candidateOperator.candidateStations.append(object)
# update the schedulingRule/multipleCriterionList of the Router
if self.sorting:
self.updateSchedulingRule()
# in case the router deals with managed entities
#------------------------------------------------------------------------------
else:
# if there are pendingEntities # if there are pendingEntities
if len(G.pendingEntities): if len(self.pending):
# for those pending entities that require a manager (MachineManagedJob case) # for those pending entities that require a manager (MachineManagedJob case)
for entity in [x for x in G.pendingEntities if x.manager]: for entity in [x for x in self.pending if x.manager]:
# if the entity is ready to move to a machine and its manager is available # if the entity is ready to move to a machine and its manager is available
if entity.hot and entity.manager.checkIfResourceIsAvailable(): if entity.manager.checkIfResourceIsAvailable():
# for entities of type OrderComponent, if they reside at a conditionalBuffer, # for entities of type OrderComponent, if they reside at a conditionalBuffer,
# they must wait till their basicsEnded flag is raised # they must wait till their basicsEnded flag is raised
if entity.type=='OrderComponent': if entity.type=='OrderComponent':
...@@ -345,13 +395,20 @@ class Router(ObjectInterruption): ...@@ -345,13 +395,20 @@ class Router(ObjectInterruption):
for nextObject in [object for object in entity.currentStation.next if object.canAcceptEntity(entity)]: for nextObject in [object for object in entity.currentStation.next if object.canAcceptEntity(entity)]:
entity.canProceed=True entity.canProceed=True
entity.candidateReceivers.append(nextObject) entity.candidateReceivers.append(nextObject)
# if the entity is in a machines who's broker waits for operator then
if entity.currentStation in self.pendingMachines:
entity.canProceed=True
# if the entity can proceed, add its manager to the candidateOperators list # if the entity can proceed, add its manager to the candidateOperators list
if entity.canProceed and not entity.manager in self.candidateOperators: if entity.canProceed and not entity.manager in self.candidateOperators:
self.candidateOperators.append(entity.manager) self.candidateOperators.append(entity.manager)
# update the schedulingRule/multipleCriterionList of the Router # update the schedulingRule/multipleCriterionList of the Router
if self.sorting: if self.sorting:
self.updateSchedulingRule() self.updateSchedulingRule()
#=======================================================================
# # testing
# print 'router found candidate operators'
# print [operator.id for operator in self.candidateOperators]
#=======================================================================
#======================================================================= #=======================================================================
# find the schedulingRules of the candidateOperators # find the schedulingRules of the candidateOperators
...@@ -380,6 +437,39 @@ class Router(ObjectInterruption): ...@@ -380,6 +437,39 @@ class Router(ObjectInterruption):
#======================================================================= #=======================================================================
def findCandidateEntities(self): def findCandidateEntities(self):
from Globals import G from Globals import G
# if the moving entities are not managed
#------------------------------------------------------------------------------
if not self.managed:
# TODO: the operator finds no entities in this case
# initialise operatorsWithOneCandidateStation lists
operatorsWithOneCandidateStation=[]
# for all the candidateOperators
for operator in self.candidateOperators:
# sort the candidate operators so that those who have only one option be served first
if len(operator.candidateStations)==1:
operatorsWithOneCandidateStation.append(operator)
# TODO: the operator here actually chooses entity. This may pose a problem as two entities may be equivalent
# and as the operators chooses the sorting of the queue (if they do reside in the same queue is not taken into account)
# sort the candidateEntities list of each operator according to its schedulingRule
# TODO: rename the sorting method, the simple operator is not sorting entities but candidateStations
for operator in [x for x in self.candidateOperators if x.candidateStations]:
operator.sortCandidateEntities()
# if there operators that have only one option then sort the candidateOperators according to the first one of these
# TODO: find out what happens if there are many operators with one option
# TODO: incorporate that to
# self.sortOperators()
if self.sorting:
# sort the operators according to their waiting time
self.candidateOperators.sort(key=lambda x: x.totalWorkingTime)
# sort according to the number of options
if operatorsWithOneCandidateStation:
self.candidateOperators.sort(key=lambda x: x in operatorsWithOneCandidateStation, reverse=True)
# if the entities are managed
#------------------------------------------------------------------------------
else:
# TODO: sort according to the number of pending Jobs # TODO: sort according to the number of pending Jobs
# TODO Have to sort again according to the priority used by the operators # TODO Have to sort again according to the priority used by the operators
...@@ -389,7 +479,7 @@ class Router(ObjectInterruption): ...@@ -389,7 +479,7 @@ class Router(ObjectInterruption):
# for all the candidateOperators # for all the candidateOperators
for operator in self.candidateOperators: for operator in self.candidateOperators:
# find which pendingEntities that can move to machines is the operator managing # find which pendingEntities that can move to machines is the operator managing
for entity in [x for x in G.pendingEntities if x.canProceed and x.manager==operator]: for entity in [x for x in self.pending if x.canProceed and x.manager==operator]:
operator.candidateEntities.append(entity) operator.candidateEntities.append(entity)
# sort the candidate operators so that those who have only one option be served first # sort the candidate operators so that those who have only one option be served first
if len(operator.candidateEntities)==1: if len(operator.candidateEntities)==1:
...@@ -415,6 +505,47 @@ class Router(ObjectInterruption): ...@@ -415,6 +505,47 @@ class Router(ObjectInterruption):
# sort according to the number of options # sort according to the number of options
if operatorsWithOneOption: if operatorsWithOneOption:
self.candidateOperators.sort(key=lambda x: x in operatorsWithOneOption, reverse=True) self.candidateOperators.sort(key=lambda x: x in operatorsWithOneOption, reverse=True)
#=======================================================================
# # testing
# print 'router found the candidate entities for each operator'
# print [(str(operator.id),\
# [str(x.id) for x in operator.candidateEntities])
# for operator in self.candidateOperators]
#=======================================================================
#=======================================================================
# Sort pendingEntities
# TODO: sorting them according to the operators schedulingRule
#=======================================================================
def sortPendingEntities(self):
# TODO: to be used for sorting of operators
# there must be also a schedulingRule property for the Router
# there must also be a way to have multiple criteria for the operators (eg MC-Priority-WT)
# WT may be needed to be applied everywhere
# TODO: move that piece of code elsewhere, it doesn't look nice here. and there is not point in doing it here
# maybe it's better in findCandidateOperators method
if self.candidateOperators:
from Globals import G
candidateList=self.pending
self.activeQSorter(criterion=self.schedulingRule,candList=candidateList)
#=======================================================================
# # testing
# print 'router sorted pending entities'
#=======================================================================
#=======================================================================
# Sort candidateOperators
# TODO: consider if there must be an argument set for the schedulingRules of the Router
# TODO: consider if the scheduling rule for the operators must be global for all of them
#=======================================================================
def sortOperators(self):
# TODO: there must be criteria for sorting the cadidateOperators
#if we have sorting according to multiple criteria we have to call the sorter many times
# TODO: find out what happens in case of multiple criteria
if self.candidateOperators:
candidateList=self.candidateOperators
self.activeQSorter(criterion=self.schedulingRule,candList=candidateList)
#======================================================================= #=======================================================================
# Find candidate entities and their receivers # Find candidate entities and their receivers
...@@ -422,6 +553,59 @@ class Router(ObjectInterruption): ...@@ -422,6 +553,59 @@ class Router(ObjectInterruption):
# TODO: have to sort again after choosing candidateEntity # TODO: have to sort again after choosing candidateEntity
#======================================================================= #=======================================================================
def findCandidateReceivers(self): def findCandidateReceivers(self):
if not self.managed:
# initialise local variables occupiedReceivers and entitiesWithOccupiedReceivers
conflictingStations=[] # list with the operators that have candidateEntity with conflicting candidateReceivers
conflictingOperators=[]
# finally we have to sort before giving the entities to the operators
# If there is an entity which must have priority then it should be assigned first
#local method that finds a candidate entity for an operator
def findCandidateStation():
candidateStation=next(x for x in operator.candidateStations if not x in conflictingStations)
if not self.sorting:
if not candidateStation:
candidateStation=next(x for x in operator.candidateStations)
conflictingStations.append(candidateStation)
return candidateStation
# TODO: sorting again after choosing candidateEntity
if self.sorting:
self.sortOperators()
# for the candidateOperators that do have candidateEntities pick a candidateEntity
for operator in [x for x in self.candidateOperators if x.candidateStations]:
# find the first available entity that has no occupied receivers
operator.candidateStation=findCandidateStation()
# find the resources that are 'competing' for the same station
if not self.sorting:
# if there are entities that have conflicting receivers
if len(conflictingStations):
for operator in self.candidateOperators:
if operator.candidateStation in conflictingStations:
conflictingOperators.append(operator)
self.conflictingOperators=conflictingOperators
# keep the sorting provided by the queues if there is conflict between operators
conflictingGroup=[] # list that holds the operators that have the same recipient
if not self.sorting and self.conflictingOperators:
# for each of the candidateReceivers
for station in conflictingStations:
# find the group of operators that compete for this station
conflictingGroup=[operator for operator in self.conflictingOperators if operator.candidateStation==station]
# the operator that can proceed is the manager of the entity as sorted by the queue that holds them
conflictingGroup.sort()
# the operators that are not first in the list cannot proceed
for operator in conflitingGroup:
if conflictingGroup.index(operator)!=0:
self.candidateOperators.remove(operator)
self.calledOperators.remove(operator)
# if the moving entities are managed
#------------------------------------------------------------------------------
else:
# initialise local variables occupiedReceivers and entitiesWithOccupiedReceivers # initialise local variables occupiedReceivers and entitiesWithOccupiedReceivers
conflictingOperators=[] # list with the operators that have candidateEntity with conflicting candidateReceivers conflictingOperators=[] # list with the operators that have candidateEntity with conflicting candidateReceivers
conflictingEntities=[] # entities with conflictingReceivers conflictingEntities=[] # entities with conflictingReceivers
...@@ -478,6 +662,9 @@ class Router(ObjectInterruption): ...@@ -478,6 +662,9 @@ class Router(ObjectInterruption):
# find the first available entity that has no occupied receivers # find the first available entity that has no occupied receivers
operator.candidateEntity=findCandidateEntity() operator.candidateEntity=findCandidateEntity()
if operator.candidateEntity: if operator.candidateEntity:
if operator.candidateEntity.currentStation in self.pendingMachines:
operator.candidateEntity.candidateReceiver=operator.candidateEntity.currentStation
else:
operator.candidateEntity.candidateReceiver=findCandidateReceiver() operator.candidateEntity.candidateReceiver=findCandidateReceiver()
# find the resources that are 'competing' for the same station # find the resources that are 'competing' for the same station
...@@ -512,27 +699,12 @@ class Router(ObjectInterruption): ...@@ -512,27 +699,12 @@ class Router(ObjectInterruption):
self.calledOperators.remove(operator) self.calledOperators.remove(operator)
#======================================================================= #=======================================================================
# Sort Givers # # testing
# TODO: the queues of the candidate givers are sorted only if their receiver is not in activeCallersList # print 'router found candidate receivers for each entity'
# if an operator is called the control returns to the generator of the Router (run()) # print [(str(entity.id),\
# the next objects are not checked # str(entity.candidateReceiver.id))
# They must be control # for entity in self.pending if entity.candidateReceiver]
#======================================================================= #=======================================================================
def sortGiverQueue(self):
# for those operators that do have candidateEntity
for operator in [x for x in self.candidateOperators if x.candidateEntity]:
# check whether are called by objects that require the resource
operator.called = (operator in self.calledOperators)
# if they are not called or are not in the pendingObjects list sort the queues of the
# of the requesting the operator entities.
if not operator.called:
operator.candidateEntity.currentStation.sortEntitiesForOperator(operator)
# TODO: if the first candidate is not called then must run again
# if the first is called then this one must proceed with get entity
elif not operator.candidateEntity.candidateReceiver in self.pendingObjects:
operator.candidateEntity.currentStation.sortEntitiesForOperator(operator)
else:
break
# ======================================================================= # =======================================================================
# sorts the Operators of the Queue according to the scheduling rule # sorts the Operators of the Queue according to the scheduling rule
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment