Commit 8a9dd26a authored by Georgios Dagkakis's avatar Georgios Dagkakis

CapacityObjects moved from simulation folder

parent 94d13812
# ===========================================================================
# 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 5 June 2013
@author: George
'''
'''
entity that requires specific capacity from a station
'''
from Entity import Entity
# ===========================================================================
# The CapacityEntity object
# ===========================================================================
class CapacityEntity(Entity):
type="CapacityEntity"
def __init__(self, id=None, name=None, capacityProjectId=None, requiredCapacity=10, priority=0, dueDate=0,
orderDate=0, currentStation=None, isCritical=False, **kw):
Entity.__init__(self, id, name, priority, dueDate, orderDate, isCritical, currentStation=currentStation)
self.capacityProjectId=capacityProjectId # the project id hat the capacity Entity is part of
self.capacityProject=None # the project that the capacity Entity is part of. It is defined in initialize
self.requiredCapacity=requiredCapacity # the capacity that the capacity entity requires from the following station
self.shouldMove=False
from Globals import G
G.CapacityEntityList.append(self)
def initialize(self):
Entity.initialize(self)
self.shouldMove=False
from Globals import G
# find the project that the capacity entity is part of
for project in G.CapacityProjectList:
if project.id==self.capacityProjectId:
self.capacityProject=project
break
\ No newline at end of file
# ===========================================================================
# 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 5 June 2013
@author: George
'''
'''
a project that requires specific capacity from each station
'''
from Entity import Entity
# ===========================================================================
# The CapacityEntityProject object
# ===========================================================================
class CapacityProject(Entity):
type="CapacityProject"
def __init__(self, id=None, name=None, capacityRequirementDict={}, earliestStartDict={}, dueDate=0,
assemblySpaceRequirement=0, **kw):
Entity.__init__(self, id, name, dueDate=dueDate)
# a dict that shows the required capacity from every station
self.capacityRequirementDict=capacityRequirementDict
# a dict that shows the earliest start in every station
self.earliestStartDict=earliestStartDict
# the assembly space the project requires
self.assemblySpaceRequirement=assemblySpaceRequirement
from Globals import G
G.CapacityProjectList.append(self)
def initialize(self):
self.projectSchedule=[] # a list of dicts to keep the schedule
self.alreadyWorkedDict={} # a dict that hold what has been processed at every station
for stationId in self.capacityRequirementDict:
self.alreadyWorkedDict[stationId]=0
# =======================================================================
# outputs results to JSON File
# =======================================================================
def outputResultsJSON(self):
from Globals import G
json = {'_class': 'Dream.%s' % (self.__class__.__name__),
'id': self.id,
'family': 'Job',
'results': {}}
if (G.numberOfReplications == 1):
# if we had just one replication output the results as numbers
json['results']['schedule']=self.projectSchedule
G.outputJSON['elementList'].append(json)
# ===========================================================================
# 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 5 June 2013
@author: George
'''
'''
a station that can process a specified capacity in every time period
'''
from Queue import Queue
import simpy
# ===========================================================================
# the CapacityStation object
# ===========================================================================
class CapacityStation(Queue):
family='CapacityStation'
#===========================================================================
# the __init__ method of the CapacityStation
#===========================================================================
def __init__(self, id, name, capacity=float("inf"), intervalCapacity=[], schedulingRule="FIFO", gatherWipStat=False,
sharedResources={}, **kw):
Queue.__init__(self, id, name, capacity=capacity)
# a list that holds the capacity (manhours) that is available in each interval
self.intervalCapacity=intervalCapacity
# a list that holds the capacity (manhours) that is available in each interval for the remaining time
self.remainingIntervalCapacity=list(self.intervalCapacity)
# blocks the entry of the capacity station, so that it can be manipulated to accept only in certain moments of simulation time
self.isLocked=True
# dict that holds information if station shares workpower with some other station
self.sharedResources=sharedResources
def initialize(self):
Queue.initialize(self)
# if the station shares resources and the capacity is not defined in this
# then read it from some other of the sharing stations
if not self.intervalCapacity and self.sharedResources:
for stationId in self.sharedResources.get('stationIds',[]):
import Globals
station=Globals.findObjectById(stationId)
if station.intervalCapacity:
self.intervalCapacity=station.intervalCapacity
break
# initialize variables
self.remainingIntervalCapacity=list(self.intervalCapacity)
self.isLocked=True
self.utilisationDict=[] # a list of dicts for the utilization results
self.detailedWorkPlan=[] # a list of dicts to keep detailed data
from Globals import G
G.CapacityStationList.append(self)
def canAccept(self, callerObject=None):
if self.isLocked:
return False
return Queue.canAccept(self)
# =======================================================================
# outputs results to JSON File
# =======================================================================
def outputResultsJSON(self):
from Globals import G
json = {'_class': 'Dream.%s' % self.__class__.__name__,
'id': self.id,
'family': self.family,
'results': {}}
if (G.numberOfReplications == 1):
# if we had just one replication output the results as numbers
json['results']['capacityUsed']=self.utilisationDict
meanUtilization=0
for entry in self.utilisationDict:
meanUtilization+=entry['utilization']/float(len(self.utilisationDict))
json['results']['meanUtilization']=meanUtilization
json['results']['detailedWorkPlan']=self.detailedWorkPlan
G.outputJSON['elementList'].append(json)
\ No newline at end of file
# ===========================================================================
# 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 6 June 2013
@author: George
'''
'''
the buffer of the capacity station. Only change from queue that it can be blocked.
'''
import simpy
from Queue import Queue
# ===========================================================================
# the Queue object
# ===========================================================================
class CapacityStationBuffer(Queue):
#===========================================================================
# the __init__ method of the CapacityStationBuffer
#===========================================================================
def __init__(self, id, name, requireFullProject =False, capacity=float("inf"), isDummy=False,
schedulingRule="FIFO", gatherWipStat=False,**kw):
Queue.__init__(self, id, name, capacity=capacity)
self.isLocked=True
self.requireFullProject=requireFullProject # flag that shows if here the whole project is assembled
from Globals import G
G.CapacityStationBufferList.append(self)
def initialize(self):
Queue.initialize(self)
self.isLocked=True
def canAccept(self, callerObject=None):
if self.isLocked:
return False
return Queue.canAccept(self)
def haveToDispose(self, callerObject=None):
activeObjectQ=self.getActiveObjectQueue()
if len(activeObjectQ)==0:
return False
if not activeObjectQ[0].shouldMove:
return False
# put the entities that should move in front
def sortEntities(self):
activeObjectQ=self.getActiveObjectQueue()
activeObjectQ.sort(key=lambda x: x.shouldMove, reverse=True)
# ===========================================================================
# 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 6 June 2013
@author: George
'''
'''
event generator that controls the capacity station objects
'''
import simpy
from EventGenerator import EventGenerator
from CapacityEntity import CapacityEntity
from Globals import G
class CapacityStationController(EventGenerator):
def __init__(self, id=id, name=None, start=0, stop=float('inf'), interval=1,
duration=0, method=None, argumentDict={}, dueDateThreshold=float('inf'),
prioritizeIfCanFinish=False,**kw):
EventGenerator.__init__(self, id, name, start, stop, interval,
duration, method, argumentDict)
# attribute used by optimization in calculateWhatIsToBeProcessed
# only the projects that are within this threshold from the one with EDD in the same bufffer
# will be considered to move at first
self.dueDateThreshold=float(dueDateThreshold)
# attribute that shows if we prioritize entities that can finish work in this station in the next interval
self.prioritizeIfCanFinish=bool(int(prioritizeIfCanFinish))
# the total assemblySpace in the system
self.assemblySpace=float(G.extraPropertyDict.get('assemblySpace', float('inf')))
self.method=self.steps
def initialize(self):
EventGenerator.initialize(self)
# sort the buffers so if they have shared resources the ones with highest priority will go in front
self.sortBuffers()
# the main loop that is carried in every interval
def steps(self):
# loop through the stations
for station in G.CapacityStationList:
exit=station.next[0] # take the exit
exit.isLocked=False # unlock the exit
# loop though the entities
entitiesToCheck=list(station.getActiveObjectQueue())
for entity in entitiesToCheck:
if not exit.isRequested.triggered: # this is needed because the signal can be triggered also by the buffer
if exit.expectedSignals['isRequested']:
self.sendSignal(receiver=exit, signal=exit.isRequested)
# wait until the entity is removed
station.waitEntityRemoval=True
station.expectedSignals['entityRemoved']=1
yield station.entityRemoved
transmitter, eventTime=station.entityRemoved.value
station.waitEntityRemoval=False
exit.currentlyObtainedEntities.append(entity)
station.entityRemoved=self.env.event()
project=entity.capacityProject
# output the finish time of the project. This will updated every time, so in the end it should be correct
for entry in project.projectSchedule:
if entry['stationId']==station.id:
entry['exitTime']=self.env.now
# lock the exit again
exit.isLocked=True
# create the entities in the following stations
self.createInCapacityStationBuffers()
# if the last exits led to an empty system then the simulation must be stopped
# step returns and the generator never yields the stepsAreComplete signal
if self.checkIfSystemEmpty():
# if the system is empty set stop to now so that the generator stops and return
self.stop=self.env.now
return
# if there is need to merge entities in a buffer
self.mergeEntities()
# Calculate from the last moves in Station->StationExits
# what should be created in StationBuffers and create it
self.createInCapacityStationBuffers()
# Calculate what should be given in every Station
# and set the flags to the entities of StationBuffers
self.calculateWhatIsToBeProcessed()
# move the entities into the stations
# loop through the stations
for station in G.CapacityStationList:
station.isLocked=False # unlock the station
buffer=station.previous[0] # take the buffer
buffer.sortEntities() # sort the entities of the buffer so the ones to move go in front
periodDict={}
periodDict['period']=self.env.now
# loop though the entities
entitiesToCheck=list(buffer.getActiveObjectQueue())
capacityAvailable=station.intervalCapacity[int(self.env.now)]
capacityAllocated=0
for entity in entitiesToCheck:
if not entity.shouldMove: # when the first entity that should not move is reached break
break
# ToDo, here we do not check if station.expectedSignals['isRequested']==1
# consistency problem?
self.sendSignal(receiver=station, signal=station.isRequested)
buffer.waitEntityRemoval=True
buffer.expectedSignals['entityRemoved']=1
yield buffer.entityRemoved
transmitter, eventTime=buffer.entityRemoved.value
buffer.waitEntityRemoval=False
buffer.entityRemoved=self.env.event()
project=entity.capacityProject
periodDict[project.id]=entity.requiredCapacity # dict to be appended in the utilization list
# append the move in the detailedWorkPlan of the station
station.detailedWorkPlan.append({'time':self.env.now,
'operation':station.id,
'project':project.id,
'allocation':entity.requiredCapacity})
capacityAllocated+=entity.requiredCapacity
if self.checkIfProjectJustStartsInStation(project, station):
project.projectSchedule.append({
"stationId": station.id,
"entranceTime": self.env.now})
# lock the station
station.isLocked=True
# calculate the utilization
if capacityAvailable:
periodDict['utilization']=capacityAllocated/float(capacityAvailable)
else:
# TODO check how the utilization and mean utilization should be calculated if it is 0
periodDict['utilization']=0
# update the utilisationDict of the station
station.utilisationDict.append(periodDict)
# for every station update the remaining interval capacity so that it is ready for next loop
for station in G.CapacityStationList:
station.remainingIntervalCapacity.pop(0)
# invoked after entities have exited one station to create
# the corresponding entities to the following buffer
def createInCapacityStationBuffers(self):
# loop through the exits
for exit in G.CapacityStationExitList:
# if the exit received nothing currently there is nothing to do
if exit.currentlyObtainedEntities==[]:
continue
buffer=exit.nextCapacityStationBuffer # the next buffer
# if it is the end of the system there is nothing to do
if not buffer:
exit.currentlyObtainedEntities=[]
continue
previousStation=exit.previous[0] # the station the the entity just finished from
previousBuffer=previousStation.previous[0] # the buffer of the station
nextStation=buffer.next[0] # the next processing station
# for every entity calculate the new entity to be created in the next station and create it
for entity in exit.currentlyObtainedEntities:
project=entity.capacityProject
# if the entity exits from an assembly station
# and not all project is finished there, then do not create anything in the next
if previousBuffer.requireFullProject:
projectFinishedFromLast=True
for e in previousBuffer.getActiveObjectQueue():
if e.capacityProject==project:
projectFinishedFromLast=False
break
if not projectFinishedFromLast:
continue
entityCapacity=entity.requiredCapacity
previousRequirement=float(project.capacityRequirementDict[previousStation.id])
nextRequirement=float(project.capacityRequirementDict[nextStation.id])
# if the previous station was assembly then in the next the full project arrives
# so requires whatever the project requires
if previousBuffer.requireFullProject:
nextStationCapacityRequirement=nextRequirement
# else calculate proportionally
else:
proportion=nextRequirement/previousRequirement
nextStationCapacityRequirement=proportion*entityCapacity
entityToCreateName=entity.capacityProjectId+'_'+nextStation.objName+'_'+str(nextStationCapacityRequirement)
entityToCreate=CapacityEntity(name=entityToCreateName, capacityProjectId=entity.capacityProjectId,
requiredCapacity=nextStationCapacityRequirement)
entityToCreate.currentStation=buffer
entityToCreate.initialize()
import Globals
Globals.setWIP([entityToCreate]) #set the new components as wip
# reset the currently obtained entities list to empty
exit.currentlyObtainedEntities=[]
def calculateWhatIsToBeProcessed(self):
import Globals
# calculate what space is available
availableSpace=self.assemblySpace-self.calculateConsumedSpace()
assert availableSpace>=0, 'negative available space'
# list to hold the buffers that are already considered (due to shared resources)
alreadyConsideredBuffers = []
# loop through the capacity station buffers
for buffer in G.CapacityStationBufferList:
# if the buffer was considered before (due to shared resources) continue
if buffer in alreadyConsideredBuffers:
continue
alreadyConsideredBuffers.append(buffer)
sharedBuffers = []
station=buffer.next[0] # get the station
# find the stations that share resources with the one considered now
if station.sharedResources:
sharedStations = station.sharedResources.get('stationIds',[])
for element in sharedStations:
s = Globals.findObjectById(element)
b = s.previous[0]
sharedBuffers.append(b)
activeObjectQueue=buffer.getActiveObjectQueue()
# the entities considered should be the entities in the current buffer plus the ones in buffers
# of stations that share resources with the current one
entitiesConsidered=list(activeObjectQueue)
for b in sharedBuffers:
entitiesConsidered+=b.getActiveObjectQueue()
alreadyConsideredBuffers.append(b)
# sort entities according to due date of the project that each belongs to
entitiesConsidered.sort(key=lambda x: x.capacityProject.dueDate)
totalAvailableCapacity=station.remainingIntervalCapacity[0] # get the available capacity of the station
# for this interval
# list to keep entities that have not been already allocated
entitiesNotAllocated=list(entitiesConsidered)
allCapacityConsumed=False
# if there is no available capacity no need to do anything
if totalAvailableCapacity==0:
continue
while not allCapacityConsumed:
# list to keep entities that are within a threshold from the EDD
entitiesWithinThreshold=[]
# list to keep entities that are outside a threshold from the EDD
entitiesOutsideThreshold=[]
# get the EDD
EDD=float('inf')
for entity in entitiesNotAllocated:
if EDD>entity.capacityProject.dueDate:
EDD=entity.capacityProject.dueDate
# put the entities in the corresponding list according to their due date
for entity in entitiesNotAllocated:
if entity.capacityProject.dueDate-EDD<=self.dueDateThreshold:
entitiesWithinThreshold.append(entity)
else:
entitiesOutsideThreshold.append(entity)
# calculate the total capacity that is requested
totalRequestedCapacity=0
for entity in entitiesWithinThreshold:
# get buffer where the entity is and the station it requests to get in
entityBuffer=entity.currentStation
entityStation=entity.currentStation.next[0]
# entities that cannot start (due to space, need for assembly or earliest start)
# do not request for capacity
if self.checkIfProjectCanStartInStation(entity.capacityProject, entityStation) and\
(not self.checkIfProjectNeedsToBeAssembled(entity.capacityProject, entityBuffer))\
and self.checkIfThereIsEnoughSpace(entity, entityBuffer, availableSpace):
totalRequestedCapacity+=entity.requiredCapacity
# if there is enough capacity for all the entities set them that they all should move
if totalRequestedCapacity<=totalAvailableCapacity:
for entity in entitiesWithinThreshold:
# get buffer where the entity is and the station it requests to get in
entityBuffer=entity.currentStation
entityStation=entity.currentStation.next[0]
if self.checkIfProjectCanStartInStation(entity.capacityProject, entityStation) and\
(not self.checkIfProjectNeedsToBeAssembled(entity.capacityProject, entityBuffer))\
and self.checkIfThereIsEnoughSpace(entity, entityBuffer, availableSpace):
entity.shouldMove=True
# reduce the available space if there is need to
if entityBuffer.requireFullProject and \
(not self.checkIfProjectConsumesAssemblySpace(entity, entityBuffer)):
availableSpace-=entity.capacityProject.assemblySpaceRequirement
assert availableSpace>=0, 'negative available space'
# remove the entity from the none allocated ones
entitiesNotAllocated.remove(entity)
# check if all the capacity is consumed to update the flag and break the loop
if totalRequestedCapacity==totalAvailableCapacity:
# the capacity will be 0 since we consumed it all
totalAvailableCapacity=0
allCapacityConsumed=True
# if we still have available capacity
else:
# check in the entities outside the threshold if there is one or more that can be moved
haveMoreEntitiesToAllocate=False
for entity in entitiesOutsideThreshold:
# get buffer where the entity is and the station it requests to get in
entityBuffer=entity.currentStation
entityStation=entity.currentStation.next[0]
if self.checkIfProjectCanStartInStation(entity.capacityProject, entityStation) and\
(not self.checkIfProjectNeedsToBeAssembled(entity.capacityProject, entityBuffer))\
and self.checkIfThereIsEnoughSpace(entity, entityBuffer, availableSpace):
haveMoreEntitiesToAllocate=True
break
# otherwise we have to calculate the capacity for next loop
# the remaining capacity will be decreased by the one that was originally requested
totalAvailableCapacity-=totalRequestedCapacity
# if we have more entities break
if not haveMoreEntitiesToAllocate:
break
# else calculate the capacity for every entity and create the entities
else:
allCapacityConsumed=True
entitiesToBeBroken=list(entitiesWithinThreshold)
# we sort the entities so the ones that can finish in current period (if any) go in front
entitiesToBeBroken.sort(key=lambda \
x: self.checkIfAProjectCanBeFinishedInStation(x,x.currentStation.next[0],
totalAvailableCapacity) \
and self.prioritizeIfCanFinish,
reverse=True)
# loop through the entities
for entity in entitiesToBeBroken:
# get buffer where the entity is and the station it requests to get in
entityBuffer=entity.currentStation
entityStation=entity.currentStation.next[0]
# consider only entities that can move - not those waiting for assembly or earliest start
if self.checkIfProjectCanStartInStation(entity.capacityProject, entityStation) and\
(not self.checkIfProjectNeedsToBeAssembled(entity.capacityProject, entityBuffer)) and\
self.checkIfThereIsEnoughSpace(entity, entityBuffer, availableSpace):
# if we prioritize an entity that can completely finish then check for this
if self.checkIfAProjectCanBeFinishedInStation(entity, entityStation, totalAvailableCapacity)\
and self.prioritizeIfCanFinish:
# set that the entity can move
entity.shouldMove=True
# reduce the available space if there is need to
if entityBuffer.requireFullProject and \
(not self.checkIfProjectConsumesAssemblySpace(entity, entityBuffer)):
availableSpace-=entity.capacityProject.assemblySpaceRequirement
assert availableSpace>=0, 'negative available space'
# update the values
totalAvailableCapacity-=entity.requiredCapacity
totalRequestedCapacity-=entity.requiredCapacity
# else break the entity according to rule
else:
self.breakEntity(entity, entityBuffer, entityStation,
totalAvailableCapacity, totalRequestedCapacity)
# reduce the available space if there is need to
if entityBuffer.requireFullProject and \
(not self.checkIfProjectConsumesAssemblySpace(entity, entityBuffer)):
availableSpace-=entity.capacityProject.assemblySpaceRequirement
assert availableSpace>=0, 'negative available space'
# breaks an entity in the part that should move and the one that should stay
def breakEntity(self, entity, buffer, station, totalAvailableCapacity, totalRequestedCapacity):
# calculate what is the capacity that should proceed and what that should remain
capacityToMove=totalAvailableCapacity*(entity.requiredCapacity)/float(totalRequestedCapacity)
capacityToStay=entity.requiredCapacity-capacityToMove
# remove the capacity entity by the buffer so that the broken ones are created
buffer.getActiveObjectQueue().remove(entity)
entityToMoveName=entity.capacityProjectId+'_'+station.objName+'_'+str(capacityToMove)
entityToMove=CapacityEntity(name=entityToMoveName, capacityProjectId=entity.capacityProjectId, requiredCapacity=capacityToMove)
entityToMove.initialize()
entityToMove.currentStation=buffer
entityToMove.shouldMove=True
entityToStayName=entity.capacityProjectId+'_'+station.objName+'_'+str(capacityToStay)
entityToStay=CapacityEntity(name=entityToStayName, capacityProjectId=entity.capacityProjectId, requiredCapacity=capacityToStay)
entityToStay.initialize()
entityToStay.currentStation=buffer
import Globals
Globals.setWIP([entityToMove,entityToStay]) #set the new components as wip
# merges the capacity entities if they belong to the same project
def mergeEntities(self):
# loop through the capacity station buffers
for buffer in G.CapacityStationBufferList:
nextStation=buffer.next[0]
projectList=[]
# loop through the entities to see what projects lie in the buffer
for entity in buffer.getActiveObjectQueue():
if entity.capacityProject not in projectList:
projectList.append(entity.capacityProject)
for project in projectList:
entitiesToBeMerged=[]
for entity in buffer.getActiveObjectQueue():
if entity.capacityProject==project:
entitiesToBeMerged.append(entity)
totalCapacityRequirement=0
# if the buffer acts as assembly there is no need to calculate the total capacity requirement,
# it will be the one that the project has as a total for this station
if buffer.requireFullProject:
# find what has been already processed
alreadyProcessed=0
for record in nextStation.detailedWorkPlan:
if record['project']==project.id:
alreadyProcessed+=float(record['allocation'])
totalCapacityRequirement=project.capacityRequirementDict[nextStation.id]-alreadyProcessed
# else calculate the total capacity requirement by adding the one each entity requires
else:
for entity in entitiesToBeMerged:
totalCapacityRequirement+=entity.requiredCapacity
# erase the Entities to create the merged one
for entity in entitiesToBeMerged:
buffer.getActiveObjectQueue().remove(entity)
# create the merged entity
entityToCreateName=entity.capacityProjectId+'_'+nextStation.objName+'_'+str(totalCapacityRequirement)
entityToCreate=CapacityEntity(name=entityToCreateName, capacityProjectId=project.id,
requiredCapacity=totalCapacityRequirement)
entityToCreate.currentStation=buffer
entityToCreate.initialize()
import Globals
Globals.setWIP([entityToCreate]) #set the new components as wip
# checks if the system is empty so that the simulation can be stopped
def checkIfSystemEmpty(self):
for object in G.CapacityStationList+G.CapacityStationBufferList+G.CapacityStationExitList:
if len(object.getActiveObjectQueue()):
return False
return True
# checks if a project is just starting in station
def checkIfProjectJustStartsInStation(self, project, station):
for entry in project.projectSchedule:
if entry['stationId']==station.id:
return False
return True
# checks if a project cannot move because it needs to be assembled first
def checkIfProjectNeedsToBeAssembled(self, project, buffer):
# if we are not in assembly return false
if not buffer.requireFullProject:
return False
# if project is already assembled return false
if self.checkIfProjectAssembledInBuffer(project, buffer):
return False
# at any other case return true
return True
# checks if the given project is all in the buffer
def checkIfProjectAssembledInBuffer(self, project, buffer):
# loop through all the stations of the system
for object in G.CapacityStationList+G.CapacityStationBufferList+G.CapacityStationExitList:
# skip the given buffer
if object is buffer:
continue
# if there is one entity from the same project which we check somewhere else return false
for entity in object.getActiveObjectQueue():
if entity.capacityProject==project:
return False
# if nothing was found return true
return True
# checks if the given project can start in the station or not because there is an earliest start defined
def checkIfProjectCanStartInStation(self, project, station):
earliestStartInStation=project.earliestStartDict.get(station.id, 0)
if self.env.now<earliestStartInStation:
return False
return True
# checks if the whole project can be finished in one station in the next time period
def checkIfAProjectCanBeFinishedInStation(self, entity, station, availableCapacity):
required=entity.requiredCapacity
alreadyWorked=entity.capacityProject.alreadyWorkedDict[station.id]
total=entity.capacityProject.capacityRequirementDict[station.id]
# return true if all the work can be finished and if there is available capacity
if total-(alreadyWorked+required)<0.001 and availableCapacity>=required: # a small value to avoid mistakes due to rounding
return True
return False
# returns true if there is enough space for the entity to move
def checkIfThereIsEnoughSpace(self, entity, buffer, availableSpace):
if buffer.requireFullProject:
# if the project already consumes assembly space then there is enough space for it
if self.checkIfProjectConsumesAssemblySpace(entity, buffer):
return True
# else check if there is enough space
return entity.capacityProject.assemblySpaceRequirement<=availableSpace
# if the station is not assembly then return true
return True
# sorts the buffers so if they have shared resources the ones with highest priority will go in front
def sortBuffers(self):
for buffer in G.CapacityStationBufferList:
station=buffer.next[0]
buffer.sharedPriority=station.sharedResources.get('priority', -float('inf'))
G.CapacityStationBufferList.sort(key=lambda x: x.sharedPriority, reverse=True)
# calculates the space that is already consumed before the allocation for current period
def calculateConsumedSpace(self):
consumedSpace=0
# loop in the buffers and find projects that have started assembly without having been finished
# add what they consume
for buffer in G.CapacityStationBufferList:
station=buffer.next[0]
for entity in buffer.getActiveObjectQueue():
if self.checkIfProjectConsumesAssemblySpace(entity, buffer):
consumedSpace+=entity.capacityProject.assemblySpaceRequirement
return consumedSpace
# checks if a project already consumes assembly space because assembly work started in a previous period
# and was not completed
def checkIfProjectConsumesAssemblySpace(self, entity, buffer):
if buffer.requireFullProject:
station=buffer.next[0]
project=entity.capacityProject
projectRequirement=project.capacityRequirementDict[station.id]
if projectRequirement>entity.requiredCapacity:
return True
return False
\ No newline at end of file
# ===========================================================================
# 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 6 June 2013
@author: George
'''
'''
the exit of the capacity station. Only change from buffer that it can be blocked.
'''
from Exit import Exit
import simpy
# ===========================================================================
# the CapacityStationExit object
# ===========================================================================
class CapacityStationExit(Exit):
#===========================================================================
# the __init__ method of the CapacityStationExit
#===========================================================================
def __init__(self, id, name=None, nextCapacityStationBufferId=None,**kw):
Exit.__init__(self, id, name)
self.isLocked=True
self.nextCapacityStationBufferId=nextCapacityStationBufferId # the id of the next station. If it is None it
# means it is the end of the system.
self.nextCapacityStationBuffer=None # the next buffer. If it is None it
from Globals import G
G.CapacityStationExitList.append(self)
# means it is the end of the system.
def initialize(self):
Exit.initialize(self)
self.isLocked=True
# list that contains the entities that are just obtained so that they can be
# moved to the next buffer
self.currentlyObtainedEntities=[]
# find the next buffer
if self.nextCapacityStationBufferId:
from Globals import G
# find the project that the capacity entity is part of
for capacityStationBuffer in G.CapacityStationBufferList:
if capacityStationBuffer.id==self.nextCapacityStationBufferId:
self.nextCapacityStationBuffer=capacityStationBuffer
break
def canAccept(self, callerObject=None):
if self.isLocked:
return False
return Exit.canAccept(self)
# =======================================================================
# outputs results to JSON File
# =======================================================================
def outputResultsJSON(self):
# output results only for the last exit
if not self.nextCapacityStationBuffer:
Exit.outputResultsJSON(self)
# extend so that it updates alreadyWorkedDict of the project
def getEntity(self):
activeEntity=Exit.getEntity(self)
alreadyWorkedDict=activeEntity.capacityProject.alreadyWorkedDict
stationId=self.giver.id
alreadyWorkedDict[stationId]+=activeEntity.requiredCapacity
\ No newline at end of file
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