Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
dream
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
dream
Commits
c94bdc63
Commit
c94bdc63
authored
Jun 05, 2019
by
Georgios Dagkakis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code for experiments
parent
50a4e123
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
666 additions
and
20 deletions
+666
-20
dream/platform/static/manifest.appcache
dream/platform/static/manifest.appcache
+1
-1
dream/plugins/ACO.py
dream/plugins/ACO.py
+7
-1
dream/plugins/Batches/BatchesACO.py
dream/plugins/Batches/BatchesACO.py
+2
-0
dream/plugins/Batches/BatchesStochasticACO.py
dream/plugins/Batches/BatchesStochasticACO.py
+27
-6
dream/simulation/CoreObject.py
dream/simulation/CoreObject.py
+5
-0
dream/simulation/Examples/MilkPlant2.xls
dream/simulation/Examples/MilkPlant2.xls
+0
-0
dream/simulation/Examples/SeminarModels.py
dream/simulation/Examples/SeminarModels.py
+71
-0
dream/simulation/Examples/TestConveyer.xls
dream/simulation/Examples/TestConveyer.xls
+0
-0
dream/simulation/Exit.py
dream/simulation/Exit.py
+4
-0
dream/simulation/OperatedPoolBroker.py
dream/simulation/OperatedPoolBroker.py
+13
-4
dream/simulation/SkilledOperatorRouter.py
dream/simulation/SkilledOperatorRouter.py
+21
-8
dream/simulation/WhereToRuleSkilledRouter.py
dream/simulation/WhereToRuleSkilledRouter.py
+515
-0
No files found.
dream/platform/static/manifest.appcache
View file @
c94bdc63
CACHE MANIFEST
# This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator
# Time: Wed
Sep 16 2015 18:23:50 GMT+0200 (CES
T)
# Time: Wed
Nov 28 2018 10:09:45 GMT+0000 (GM
T)
CACHE:
daff/index.html
...
...
dream/plugins/ACO.py
View file @
c94bdc63
...
...
@@ -41,6 +41,7 @@ class ACO(plugin.ExecutionPlugin):
def
run
(
self
,
data
):
"""Preprocess the data.
"""
self
.
logger
.
info
(
"ACO"
)
distributor_url
=
data
[
'general'
].
get
(
'distributorURL'
)
distributor
=
None
if
distributor_url
:
...
...
@@ -108,7 +109,12 @@ class ACO(plugin.ExecutionPlugin):
else
:
# synchronous
for
ant
in
scenario_list
:
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
self
.
logger
.
info
(
"%s running"
%
ant
[
'key'
])
try
:
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
except
:
self
.
logger
.
info
(
"%s failed"
%
ant
[
'key'
])
ant
[
'result'
]
=
{
'result_list'
:
[
'fail'
]}
else
:
# asynchronous
self
.
logger
.
info
(
"Registering a job for %s scenarios"
%
len
(
scenario_list
))
...
...
dream/plugins/Batches/BatchesACO.py
View file @
c94bdc63
...
...
@@ -18,6 +18,8 @@ class BatchesACO(ACO):
"""Calculate the score of this ant.
"""
result
,
=
ant
[
'result'
][
'result_list'
]
#read the result as JSON
if
result
==
'fail'
:
return
0
#loop through the elements
for
element
in
result
[
'elementList'
]:
element_family
=
element
.
get
(
'family'
,
None
)
...
...
dream/plugins/Batches/BatchesStochasticACO.py
View file @
c94bdc63
...
...
@@ -39,6 +39,8 @@ class BatchesStochasticACO(BatchesACO):
"""Calculate the score of this ant.
"""
result
,
=
ant
[
'result'
][
'result_list'
]
#read the result as JSON
if
result
==
'fail'
:
return
0
#loop through the elements
for
element
in
result
[
'elementList'
]:
element_family
=
element
.
get
(
'family'
,
None
)
...
...
@@ -68,6 +70,7 @@ class BatchesStochasticACO(BatchesACO):
def
run
(
self
,
data
):
"""Preprocess the data.
"""
self
.
logger
.
info
(
"Stoch ACO"
)
self
.
outputFile
=
xlwt
.
Workbook
()
self
.
outputSheet
=
self
.
outputFile
.
add_sheet
(
'ACO Results'
,
cell_overwrite_ok
=
True
)
self
.
rowIndex
=
0
...
...
@@ -141,6 +144,7 @@ class BatchesStochasticACO(BatchesACO):
for
i
in
range
(
int
(
data
[
"general"
][
"numberOfGenerations"
])):
self
.
outputSheet
.
write
(
self
.
rowIndex
,
0
,
'Generation '
+
str
(
i
+
1
))
self
.
rowIndex
+=
1
self
.
logger
.
info
(
"Generation %s"
%
self
.
rowIndex
)
antsInCurrentGeneration
=
[]
scenario_list
=
[]
# for the distributor
# number of ants created per generation
...
...
@@ -190,8 +194,13 @@ class BatchesStochasticACO(BatchesACO):
self
.
outputSheet
.
write
(
self
.
rowIndex
,
1
,
'running deterministic'
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
2
,
ant
[
'key'
])
self
.
rowIndex
+=
1
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
ant
[
'score'
]
=
self
.
_calculateAntScore
(
ant
)
try
:
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
ant
[
'score'
]
=
self
.
_calculateAntScore
(
ant
)
except
:
self
.
logger
.
info
(
"%s failed"
%
ant
[
'key'
])
ant
[
'result'
]
=
{
'result_list'
:
[
'fail'
]}
ant
[
'score'
]
=
0
ant
[
'evaluationType'
]
=
'deterministic'
self
.
outputSheet
.
write
(
self
.
rowIndex
,
2
,
'Units Throughput'
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
3
,
-
ant
[
'score'
])
...
...
@@ -220,9 +229,14 @@ class BatchesStochasticACO(BatchesACO):
self
.
outputSheet
.
write
(
self
.
rowIndex
,
1
,
'running stochastic for '
+
str
(
numberOfReplicationsInGeneration
)
+
' replications'
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
2
,
ant
[
'key'
])
self
.
rowIndex
+=
1
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
try
:
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
ant
[
'score'
]
=
self
.
calculateStochasticAntScore
(
ant
)
except
:
self
.
logger
.
info
(
"%s failed"
%
ant
[
'key'
])
ant
[
'result'
]
=
{
'result_list'
:
[
'fail'
]}
ant
[
'score'
]
=
0
ant
[
'evaluationType'
]
=
'stochastic'
ant
[
'score'
]
=
self
.
calculateStochasticAntScore
(
ant
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
2
,
'Average Units Throughput'
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
3
,
-
ant
[
'score'
])
self
.
rowIndex
+=
1
...
...
@@ -281,8 +295,15 @@ class BatchesStochasticACO(BatchesACO):
self
.
outputSheet
.
write
(
self
.
rowIndex
,
1
,
'running stochastic for '
+
str
(
numberOfReplicationsInTheEnd
)
+
' replications'
)
self
.
outputSheet
.
write
(
self
.
rowIndex
,
2
,
ant
[
'key'
])
self
.
rowIndex
+=
1
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
ant
[
'score'
]
=
self
.
calculateStochasticAntScore
(
ant
)
try
:
ant
[
'result'
]
=
self
.
runOneScenario
(
ant
[
'input'
])[
'result'
]
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
,
3
,
-
ant
[
'score'
])
self
.
rowIndex
+=
1
...
...
dream/simulation/CoreObject.py
View file @
c94bdc63
...
...
@@ -347,6 +347,11 @@ class CoreObject(ManPyObject):
# gets an entity from the giver
# =======================================================================
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
#(after the sorting of the entities in the queue of the giver object)
# activeObject=self.getActiveObject()
...
...
dream/simulation/Examples/MilkPlant2.xls
0 → 100644
View file @
c94bdc63
File added
dream/simulation/Examples/SeminarModels.py
0 → 100644
View file @
c94bdc63
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
()
dream/simulation/Examples/TestConveyer.xls
0 → 100644
View file @
c94bdc63
File added
dream/simulation/Exit.py
View file @
c94bdc63
...
...
@@ -105,6 +105,10 @@ class Exit(CoreObject):
# gets an entity from the predecessor
# =======================================================================
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
# if the entity is in the G.pendingEntities list then remove it from there
from
Globals
import
G
...
...
dream/simulation/OperatedPoolBroker.py
View file @
c94bdc63
...
...
@@ -30,6 +30,7 @@ Models an Interruption that handles the operating of a Station by an ObjectResou
import
simpy
from
ObjectInterruption
import
ObjectInterruption
# from SimPy.Simulation import waituntil, now, hold, request, release, waitevent
import
logging
# ===========================================================================
# Class that handles the Operator Behavior
...
...
@@ -52,7 +53,8 @@ class Broker(ObjectInterruption):
# flag that shows if broker was called to request or release operator.
# Machine updates this before calling the broker
self
.
invokeType
=
'request'
self
.
logger
=
logging
.
getLogger
(
"dream.platform"
)
#===========================================================================
# the initialize method
#===========================================================================
...
...
@@ -77,8 +79,9 @@ class Broker(ObjectInterruption):
# TODO: add new broker event - brokerIsCalled
self
.
expectedSignals
[
'isCalled'
]
=
1
self
.
logger
.
info
(
"!--- %s %s Waiting isCalled1 ----!"
%
(
self
.
env
.
now
,
self
.
id
))
yield
self
.
isCalled
self
.
logger
.
info
(
"!--- %s %s Got isCalled1 ----!"
%
(
self
.
env
.
now
,
self
.
id
))
transmitter
,
eventTime
=
self
.
isCalled
.
value
assert
eventTime
==
self
.
env
.
now
,
'the broker should be granted control instantly'
self
.
isCalled
=
self
.
env
.
event
()
...
...
@@ -106,8 +109,9 @@ class Broker(ObjectInterruption):
self
.
victim
.
printTrace
(
self
.
victim
.
id
,
waitEvent
=
'(resourceIsAvailable broker)'
)
self
.
expectedSignals
[
'resourceAvailable'
]
=
1
self
.
logger
.
info
(
"!--- %s %s Waiting resourceAvailable ----!"
%
(
self
.
env
.
now
,
self
.
id
))
yield
self
.
resourceAvailable
self
.
logger
.
info
(
"!--- %s %s Got resourceAvailable ----!"
%
(
self
.
env
.
now
,
self
.
id
))
transmitter
,
eventTime
=
self
.
resourceAvailable
.
value
self
.
resourceAvailable
=
self
.
env
.
event
()
...
...
@@ -132,7 +136,10 @@ class Broker(ObjectInterruption):
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
self
.
logger
.
info
(
"!--- %s %s Got request ----!"
%
(
self
.
env
.
now
,
self
.
id
))
# update the operator workingStation
self
.
victim
.
currentOperator
.
workingStation
=
self
.
victim
self
.
victim
.
printTrace
(
self
.
victim
.
currentOperator
.
objName
,
startWork
=
self
.
victim
.
id
)
...
...
@@ -165,8 +172,10 @@ class Broker(ObjectInterruption):
# wait till the processing is over
self
.
expectedSignals
[
'isCalled'
]
=
1
self
.
logger
.
info
(
"!--- %s %s Waiting isCalled2 ----!"
%
(
self
.
env
.
now
,
self
.
id
))
yield
self
.
isCalled
self
.
logger
.
info
(
"!--- %s %s Got isCalled2 ----!"
%
(
self
.
env
.
now
,
self
.
id
))
transmitter
,
eventTime
=
self
.
isCalled
.
value
assert
eventTime
==
self
.
env
.
now
,
'the broker should be granted control instantly'
self
.
isCalled
=
self
.
env
.
event
()
...
...
dream/simulation/SkilledOperatorRouter.py
View file @
c94bdc63
...
...
@@ -87,8 +87,9 @@ class SkilledRouter(Router):
# wait until the router is called
self
.
expectedSignals
[
'isCalled'
]
=
1
self
.
logger
.
info
(
"!--- %s %s WAITING isCalled ----!"
%
(
self
.
env
.
now
,
self
.
id
))
yield
self
.
isCalled
self
.
logger
.
info
(
"!--- %s %s GOT isCalled ----!"
%
(
self
.
env
.
now
,
self
.
id
))
transmitter
,
eventTime
=
self
.
isCalled
.
value
self
.
isCalled
=
self
.
env
.
event
()
...
...
@@ -223,8 +224,11 @@ class SkilledRouter(Router):
import
time
startLP
=
time
.
time
()
if
LPFlag
:
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
))
#
self.logger.info('---> ' + str(self.env.now))
solution
=
{}
maxWIP
=-
1
minWIP
=
float
(
'inf'
)
...
...
@@ -239,7 +243,7 @@ class SkilledRouter(Router):
# first, find the machine with max wip
for
stationId
in
sorted_station_id_list
:
stationDict
=
self
.
availableStationsDict
.
get
(
stationId
,
None
)
self
.
logger
.
info
(
stationDict
)
#
self.logger.info(stationDict)
if
not
stationDict
:
continue
wip
=
stationDict
[
'WIP'
]
...
...
@@ -250,11 +254,12 @@ class SkilledRouter(Router):
]
assert
len
(
assignedOperatorList
)
in
(
0
,
1
),
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
:
machineWithMaxWIP
=
stationId
maxWIP
=
wip
self
.
logger
.
info
(
machineWithMaxWIP
)
#
self.logger.info(machineWithMaxWIP)
solution
=
{}
# First, search for an operator that was not
# previously assigned, and can handle the maxWIP station
...
...
@@ -376,7 +381,7 @@ class SkilledRouter(Router):
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
:
...
...
@@ -398,7 +403,7 @@ class SkilledRouter(Router):
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
]
:
if
not
(
self
.
previousSolution
[
operatorID
]
==
solution
[
operatorID
]
and
operator
==
station
.
currentOperator
)
:
self
.
toBeSignalled
.
append
(
station
)
else
:
self
.
toBeSignalled
.
append
(
station
)
...
...
@@ -412,13 +417,16 @@ class SkilledRouter(Router):
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
)
self
.
logger
.
info
(
"!--- %s toBeSignalled: %s ----!"
%
(
self
.
env
.
now
,
len
(
toBeSignalled
)))
for
station
in
toBeSignalled
:
# check if the operator that the station waits for is free
operator
=
station
.
operatorToGet
...
...
@@ -438,7 +446,10 @@ class SkilledRouter(Router):
self
.
expectedFinishSignalsDict
[
station
.
id
]
=
signal
self
.
expectedFinishSignals
.
append
(
signal
)
while
self
.
expectedFinishSignals
:
self
.
logger
.
info
(
"!--- %s %s WAITING expectedFinishSignals ----!"
%
(
self
.
env
.
now
,
self
.
id
))
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
:
if
signal
in
receivedEvent
:
transmitter
,
eventTime
=
signal
.
value
...
...
@@ -488,6 +499,8 @@ class SkilledRouter(Router):
# =======================================================================
def
signalStation
(
self
,
station
,
operator
):
# 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
.
expectedSignals
[
'resourceAvailable'
]:
self
.
sendSignal
(
receiver
=
station
.
broker
,
signal
=
station
.
broker
.
resourceAvailable
)
...
...
dream/simulation/WhereToRuleSkilledRouter.py
0 → 100644
View file @
c94bdc63
# ===========================================================================
# 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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment