Commit c94bdc63 authored by Georgios Dagkakis's avatar Georgios Dagkakis

code for experiments

parent 50a4e123
CACHE MANIFEST CACHE MANIFEST
# This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator # This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator
# Time: Wed Sep 16 2015 18:23:50 GMT+0200 (CEST) # Time: Wed Nov 28 2018 10:09:45 GMT+0000 (GMT)
CACHE: CACHE:
daff/index.html daff/index.html
......
...@@ -41,6 +41,7 @@ class ACO(plugin.ExecutionPlugin): ...@@ -41,6 +41,7 @@ class ACO(plugin.ExecutionPlugin):
def run(self, data): def run(self, data):
"""Preprocess the data. """Preprocess the data.
""" """
self.logger.info("ACO")
distributor_url = data['general'].get('distributorURL') distributor_url = data['general'].get('distributorURL')
distributor = None distributor = None
if distributor_url: if distributor_url:
...@@ -108,7 +109,12 @@ class ACO(plugin.ExecutionPlugin): ...@@ -108,7 +109,12 @@ class ACO(plugin.ExecutionPlugin):
else: else:
# synchronous # synchronous
for ant in scenario_list: for ant in scenario_list:
self.logger.info("%s running" % ant['key'])
try:
ant['result'] = self.runOneScenario(ant['input'])['result'] ant['result'] = self.runOneScenario(ant['input'])['result']
except:
self.logger.info("%s failed" % ant['key'])
ant['result'] = {'result_list': ['fail']}
else: # asynchronous else: # asynchronous
self.logger.info("Registering a job for %s scenarios" % len(scenario_list)) self.logger.info("Registering a job for %s scenarios" % len(scenario_list))
......
...@@ -18,6 +18,8 @@ class BatchesACO(ACO): ...@@ -18,6 +18,8 @@ class BatchesACO(ACO):
"""Calculate the score of this ant. """Calculate the score of this ant.
""" """
result, = ant['result']['result_list'] #read the result as JSON result, = ant['result']['result_list'] #read the result as JSON
if result == 'fail':
return 0
#loop through the elements #loop through the elements
for element in result['elementList']: for element in result['elementList']:
element_family = element.get('family', None) element_family = element.get('family', None)
......
...@@ -39,6 +39,8 @@ class BatchesStochasticACO(BatchesACO): ...@@ -39,6 +39,8 @@ class BatchesStochasticACO(BatchesACO):
"""Calculate the score of this ant. """Calculate the score of this ant.
""" """
result, = ant['result']['result_list'] #read the result as JSON result, = ant['result']['result_list'] #read the result as JSON
if result == 'fail':
return 0
#loop through the elements #loop through the elements
for element in result['elementList']: for element in result['elementList']:
element_family = element.get('family', None) element_family = element.get('family', None)
...@@ -68,6 +70,7 @@ class BatchesStochasticACO(BatchesACO): ...@@ -68,6 +70,7 @@ class BatchesStochasticACO(BatchesACO):
def run(self, data): def run(self, data):
"""Preprocess the data. """Preprocess the data.
""" """
self.logger.info("Stoch ACO")
self.outputFile = xlwt.Workbook() self.outputFile = xlwt.Workbook()
self.outputSheet = self.outputFile.add_sheet('ACO Results', cell_overwrite_ok=True) self.outputSheet = self.outputFile.add_sheet('ACO Results', cell_overwrite_ok=True)
self.rowIndex=0 self.rowIndex=0
...@@ -141,6 +144,7 @@ class BatchesStochasticACO(BatchesACO): ...@@ -141,6 +144,7 @@ class BatchesStochasticACO(BatchesACO):
for i in range(int(data["general"]["numberOfGenerations"])): for i in range(int(data["general"]["numberOfGenerations"])):
self.outputSheet.write(self.rowIndex,0,'Generation '+str(i+1)) self.outputSheet.write(self.rowIndex,0,'Generation '+str(i+1))
self.rowIndex+=1 self.rowIndex+=1
self.logger.info("Generation %s" % self.rowIndex)
antsInCurrentGeneration=[] antsInCurrentGeneration=[]
scenario_list = [] # for the distributor scenario_list = [] # for the distributor
# number of ants created per generation # number of ants created per generation
...@@ -190,8 +194,13 @@ class BatchesStochasticACO(BatchesACO): ...@@ -190,8 +194,13 @@ class BatchesStochasticACO(BatchesACO):
self.outputSheet.write(self.rowIndex,1,'running deterministic') self.outputSheet.write(self.rowIndex,1,'running deterministic')
self.outputSheet.write(self.rowIndex,2,ant['key']) self.outputSheet.write(self.rowIndex,2,ant['key'])
self.rowIndex+=1 self.rowIndex+=1
try:
ant['result'] = self.runOneScenario(ant['input'])['result'] ant['result'] = self.runOneScenario(ant['input'])['result']
ant['score'] = self._calculateAntScore(ant) ant['score'] = self._calculateAntScore(ant)
except:
self.logger.info("%s failed" % ant['key'])
ant['result'] = {'result_list': ['fail']}
ant['score'] = 0
ant['evaluationType']='deterministic' ant['evaluationType']='deterministic'
self.outputSheet.write(self.rowIndex,2,'Units Throughput') self.outputSheet.write(self.rowIndex,2,'Units Throughput')
self.outputSheet.write(self.rowIndex,3,-ant['score']) self.outputSheet.write(self.rowIndex,3,-ant['score'])
...@@ -220,9 +229,14 @@ class BatchesStochasticACO(BatchesACO): ...@@ -220,9 +229,14 @@ class BatchesStochasticACO(BatchesACO):
self.outputSheet.write(self.rowIndex,1,'running stochastic for '+str(numberOfReplicationsInGeneration)+' replications') self.outputSheet.write(self.rowIndex,1,'running stochastic for '+str(numberOfReplicationsInGeneration)+' replications')
self.outputSheet.write(self.rowIndex,2,ant['key']) self.outputSheet.write(self.rowIndex,2,ant['key'])
self.rowIndex+=1 self.rowIndex+=1
try:
ant['result'] = self.runOneScenario(ant['input'])['result'] ant['result'] = self.runOneScenario(ant['input'])['result']
ant['evaluationType']='stochastic'
ant['score'] = self.calculateStochasticAntScore(ant) ant['score'] = self.calculateStochasticAntScore(ant)
except:
self.logger.info("%s failed" % ant['key'])
ant['result'] = {'result_list': ['fail']}
ant['score'] = 0
ant['evaluationType']='stochastic'
self.outputSheet.write(self.rowIndex,2,'Average Units Throughput') self.outputSheet.write(self.rowIndex,2,'Average Units Throughput')
self.outputSheet.write(self.rowIndex,3,-ant['score']) self.outputSheet.write(self.rowIndex,3,-ant['score'])
self.rowIndex+=1 self.rowIndex+=1
...@@ -281,8 +295,15 @@ class BatchesStochasticACO(BatchesACO): ...@@ -281,8 +295,15 @@ class BatchesStochasticACO(BatchesACO):
self.outputSheet.write(self.rowIndex,1,'running stochastic for '+str(numberOfReplicationsInTheEnd)+' replications') self.outputSheet.write(self.rowIndex,1,'running stochastic for '+str(numberOfReplicationsInTheEnd)+' replications')
self.outputSheet.write(self.rowIndex,2,ant['key']) self.outputSheet.write(self.rowIndex,2,ant['key'])
self.rowIndex+=1 self.rowIndex+=1
try:
ant['result'] = self.runOneScenario(ant['input'])['result'] ant['result'] = self.runOneScenario(ant['input'])['result']
ant['score'] = self.calculateStochasticAntScore(ant) ant['score'] = self.calculateStochasticAntScore(ant)
except:
self.logger.info("%s failed" % ant['key'])
ant['result'] = {'result_list': ['fail']}
ant['score'] = 0
# ant['result'] = self.runOneScenario(ant['input'])['result']
# ant['score'] = self.calculateStochasticAntScore(ant)
self.outputSheet.write(self.rowIndex,2,'Average Units Throughput') self.outputSheet.write(self.rowIndex,2,'Average Units Throughput')
self.outputSheet.write(self.rowIndex,3,-ant['score']) self.outputSheet.write(self.rowIndex,3,-ant['score'])
self.rowIndex+=1 self.rowIndex+=1
......
...@@ -347,6 +347,11 @@ class CoreObject(ManPyObject): ...@@ -347,6 +347,11 @@ class CoreObject(ManPyObject):
# gets an entity from the giver # gets an entity from the giver
# ======================================================================= # =======================================================================
def getEntity(self): def getEntity(self):
import logging
self.logger = logging.getLogger("dream.platform")
self.logger.info(self.env.now, self.id, 'GETTING!')
# raise ValueError('FOO')
# get active object and its queue, as well as the active (to be) entity # get active object and its queue, as well as the active (to be) entity
#(after the sorting of the entities in the queue of the giver object) #(after the sorting of the entities in the queue of the giver object)
# activeObject=self.getActiveObject() # activeObject=self.getActiveObject()
......
from dream.simulation.Source import Source
from dream.simulation.Queue import Queue
from dream.simulation.Machine import Machine
from dream.simulation.Exit import Exit
from dream.simulation.Part import Part
from dream.simulation.Globals import runSimulation
from dream.simulation.Globals import G
import random
#the custom machine
class Inspection(Machine):
def selectReceiver(self, possibleReceivers=[]):
# 80% continue, 20% go back to Q1
# XXX Custom implementation hard-coding objects
if random.uniform(0, 1) < 0.8:
return Q2
else:
return Q1
#define the objects of the model
S=Source('S','Source', interArrivalTime={'Fixed':{'mean':0.5}}, entity='Dream.Part')
Q1=Queue('Q','Queue', capacity=float("inf"))
M1=Machine('M1','Milling1', processingTime={'Fixed':{'mean':1}})
QI=Queue('Q','Queue', capacity=float("inf"))
I=Inspection('I','Inspection', processingTime={'Fixed':{'mean':0.2}})
Q2=Queue('Q','Queue', capacity=float("inf"))
M2=Machine('M2','Milling2', processingTime={'Fixed':{'mean':1}})
E=Exit('E1','Exit')
#create the global counter variables
G.NumM1=0
G.NumM2=0
#define predecessors and successors for the objects
S.defineRouting([Q1])
Q1.defineRouting([S, I],[M1])
M1.defineRouting([Q1],[QI])
QI.defineRouting([M1],[I])
I.defineRouting([QI],[Q1, Q2])
Q2.defineRouting([I],[M2])
M2.defineRouting([Q2],[E])
E.defineRouting([M2])
def main(test=0):
# add all the objects in a list
objectList=[S,Q1,M1,QI,I,Q2,M2,E]
# set the length of the experiment
maxSimTime=1440.0
# call the runSimulation giving the objects and the length of the experiment
runSimulation(objectList, maxSimTime)
# calculate metrics
working_ratio_M1=(M1.totalWorkingTime/maxSimTime)*100
working_ratio_M2=(M2.totalWorkingTime/maxSimTime)*100
# return results for the test
if test:
return {"parts": E.numOfExits,
"working_ratio_M1": working_ratio_M1,
"working_ratio_M2": working_ratio_M2,
"NumM1":G.NumM1,
"NumM2":G.NumM2}
#print the results
print "the system produced", E.numOfExits, "parts"
print "the working ratio of", M1.objName, "is", working_ratio_M1, "%"
print "the working ratio of", M2.objName, "is", working_ratio_M2, "%"
if __name__ == '__main__':
main()
...@@ -105,6 +105,10 @@ class Exit(CoreObject): ...@@ -105,6 +105,10 @@ class Exit(CoreObject):
# gets an entity from the predecessor # gets an entity from the predecessor
# ======================================================================= # =======================================================================
def getEntity(self): def getEntity(self):
import logging
self.logger = logging.getLogger("dream.platform")
self.logger.info("!--- %s ----!" % self.env.now)
activeEntity = CoreObject.getEntity(self) #run the default method activeEntity = CoreObject.getEntity(self) #run the default method
# if the entity is in the G.pendingEntities list then remove it from there # if the entity is in the G.pendingEntities list then remove it from there
from Globals import G from Globals import G
......
...@@ -30,6 +30,7 @@ Models an Interruption that handles the operating of a Station by an ObjectResou ...@@ -30,6 +30,7 @@ Models an Interruption that handles the operating of a Station by an ObjectResou
import simpy import simpy
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
import logging
# =========================================================================== # ===========================================================================
# Class that handles the Operator Behavior # Class that handles the Operator Behavior
...@@ -52,6 +53,7 @@ class Broker(ObjectInterruption): ...@@ -52,6 +53,7 @@ class Broker(ObjectInterruption):
# flag that shows if broker was called to request or release operator. # flag that shows if broker was called to request or release operator.
# Machine updates this before calling the broker # Machine updates this before calling the broker
self.invokeType='request' self.invokeType='request'
self.logger = logging.getLogger("dream.platform")
#=========================================================================== #===========================================================================
# the initialize method # the initialize method
...@@ -77,8 +79,9 @@ class Broker(ObjectInterruption): ...@@ -77,8 +79,9 @@ class Broker(ObjectInterruption):
# TODO: add new broker event - brokerIsCalled # TODO: add new broker event - brokerIsCalled
self.expectedSignals['isCalled']=1 self.expectedSignals['isCalled']=1
self.logger.info("!--- %s %s Waiting isCalled1 ----!" % (self.env.now, self.id))
yield self.isCalled yield self.isCalled
self.logger.info("!--- %s %s Got isCalled1 ----!" % (self.env.now, self.id))
transmitter, eventTime=self.isCalled.value transmitter, eventTime=self.isCalled.value
assert eventTime==self.env.now, 'the broker should be granted control instantly' assert eventTime==self.env.now, 'the broker should be granted control instantly'
self.isCalled=self.env.event() self.isCalled=self.env.event()
...@@ -106,8 +109,9 @@ class Broker(ObjectInterruption): ...@@ -106,8 +109,9 @@ class Broker(ObjectInterruption):
self.victim.printTrace(self.victim.id, waitEvent='(resourceIsAvailable broker)') self.victim.printTrace(self.victim.id, waitEvent='(resourceIsAvailable broker)')
self.expectedSignals['resourceAvailable']=1 self.expectedSignals['resourceAvailable']=1
self.logger.info("!--- %s %s Waiting resourceAvailable ----!" % (self.env.now, self.id))
yield self.resourceAvailable yield self.resourceAvailable
self.logger.info("!--- %s %s Got resourceAvailable ----!" % (self.env.now, self.id))
transmitter, eventTime=self.resourceAvailable.value transmitter, eventTime=self.resourceAvailable.value
self.resourceAvailable=self.env.event() self.resourceAvailable=self.env.event()
...@@ -132,7 +136,10 @@ class Broker(ObjectInterruption): ...@@ -132,7 +136,10 @@ class Broker(ObjectInterruption):
with self.victim.operatorPool.getResource(self.victim.currentOperator).request() as request: with self.victim.operatorPool.getResource(self.victim.currentOperator).request() as request:
self.logger.info("!--- %s %s Waiting request ----!" % (self.env.now, self.id))
yield request yield request
self.logger.info("!--- %s %s Got request ----!" % (self.env.now, self.id))
# update the operator workingStation # update the operator workingStation
self.victim.currentOperator.workingStation=self.victim self.victim.currentOperator.workingStation=self.victim
self.victim.printTrace(self.victim.currentOperator.objName, startWork=self.victim.id) self.victim.printTrace(self.victim.currentOperator.objName, startWork=self.victim.id)
...@@ -165,7 +172,9 @@ class Broker(ObjectInterruption): ...@@ -165,7 +172,9 @@ class Broker(ObjectInterruption):
# wait till the processing is over # wait till the processing is over
self.expectedSignals['isCalled']=1 self.expectedSignals['isCalled']=1
self.logger.info("!--- %s %s Waiting isCalled2 ----!" % (self.env.now, self.id))
yield self.isCalled yield self.isCalled
self.logger.info("!--- %s %s Got isCalled2 ----!" % (self.env.now, self.id))
transmitter, eventTime=self.isCalled.value transmitter, eventTime=self.isCalled.value
assert eventTime==self.env.now, 'the broker should be granted control instantly' assert eventTime==self.env.now, 'the broker should be granted control instantly'
......
...@@ -87,8 +87,9 @@ class SkilledRouter(Router): ...@@ -87,8 +87,9 @@ class SkilledRouter(Router):
# wait until the router is called # wait until the router is called
self.expectedSignals['isCalled']=1 self.expectedSignals['isCalled']=1
self.logger.info("!--- %s %s WAITING isCalled ----!" % (self.env.now, self.id))
yield self.isCalled yield self.isCalled
self.logger.info("!--- %s %s GOT isCalled ----!" % (self.env.now, self.id))
transmitter, eventTime=self.isCalled.value transmitter, eventTime=self.isCalled.value
self.isCalled=self.env.event() self.isCalled=self.env.event()
...@@ -223,8 +224,11 @@ class SkilledRouter(Router): ...@@ -223,8 +224,11 @@ class SkilledRouter(Router):
import time import time
startLP=time.time() startLP=time.time()
if LPFlag: if LPFlag:
if self.whereToMaxWIP and self.previousSolution:
self.logger.info('---> ' + str(self.env.now)) self.logger.info('---> ' + str(self.env.now))
self.logger.info(self.previousSolution)
self.logger.info(self.availableOperatorList)
if self.whereToMaxWIP and self.previousSolution:
# self.logger.info('---> ' + str(self.env.now))
solution={} solution={}
maxWIP=-1 maxWIP=-1
minWIP=float('inf') minWIP=float('inf')
...@@ -239,7 +243,7 @@ class SkilledRouter(Router): ...@@ -239,7 +243,7 @@ class SkilledRouter(Router):
# first, find the machine with max wip # first, find the machine with max wip
for stationId in sorted_station_id_list: for stationId in sorted_station_id_list:
stationDict = self.availableStationsDict.get(stationId, None) stationDict = self.availableStationsDict.get(stationId, None)
self.logger.info(stationDict) # self.logger.info(stationDict)
if not stationDict: if not stationDict:
continue continue
wip = stationDict['WIP'] wip = stationDict['WIP']
...@@ -250,11 +254,12 @@ class SkilledRouter(Router): ...@@ -250,11 +254,12 @@ class SkilledRouter(Router):
] ]
assert len(assignedOperatorList) in (0, 1), assignedOperatorList assert len(assignedOperatorList) in (0, 1), assignedOperatorList
if not assignedOperatorList: if not assignedOperatorList:
self.logger.info('%s has no operator' % stationId) pass
# self.logger.info('%s has no operator' % stationId)
if wip > maxWIP and not assignedOperatorList: if wip > maxWIP and not assignedOperatorList:
machineWithMaxWIP=stationId machineWithMaxWIP=stationId
maxWIP = wip maxWIP = wip
self.logger.info(machineWithMaxWIP) # self.logger.info(machineWithMaxWIP)
solution={} solution={}
# First, search for an operator that was not # First, search for an operator that was not
# previously assigned, and can handle the maxWIP station # previously assigned, and can handle the maxWIP station
...@@ -398,7 +403,7 @@ class SkilledRouter(Router): ...@@ -398,7 +403,7 @@ class SkilledRouter(Router):
if operatorID in self.previousSolution: if operatorID in self.previousSolution:
# if the solution returned the operator that is already in the station # if the solution returned the operator that is already in the station
# then no signal is needed # then no signal is needed
if not self.previousSolution[operatorID] == solution[operatorID]: if not (self.previousSolution[operatorID] == solution[operatorID] and operator == station.currentOperator):
self.toBeSignalled.append(station) self.toBeSignalled.append(station)
else: else:
self.toBeSignalled.append(station) self.toBeSignalled.append(station)
...@@ -413,12 +418,15 @@ class SkilledRouter(Router): ...@@ -413,12 +418,15 @@ class SkilledRouter(Router):
# remove the operator id from availableOperatorList # remove the operator id from availableOperatorList
self.availableOperatorList.remove(operatorID) self.availableOperatorList.remove(operatorID)
#=================================================================== #===================================================================
# # XXX signal the stations that the assignment is complete # # XXX signal the stations that the assignment is complete
#=================================================================== #===================================================================
# if the operator is free the station can be signalled right away # if the operator is free the station can be signalled right away
stationsProcessingLast=[] stationsProcessingLast=[]
toBeSignalled=list(self.toBeSignalled) toBeSignalled=list(self.toBeSignalled)
self.logger.info("!--- %s toBeSignalled: %s ----!" % (self.env.now, len(toBeSignalled)))
for station in toBeSignalled: for station in toBeSignalled:
# check if the operator that the station waits for is free # check if the operator that the station waits for is free
operator=station.operatorToGet operator=station.operatorToGet
...@@ -438,7 +446,10 @@ class SkilledRouter(Router): ...@@ -438,7 +446,10 @@ class SkilledRouter(Router):
self.expectedFinishSignalsDict[station.id]=signal self.expectedFinishSignalsDict[station.id]=signal
self.expectedFinishSignals.append(signal) self.expectedFinishSignals.append(signal)
while self.expectedFinishSignals: while self.expectedFinishSignals:
self.logger.info("!--- %s %s WAITING expectedFinishSignals ----!" % (self.env.now, self.id))
receivedEvent = yield self.env.any_of(self.expectedFinishSignals) receivedEvent = yield self.env.any_of(self.expectedFinishSignals)
self.logger.info("!--- %s %s GOT expectedFinishSignals ----!" % (self.env.now, self.id))
for signal in self.expectedFinishSignals: for signal in self.expectedFinishSignals:
if signal in receivedEvent: if signal in receivedEvent:
transmitter, eventTime=signal.value transmitter, eventTime=signal.value
...@@ -488,6 +499,8 @@ class SkilledRouter(Router): ...@@ -488,6 +499,8 @@ class SkilledRouter(Router):
# ======================================================================= # =======================================================================
def signalStation(self, station, operator): def signalStation(self, station, operator):
# signal this station's broker that the resource is available # signal this station's broker that the resource is available
self.logger.info("!--- %s %s signalStation ----!" % (self.env.now, self.id))
if station.broker.waitForOperator: if station.broker.waitForOperator:
if station.broker.expectedSignals['resourceAvailable']: if station.broker.expectedSignals['resourceAvailable']:
self.sendSignal(receiver=station.broker, signal=station.broker.resourceAvailable) self.sendSignal(receiver=station.broker, signal=station.broker.resourceAvailable)
......
# ===========================================================================
# Copyright 2013 University of Limerick
#
# This file is part of DREAM.
#
# DREAM is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DREAM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with DREAM. If not, see <http://www.gnu.org/licenses/>.
# ===========================================================================
'''
Created on 19 Feb 2013
@author: Ioannis
'''
'''
Models an Interruption that schedules the operation of the machines by different managers
'''
import simpy
from OperatorRouter import Router
from opAss_LPmethod import opAss_LP
import Globals
# ===========================================================================
# Class that handles the Operator Behavior
# ===========================================================================
class WhereToSkilledRouter(Router):
# =======================================================================
# according to this implementation one machine per broker is allowed
# The Broker is initiated within the Machine and considered as
# black box for the ManPy end Developer
# TODO: we should maybe define a global schedulingRule criterion that will be
# chosen in case of multiple criteria for different Operators
# =======================================================================
def __init__(self,id='SkilledRouter01',name='SkilledRouter01',sorting=False,outputSolutions=True,
weightFactors=[2, 1, 0, 2, 0, 1], tool={},checkCondition=False,twoPhaseSearch=False,**kw):
Router.__init__(self)
# Flag used to notify the need for re-allocation of skilled operators to operatorPools
self.allocation=False
# Flag used to notify the need to wait for endedLastProcessing signal
waitEndProcess=False
self.outputSolutions=outputSolutions
self.id=id
self.name=name
self.weightFactors=weightFactors
self.tool=tool
self.checkCondition=checkCondition
self.twoPhaseSearch=twoPhaseSearch
#===========================================================================
# the initialize method
#===========================================================================
def initialize(self):
Router.initialize(self)
self.allocation=False
self.waitEndProcess=False
self.pendingQueues=[]
self.pendingMachines=[]
self.previousSolution={}
self.solutionList=[]
# =======================================================================
# the run method
# =======================================================================
'''
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
'''
def run(self):
while 1:
# wait until the router is called
self.expectedSignals['isCalled']=1
yield self.isCalled
import logging
logger = logging.getLogger("WhereToSkilledRouter")
logger.info(self.env.now)
transmitter, eventTime=self.isCalled.value
self.isCalled=self.env.event()
self.printTrace('','=-'*15)
self.printTrace('','router received event')
# wait till there are no more events, the machines must be blocked
while 1:
if self.env.now==self.env.peek():
self.printTrace('', 'there are MORE events for now')
yield self.env.timeout(0)
else:
self.printTrace('','there are NO more events for now')
break
self.printTrace('','=-'*15)
from Globals import G
if self.allocation:
#===================================================================
# # XXX wait for the interval time to finish (10 minutes between reassignments
#===================================================================
'''not implemented yet'''
#===================================================================
# # find stations that are in position to process
#===================================================================
self.availableStations=[]
for station in G.MachineList:
if station.checkIfActive():
self.availableStations.append(station)
#===================================================================
# # XXX if the resources are still assigned then un-assign them from the machines they are currently assigned
# # the same for all the objects exits
#===================================================================
for operator in [x for x in G.OperatorsList if x.isAssignedTo()]:
operator.unAssign()
for object in [x for x in G.ObjList if x.exitIsAssignedTo()]:
object.unAssignExit()
#===================================================================
# # XXX un-assign all the PBs from their operatorPools
#===================================================================
for station in G.MachineList:
station.operatorPool.operators=[]
#===================================================================
# # XXX calculate the WIP of each station
#===================================================================
for station in self.availableStations:
station.wip=1+(len(station.getActiveObjectQueue())/station.capacity)
for predecessor in station.previous:
try:
station.wip+=float(len(predecessor.getActiveObjectQueue())/float(predecessor.capacity))
except:
# XXX what happens in the case of sources or infinite-capacity-queues
pass
#===================================================================
# # stations of the line and their corresponding WIP
# TODO: the WIP of the stations must be normalised to the max WIP possible on that station
#===================================================================
# identify the last time that there was an assignment
maxLastAssignment=0
for record in self.solutionList:
if record:
maxLastAssignment=record["time"]
self.availableStationsDict={}
for station in self.availableStations:
lastAssignmentTime=0
for record in self.solutionList:
if station.id in record["allocation"].values():
lastAssignmentTime=record["time"]
# normalise the lastAssignmentTime based on the maxLastAssignment.
if maxLastAssignment:
lastAssignmentTime=1.0-float(lastAssignmentTime/float(maxLastAssignment))
# it there is definition of 'technology' to group machines add this
if station.technology:
self.availableStationsDict[str(station.id)]={'stationID':station.technology,'machineID':station.id,
'WIP':station.wip,'lastAssignment':lastAssignmentTime}
# otherwise add just the id
else:
self.availableStationsDict[str(station.id)]={'stationID':station.id,
'WIP':station.wip,'lastAssignment':lastAssignmentTime}
#===================================================================
# # operators and their skills set
#===================================================================
self.operators={}
import Globals
for operator in G.OperatorsList:
newSkillsList=[]
for skill in operator.skillsList:
newSkill=skill
mach=Globals.findObjectById(skill)
# if there is 'technology' defined for the stations send this to the LP solver
if mach.technology:
newSkill=mach.technology
if newSkill not in newSkillsList:
newSkillsList.append(newSkill)
self.operators[str(operator.id)]=newSkillsList
#===================================================================
# # available operators
#===================================================================
self.availableOperatorList=[]
for operator in G.OperatorsList:
if operator.available and operator.onShift and not operator.onBreak:
self.availableOperatorList.append(operator.id)
LPFlag=True
if self.checkCondition:
LPFlag=self.checkIfAllocationShouldBeCalled()
#===================================================================
# # XXX run the LP assignment algorithm
# # should return a list of correspondences
# # XXX signal the stations that the assignment is complete
# TODO: a constant integer must be added to all WIP before provided to the opAss_LP
# as it doesn't support zero WIP levels
#===================================================================
import time
startLP=time.time()
if LPFlag:
if self.twoPhaseSearch:
# remove all the blocked machines from the available stations
# and create another dict only with them
machinesForSecondPhaseDict={}
for stationId in self.availableStationsDict.keys():
machine = Globals.findObjectById(stationId)
nextObject = machine.next[0]
nextObjectClassName = nextObject.__class__.__name__
reassemblyBlocksMachine = False
if 'Reassembly' in nextObjectClassName:
if nextObject.getActiveObjectQueue():
if nextObject.getActiveObjectQueue()[0].type == 'Batch':
reassemblyBlocksMachine = True
if machine.isBlocked or reassemblyBlocksMachine:
if not len(machine.getActiveObjectQueue()) and (not reassemblyBlocksMachine):
raise ValueError('empty machine considered as blocked')
if machine.timeLastEntityEnded < machine.timeLastEntityEntered:
raise ValueError('machine considered as blocked, while it has Entity that has not finished')
if "Queue" in nextObjectClassName:
if len(nextObject.getActiveObjectQueue()) != nextObject.capacity:
raise ValueError('Machine considered as blocked while Queue has space')
if "Clearance" in nextObjectClassName:
if not nextObject.getActiveObjectQueue():
raise ValueError('Machine considered as blocked while Clearance is empty')
else:
subBatchMachineHolds = machine.getActiveObjectQueue()[0]
subBatchLineClearanceHolds = nextObject.getActiveObjectQueue()[0]
if subBatchMachineHolds.parentBatch == subBatchLineClearanceHolds.parentBatch and\
(len(nextObject.getActiveObjectQueue()) != nextObject.capacity):
raise ValueError('Machine considered as blocked while Line Clearance holds same batch and has space')
machinesForSecondPhaseDict[stationId] = self.availableStationsDict[stationId]
del self.availableStationsDict[stationId]
else:
if len(machine.getActiveObjectQueue()) and (not machine.isProcessing) and\
machine.onShift and machine.currentOperator:
raise ValueError('machine should be considered blocked')
# run the LP method only for the machines that are not blocked
solution=opAss_LP(self.availableStationsDict, self.availableOperatorList,
self.operators, previousAssignment=self.previousSolution,
weightFactors=self.weightFactors,Tool=self.tool)
# create a list with the operators that were sent to the LP but did not get allocated
operatorsForSecondPhaseList=[]
for operatorId in self.availableOperatorList:
if operatorId not in solution.keys():
operatorsForSecondPhaseList.append(operatorId)
# in case there is some station that did not get operator even if it was not blocked
# add them alos for the second fail (XXX do not think there is such case)
for stationId in self.availableStationsDict.keys():
if stationId not in solution.values():
machinesForSecondPhaseDict[stationId] = self.availableStationsDict[stationId]
# if there are machines and operators for the second phase
# run again the LP for machines and operators that are not in the former solution
if machinesForSecondPhaseDict and operatorsForSecondPhaseList:
secondPhaseSolution=opAss_LP(machinesForSecondPhaseDict, operatorsForSecondPhaseList,
self.operators, previousAssignment=self.previousSolution,
weightFactors=self.weightFactors,Tool=self.tool)
# update the solution with the new LP results
solution.update(secondPhaseSolution)
else:
solution=opAss_LP(self.availableStationsDict, self.availableOperatorList,
self.operators, previousAssignment=self.previousSolution,
weightFactors=self.weightFactors,Tool=self.tool)
else:
# if the LP is not called keep the previous solution
# if there are no available operators though, remove those
solution=self.previousSolution
for operatorID in solution.keys():
if not operatorID in self.availableOperatorList:
del solution[operatorID]
# print '-------'
# print self.env.now, solution
# print 'time needed',time.time()-startLP
self.solutionList.append({
"time":self.env.now,
"allocation":solution
})
# XXX assign the operators to operatorPools
# pendingStations/ available stations not yet given operator
self.pendingStations=[]
from Globals import findObjectById
# apply the solution
# loop through the stations. If there is a station that should change operator
# set the operator dedicated to None and also release operator
for station in G.MachineList:
# obtain the operator and the station
if station.currentOperator:
operator=station.currentOperator
previousAssignment=self.previousSolution.get(operator.id,None)
currentAssignment=solution.get(operator.id,None)
if (not previousAssignment == currentAssignment):
operator.operatorDedicatedTo=None
if not station.isProcessing:
station.releaseOperator()
# loop through the entries in the solution dictionary
for operatorID in solution.keys():
# obtain the operator and the station
operator=findObjectById(operatorID)
station=findObjectById(solution[operatorID])
if operatorID in self.previousSolution:
# if the solution returned the operator that is already in the station
# then no signal is needed
if not self.previousSolution[operatorID] == solution[operatorID]:
self.toBeSignalled.append(station)
else:
self.toBeSignalled.append(station)
# update the operatorPool of the station
station.operatorPool.operators=[operator]
# assign the operator to the station
operator.assignTo(station)
# set that the operator is dedicated to the station
operator.operatorDedicatedTo=station
# set in every station the operator that it is to get
station.operatorToGet=operator
# remove the operator id from availableOperatorList
self.availableOperatorList.remove(operatorID)
#===================================================================
# # XXX signal the stations that the assignment is complete
#===================================================================
# if the operator is free the station can be signalled right away
stationsProcessingLast=[]
toBeSignalled=list(self.toBeSignalled)
for station in toBeSignalled:
# check if the operator that the station waits for is free
operator=station.operatorToGet
if operator.workingStation:
# if the operator is in a station that is processing or just starts processing then he/she is not free
if operator.workingStation.isProcessing or (not (operator.workingStation.timeLastEntityEntered==self.env.now)):
stationsProcessingLast.append(operator.workingStation)
continue
# signal the station so that it gets the operator
self.signalStation(station, operator)
# else wait for signals that operator became available and signal the stations
self.expectedFinishSignalsDict={}
self.expectedFinishSignals=[]
for station in stationsProcessingLast:
signal=self.env.event()
self.expectedFinishSignalsDict[station.id]=signal
self.expectedFinishSignals.append(signal)
while self.expectedFinishSignals:
receivedEvent = yield self.env.any_of(self.expectedFinishSignals)
for signal in self.expectedFinishSignals:
if signal in receivedEvent:
transmitter, eventTime=signal.value
assert eventTime==self.env.now, 'the station finished signal must be received on the time of request'
self.expectedFinishSignals.remove(signal)
del self.expectedFinishSignalsDict[transmitter.id]
# signal also the other stations that should be signalled
for id in solution.keys():
operator=findObjectById(id)
station=findObjectById(solution[id])
signal=True
# signal only the stations in the original list
if station not in self.toBeSignalled:
signal=False
# signal only if the operator is free
if operator.workingStation:
if operator.workingStation.isProcessing\
or (not (operator.workingStation.timeLastEntityEntered==self.env.now)):
signal=False
if signal:
# signal the station so that it gets the operator
self.signalStation(station, operator)
#===================================================================
# default behaviour
#===================================================================
else:
# entry actions
self.entryActions()
# run the routine that allocates operators to machines
self.allocateOperators()
# assign operators to stations
self.assignOperators()
# unAssign exits
self.unAssignExits()
# signal the stations that ought to be signalled
self.signalOperatedStations()
self.previousSolution=solution
self.printTrace('', 'router exiting')
self.printTrace('','=-'*20)
self.exitActions()
# =======================================================================
# signal the station or the Queue to impose the assignment
# =======================================================================
def signalStation(self, station, operator):
# signal this station's broker that the resource is available
if station.broker.waitForOperator:
if station.broker.expectedSignals['resourceAvailable']:
self.sendSignal(receiver=station.broker, signal=station.broker.resourceAvailable)
self.printTrace('router', 'signalling broker of'+' '*50+station.id)
self.toBeSignalled.remove(station)
# signal the queue proceeding the station
else:
if station.canAccept()\
and any(type=='Load' for type in station.multOperationTypeList):
if station.expectedSignals['loadOperatorAvailable']:
self.sendSignal(receiver=station, signal=station.loadOperatorAvailable)
self.printTrace('router', 'signalling'+' '*50+station.id)
self.toBeSignalled.remove(station)
# =======================================================================
# return control to the Machine.run
# =======================================================================
def exitActions(self):
Router.exitActions(self)
self.allocation=False
self.waitEndProcess=False
def checkIfAllocationShouldBeCalled(self):
from Globals import G
# loop through the operators and the machines.
# If for one the shift ended or started right now allocation is needed
for obj in G.OperatorsList+G.MachineList:
if (obj.timeLastShiftEnded==self.env.now) or (obj.timeLastShiftStarted==self.env.now):
return True
# loop through the machines
for machine in G.MachineList:
# if one machine is starved more than 30 then allocation is needed
if (self.env.now-machine.timeLastEntityLeft>=30) and (not machine.getActiveObjectQueue()):
return True
# check for the previous buffer. If it is more than 80% full allocation is needed
previousQueue=self.getPreviousQueue(machine)
if previousQueue:
if float(len(previousQueue.getActiveObjectQueue()))/float(previousQueue.capacity)>=0.8:
return True
return False
def postProcessing(self):
if self.outputSolutions:
self.solutionList.append({
"time":self.env.now,
"allocation":{}
})
def outputResultsJSON(self):
if self.outputSolutions:
from Globals import G
json = {'_class': 'Dream.%s' % self.__class__.__name__,
'id': self.id,
'results': {}}
json['results']['solutionList'] = self.solutionList
G.outputJSON['elementList'].append(json)
# for a machine gets the decomposition and the buffer (if any)
def getPreviousList(self, machine):
previousList=[]
predecessor=machine.previous[0]
while 1:
if "Reassembly" in str(predecessor.__class__) or "Source" in str(predecessor.__class__):
break
previousList.append(predecessor)
predecessor=predecessor.previous[0]
return previousList
# for a machine gets the previous queue (if any)
def getPreviousQueue(self, machine):
predecessor=machine.previous[0]
while 1:
if "Source" in str(predecessor.__class__):
return None
if "Queue" in str(predecessor.__class__) or "Clearance" in str(predecessor.__class__):
return predecessor
predecessor=predecessor.previous[0]
# for a machine gets a list with the parallel machines
def getParallelMachinesList(self, machine):
alreadyConsidered=[machine]
parallelMachinesList=[]
previousObject=machine.previous[0]
while 1:
if "Reassembly" in str(previousObject.__class__) or "Source" in str(previousObject.__class__)\
or "Queue" in str(previousObject.__class__) or "Clearance" in str(previousObject.__class__):
break
alreadyConsidered.append(previousObject)
previousObject=previousObject.previous[0]
for nextObject in previousObject.next:
while 1:
if nextObject in alreadyConsidered:
break
if "Machine" in str(nextObject.__class__) or "M3" in str(nextObject.__class__):
parallelMachinesList.append(nextObject)
break
nextObject=nextObject.next[0]
return parallelMachinesList
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