Commit fd670042 authored by Georgios Dagkakis's avatar Georgios Dagkakis

offer phase application and plugins added

parent 150dd66a
'''
Created on 1 Aug 2015
@author: Anna
'''
from copy import copy
import json
import time
import random
import operator
import datetime
from dream.plugins import plugin
class AddOfferPhaseGenerator(plugin.InputPreparationPlugin):
""" Input preparation
adds an EventGenerator that will call the Offer Phase model once
"""
def preprocess(self, data):
nodes=data['graph']['node']
data_uri_encoded_input_data = data['input'].get(self.configuration_dict['input_id_json'], {})
data_uri_encoded_workplan_data = data['input'].get(self.configuration_dict['input_id_workplan'], {})
algorithmAttributes=copy(data['general'])
nodes['OPG']={
"name": "OfferPhaseGenerator",
"prioritizeIfCanFinish": 1,
"interval": 1,
"start": 0,
"stop": 0.5,
"_class": "dream.simulation.EventGenerator.EventGenerator",
"method": "dream.simulation.applications.FrozenSimulation.exeSim.exeSim",
"argumentDict": {'jsonInput':data_uri_encoded_input_data, 'workplanInput':data_uri_encoded_workplan_data}
}
return data
\ No newline at end of file
'''
Created on 1 Aug 2015
@author: Anna
'''
from dream.plugins import plugin
class PostProcessingOfferPhase(plugin.OutputPreparationPlugin):
""" Output the result of offer phase in a format compatible with
Output_viewDownloadFile
"""
def postprocess(self, data):
# XXX the event generator should store its result in data and not in global
# variable.
from dream.simulation.applications.FrozenSimulation.Globals import G
data['result']['result_list'][-1][self.configuration_dict['output_id']] = {
'name': 'Result.xlsx',
'mime_type': 'application/vnd.ms-excel',
'data': G.tabSchedule.xlsx.encode('base64')
}
return data
\ 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/>.
# ===========================================================================
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
\ No newline at end of file
'''
Created on 4 Sep 2015
@author: Anna
'''
from dream.plugins import plugin
class projTabular(plugin.OutputPreparationPlugin):
""" Output the projection completion date in a tab
"""
def postprocess(self, data):
data['result']['result_list'][0]['exit_output'] = [['Project', 'Earliest Completion Date']]
from dream.simulation.applications.FrozenSimulation.Globals import G
for proj in G.completionDate.keys():
data['result']['result_list'][0]['exit_output'].append([proj, G.completionDate[proj]])
return data
\ No newline at end of file
'''
Created on 1 Aug 2015
@author: Anna
'''
from dream.plugins import plugin
class PostProcessingOfferPhase(plugin.OutputPreparationPlugin):
""" Output the result of offer phase in a format compatible with
Output_viewDownloadFile
"""
def postprocess(self, data):
# XXX the event generator should store its result in data and not in global
# variable.
from dream.simulation.applications.FrozenSimulation.Globals import G
data['result']['result_list'][-1][self.configuration_dict['output_id']] = {
'name': 'Result.xlsx',
'mime_type': 'application/vnd.ms-excel',
'data': G.tabSchedule.xlsx.encode('base64')
}
return data
\ No newline at end of file
'''
Created on 31 Aug 2015
@author: Anna
'''
import tablib
class G:
Schedule={}
seqPrjDone = None
resAvailability = None
MachPool = None
PMPool = None
Projects = None
xlreftime = None
reportResults = tablib.Databook()
tabSchedule = tablib.Dataset(title='Schedule')
tabSchedule.headers = (['Project', 'Part', 'Task ID', 'Station', 'Operator', 'Start Time', 'End Time'])
OrderDates = None
completionDate = None
# ===========================================================================
# 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/>.
# ===========================================================================
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
\ No newline at end of file
'''
Created on 20 Aug 2015
@author: Anna
'''
from jsonReader import importInput
from findSequence import findSequence
from timeCalculations import availableTimeInterval_MA, updateAvailTime, availableTimeInterval_MM, availableTimeInterval_Manual
from operator import itemgetter
from copy import deepcopy
from Globals import G
import datetime as dt
def manual_allocation(currentOp):
tStart = currentOp['minStartTime'] # earliest start date for current operation
remPT = dt.timedelta(hours=currentOp['manualTime'])
print 'in manual allocation', currentOp['id']
print 'tStart manual', tStart, remPT
while remPT > dt.timedelta(seconds=0):
startTimeMach = [] # collects earliest keyDate for machines
startTimeOp = [] # collects earliest keyDate for operators
# find machines available time intervals
for mach in G.MachPool[currentOp['operation']]:
res = availableTimeInterval_Manual(remPT, tStart, G.resAvailability[mach])
startTimeMach.append({'mach':mach, 'start':res[0], 'avPT':res[1]*(-1)})
# sort available time
sorted_startTimeMach = sorted(startTimeMach, key=itemgetter('start', 'avPT'))
tStart = max(sorted_startTimeMach[0]['start'],tStart)
# verify whether PM are available in the same time
for pm in G.PMPool[currentOp['operation']]:
res = availableTimeInterval_Manual(remPT, tStart, G.resAvailability[pm])
startTimeOp.append({'pm':pm, 'start':res[0], 'avPT':res[1]*(-1)})
# sort available time
sorted_startTimeOp = sorted(startTimeOp, key=itemgetter('start', 'avPT'))
print tStart
print 'sort mach', sorted_startTimeMach
print 'sort pm', sorted_startTimeOp
# calculate available PT
if sorted_startTimeOp[0]['start'] <= tStart:
print 'first op'
availablePT = min(sorted_startTimeMach[0]['avPT']*(-1), sorted_startTimeOp[0]['avPT']*(-1), remPT)
elif sorted_startTimeOp[0]['start'] < tStart + sorted_startTimeMach[0]['avPT']:
print 'sec op'
tEnd = min(tStart+sorted_startTimeMach[0]['avPT'], sorted_startTimeOp[0]['start']+sorted_startTimeOp[0]['avPT'])
tStart = sorted_startTimeOp[0]['start']
availablePT = min(tEnd - tStart, remPT)
else:
print '3 op'
availablePT = dt.timedelta(seconds=0)
tStart = sorted_startTimeOp[0]['start']
# update remaining PT
remPT -= availablePT
print 'fine all', tStart, availablePT, remPT
if availablePT > dt.timedelta(seconds=0):
# update machine and operator availability
G.resAvailability[sorted_startTimeMach[0]['mach']] = updateAvailTime(sorted_startTimeMach[0]['start'], availablePT, tStart,
G.resAvailability[sorted_startTimeMach[0]['mach']])
G.resAvailability[sorted_startTimeOp[0]['pm']] = updateAvailTime(sorted_startTimeOp[0]['start'], availablePT, tStart,
G.resAvailability[sorted_startTimeOp[0]['pm']])
# aggiorna schedule
if currentOp['id'] not in G.Schedule.keys():
G.Schedule[currentOp['id']]={}
G.Schedule[currentOp['id']]['startDate'] = tStart
tEnd = tStart + availablePT
G.Schedule[currentOp['id']]['endDate'] = tEnd
G.Schedule[currentOp['id']].setdefault('rList',{})[(tStart,tEnd)] = {'mach':sorted_startTimeMach[0]['mach'],'operator':sorted_startTimeOp[0]['pm']}
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['id'],sorted_startTimeMach[0]['mach'],sorted_startTimeOp[0]['pm'],tStart,tEnd])
if currentOp['preID'] != None:
G.Schedule[currentOp['preID']] = G.Schedule[currentOp['id']]
if G.completionDate[currentOp['project']] < tEnd:
G.completionDate[currentOp['project']] = tEnd
tStart = tEnd
print currentOp['id'], G.Schedule[currentOp['id']]
def MAM_allocation(currentOp):
tStart = currentOp['minStartTime'] # earliest start date for current operation
print 'tStart', tStart
remPT = currentOp['manualTime'] + currentOp['autoTime']
while remPT:
startTimeMach = [] # collects earliest keyDate for machines
startTimeOp = [] # collects earliest keyDate for operators
# find machines available time intervals
for mach in G.MachPool[currentOp['operation']]:
# find available time (availableTimeInterval_MA)
print 'man', currentOp['manualTime']
mTime = dt.timedelta(hours=currentOp['manualTime'])
aTime = dt.timedelta(hours=currentOp['autoTime'])
print 'mach av', mach, G.resAvailability[mach]
if currentOp['mode'] == 'MM':
res = availableTimeInterval_MM(mTime, aTime, tStart, G.resAvailability[mach])
startTimeMach.append({'mach':mach, 'start':res[0], 'eqPT':res[1]})
else:
res = availableTimeInterval_MA(mTime, aTime, tStart, G.resAvailability[mach])
#startTimeMach.append({'mach':mach, 'start':res, 'eqPT':mTime+aTime})
startTimeMach.append({'mach':mach, 'start':res[0], 'eqPT':res[1]+aTime})
print 'start time mach', startTimeMach
# sort available time
sorted_startTimeMach = sorted(startTimeMach, key=itemgetter('start', 'eqPT'))
tStart = max(sorted_startTimeMach[0]['start'],tStart)
print 'mach tent', sorted_startTimeMach[0]['mach'], tStart
# verify whether PM are available in the same time
for pm in G.PMPool[currentOp['operation']]:
print 'operator', pm
#find available time
if currentOp['mode'] == 'MM':
res = availableTimeInterval_MM(mTime, aTime, tStart, G.resAvailability[pm])
startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':res[1]})
else:
res = availableTimeInterval_MA(mTime, dt.timedelta(hours=0), tStart, G.resAvailability[pm])
# startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':mTime})
startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':res[1]})
# sort available time
sorted_startTimeOp = sorted(startTimeOp, key=itemgetter('start', 'eqPT'))
if sorted_startTimeOp[0]['start'] <= tStart:
remPT = 0
else:
tStart = sorted_startTimeOp[0]['start']
print 'machine chosen', sorted_startTimeMach[0]['mach']
print 'operator chosen', sorted_startTimeOp[0]['pm'], sorted_startTimeOp
print G.resAvailability[sorted_startTimeMach[0]['mach']]
print G.resAvailability[sorted_startTimeOp[0]['pm']]
# update machine availability
G.resAvailability[sorted_startTimeMach[0]['mach']] = updateAvailTime(sorted_startTimeMach[0]['start'], sorted_startTimeMach[0]['eqPT'], tStart,
G.resAvailability[sorted_startTimeMach[0]['mach']])
# update operator availability
G.resAvailability[sorted_startTimeOp[0]['pm']] = updateAvailTime(sorted_startTimeOp[0]['start'], sorted_startTimeOp[0]['eqPT'], tStart,
G.resAvailability[sorted_startTimeOp[0]['pm']])
# aggiorna schedule
G.Schedule.setdefault(currentOp['id'],{})
G.Schedule[currentOp['id']]['startDate'] = tStart
tEnd = tStart + sorted_startTimeMach[0]['eqPT']
G.Schedule[currentOp['id']]['endDate'] = tEnd
G.Schedule[currentOp['id']].setdefault('rList',{})[(tStart,tEnd)] = {'mach':sorted_startTimeMach[0]['mach'],'operator':sorted_startTimeOp[0]['pm']}
if currentOp['preID'] != None:
G.Schedule[currentOp['preID']] = G.Schedule[currentOp['id']]
if G.completionDate[currentOp['project']] < tEnd:
G.completionDate[currentOp['project']] = tEnd
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['preID'],sorted_startTimeMach[0]['mach'],sorted_startTimeOp[0]['pm'],tStart,tEnd-aTime])
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['id'],sorted_startTimeMach[0]['mach'],'automatic',tEnd-aTime,tEnd])
print 'schedule', G.Schedule
print G.resAvailability[sorted_startTimeOp[0]['pm']]
def exeSim(jsonInput, workplanInput):
mime_type, attachement_data = jsonInput[len('data:'):].split(';base64,', 1)
attachement_data = attachement_data.decode('base64')
jInput = attachement_data
mime_type, attachement_data = workplanInput[len('data:'):].split(';base64,', 1)
attachement_data = attachement_data.decode('base64')
excelInput = attachement_data
# read input data
importInput(jInput, excelInput)
# find initial operation
opDone = []
seq = deepcopy(G.seqPrjDone)
proj = deepcopy(G.Projects)
opReady = findSequence(proj, seq, opDone)
print 'opready', opReady, G.seqPrjDone
while len(opReady):
# set current operation
currentOp = opReady[0]
print 'chosen operation', currentOp['id']
# check op mode
if currentOp['mode'] == 'MA' or currentOp['mode'] == 'MM':
MAM_allocation(currentOp)
else:
manual_allocation(currentOp)
# elif currentOp['mode'] == 'MM':
# print 'MM'
# MM_allocation(currentOp)
# save results
opDone.append(currentOp['id'])
G.seqPrjDone[currentOp['project']][currentOp['part']] += 1
print 'op', currentOp
if currentOp['preID'] != None:
opDone.append(currentOp['preID'])
G.seqPrjDone[currentOp['project']][currentOp['part']] += 1
# aggiorna seqPrjDone
seq = deepcopy(G.seqPrjDone)
proj = deepcopy(G.Projects)
opReady = findSequence(proj, seq, opDone)
print opDone
print 'completion date', G.completionDate
G.reportResults.add_sheet(G.tabSchedule)
with open('schedule.xlsx', 'wb') as f: #time level schedule info
f.write(G.reportResults.xlsx)
if __name__ == '__main__':
exeSim()
\ No newline at end of file
'''
Created on 14 Aug 2015
@author: Anna
'''
from operator import itemgetter
from Globals import G
def findSequence(Projects, seqPrjDone, idDone):
opReady = []
print 'find sequence', Projects
print 'find sequence', seqPrjDone
for proj in seqPrjDone.keys():
for part in seqPrjDone[proj].keys():
if seqPrjDone[proj][part] < len(Projects[proj][part]):
possibleOp = True
print 'part', part, Projects[proj][part][seqPrjDone[proj][part]]['id']
if seqPrjDone[proj][part]==0 or Projects[proj][part][seqPrjDone[proj][part]-1]['id'] not in G.Schedule.keys():
minStartTime = max(G.xlreftime, G.OrderDates[proj])
else:
minStartTime = G.Schedule[Projects[proj][part][seqPrjDone[proj][part]-1]['id']]['endDate']
# verify whether the operation can be performed in terms of prerequisite operations
for preReq in Projects[proj][part][seqPrjDone[proj][part]]['preReq']:
if preReq not in idDone:
possibleOp = False
break
else:
if minStartTime < G.Schedule[preReq]['endDate']:
minStartTime = G.Schedule[preReq]['endDate']
if possibleOp:
newOp = Projects[proj][part][seqPrjDone[proj][part]]
print newOp['id'], 'possible'
newOp['minStartTime'] = minStartTime
newOp['project'] = proj
newOp['part'] = part
if newOp['personnel'].lower() != 'automatic':
newOp['manualTime'] = newOp['pt'] * newOp['qty']
seqPrjDone[proj][part] += 1
# newOp['manualTime']
# if it is a setup operation add the following operation
if 'SET' in newOp['operation']:
assert(seqPrjDone[proj][part] < len(Projects[proj][part]))
followOp = Projects[proj][part][seqPrjDone[proj][part]]
seqPrjDone[proj][part] += 1
# verify that the operation is the same
print followOp['operation'], newOp['operation']
assert (followOp['operation'].split('-')[0] in newOp['operation'])
# update operation (erase set)
newOp['operation'] = followOp['operation']
# update automatic time
newOp['autoTime'] = followOp['pt'] * followOp['qty']
# update opID, add followOp id
newOp['preID'] = newOp['id']
newOp['id'] = followOp['id']
else:
newOp['autoTime'] = 0
newOp['preID'] = None
if newOp['operation'] in ['INJM', 'MILL', 'EDM', 'TURN', 'DRILL']:
newOp['mode'] = 'MA'
elif newOp['operation'] == 'INJM-MAN':
newOp['mode'] = 'MM'
newOp['operation'] = 'INJM'
else:
newOp['mode'] = 'M'
opReady.append(newOp)
print 'pre', opReady
opReady = sorted(opReady, key=itemgetter('sequence', 'manualTime', 'autoTime'))
print 'seq', seqPrjDone, G.seqPrjDone
return opReady
if __name__ == '__main__':
import jsonReader as jR
seq = jR.seqPrjDone
seq['Order 1']['Order 1 - Mould'] = 2
seq['Order 1']['Order 1 - Part 01'] = 3
seq['Order 1']['Order 1 - Part 02'] = 3
seq['Order 1']['Order 1 - Part 03'] = 1
op = findSequence(jR.Projects, jR.seqPrjDone, ['ID-00001','ID-00002','ID-00003','ID-00004','ID-00005', 'ID-00006', 'ID-00007', 'ID-00008', 'ID-00009'])
print 'op', op
\ No newline at end of file
'''
Created on 7 Aug 2015
@author: Anna
'''
import json
import tablib
import datetime as dt
import xlrd
from copy import deepcopy
from shiftGeneration import shiftGenerator
from timeCalculations import availableTime_Shift
from Globals import G
def dateToOrdinal(entry, formatDate):
rec = dt.datetime.strptime(entry,formatDate)
#rec.toordinal()
return rec
def colonTimeStr(entry):
splitEntry = entry.split(':')
floatTime = int(splitEntry[0]) + float(splitEntry[1])/60
return floatTime
def excel_date(date1):
temp = dt.datetime(1899, 12, 30)
date1 = dt.datetime.combine(date1, dt.time())
delta = date1 - temp
return float(delta.days) + (float(delta.seconds) / 86400)
def offShiftFormat(colEntry):
periods = {'Start':[],'Stop':[]}
sprtdRec = colEntry.split(';'+' ')
for startANDend in sprtdRec:
splitstartANDend = str(startANDend).split('-')
for num,stAstP in enumerate(splitstartANDend):
splitstAstP = stAstP.split(':')
firstrec = int(splitstAstP[0]) + float(splitstAstP[1])/60
if num == 0:
periods['Start'].append()
else:
periods['Stop'].append(int(splitstAstP[0])+ float(splitstAstP[1])/60)
return periods
def offShiftFormat_2(colEntry, dateNow):
periods = {}
sprtdRec = colEntry.split(';'+' ')
print 'col entry', colEntry
print 'date', dateNow
for startANDend in sprtdRec:
splitstartANDend = str(startANDend).split('-')
print 'splitstartANDend', splitstartANDend
for num,stAstP in enumerate(splitstartANDend):
print 'st ast', stAstP
falseTime = dt.datetime.strptime(stAstP,'%H:%M')
if num == 0:
startTime = dt.datetime(year=dateNow.year, month=dateNow.month, day=dateNow.day, hour=falseTime.hour, minute=falseTime.minute)
else:
endTime = dt.datetime(year=dateNow.year, month=dateNow.month, day=dateNow.day, hour=falseTime.hour, minute=falseTime.minute)
periods[startTime] = {'endDate':endTime, 'taskID':'offShift'}
return periods
def combSchedules(bothSchedList,combData):
for sch in bothSchedList:
for cell in sch:
if len(cell) < 10:
cell = list(cell)
cell.extend(['Not Frozen'])
combData.append(cell)
print combData['Date']
combData = combData.sort('Date')
with open('Results\\Combined Schedule.xlsx', 'wb') as h: #completion time, cycle time and delay info in json format
h.write(combData.xlsx)
def importInput(jInput, excelInput):
#===========================================================
# Import workstations and operators schedule from json file
#===========================================================
dataJSON = json.loads(jInput)
print 'in import'
wb = xlrd.open_workbook(file_contents = excelInput)
frozen ={}
takenPeriods = {}
startSimDate = dateToOrdinal(dataJSON['general']['currentDate'], '%Y/%m/%d %H:%M')
forzenOpsData=tablib.Dataset()
forzenOpsData.headers = ['Date','Part','Order Name','WP-ID','Personnel','WorkStation','Time In','Time Out','Date Out','Frozen']
schedule = dataJSON['result']['result_list'][0]['component_schedule']
for item in schedule:
if "Job ID" in item:
continue
startDate = dateToOrdinal(item[5], '%Y/%m/%d %H:%M')
pt = dt.timedelta(hours=item[6])
dateOut = startDate + pt
station = item[4]
ordinalOutDate = excel_date(dateOut.date())
order = item[1].encode('ascii', 'ignore')
part = item[0].encode('ascii', 'ignore')
#print 'startDate', startDate.date()
if pt.seconds > 0 or pt.days>0:
forzenOpsData.append([startDate.date(), part, order, item[3], item[7], station, startDate.time(), dateOut.time(), ordinalOutDate, 'X'])
frozen[item[3]] = 'X'
G.tabSchedule.append([order,part, item[3],station,item[7],startDate,dateOut])
if station not in takenPeriods:
takenPeriods[station] = {}
takenPeriods[station][startDate] = {'endDate': dateOut, 'taskID':item[3]}
PMschedule = dataJSON['result']['result_list'][0]['operator_gantt']['task_list']
for item in PMschedule:
if 'parent' in item.keys():
pm = item['parent']
startDate = dateToOrdinal(item['start_date'], "%d-%m-%Y %H:%M")
stopDate = dateToOrdinal(item['stop_date'], "%d-%m-%Y %H:%M")
ordinalOutDate = excel_date(stopDate.date())
taskID = item['text'].split()[0]
print pm, taskID
pt = float((stopDate-startDate).seconds)/3600
if taskID == 'off-shift':
continue
if pt:
print pm, taskID
if pm not in takenPeriods:
takenPeriods[pm] = {}
takenPeriods[pm][startDate] = {'endDate': stopDate, 'taskID': taskID}
print 'frozen operations', forzenOpsData
print 'taken periods', takenPeriods
#=================================
# Import Workplan from Excel file
#=================================
global numParts
#scenario = 'SIMPLE_2.xlsx'
WorkPlan = wb.sheet_by_index(0)
Projects = {}
OrderDates = {}
DueDates = {}
Shift = {}
seqPrjDone = {}
# FIXME: importare data riferimento
td = dt.datetime(2015,07,23)
xlreftime = excel_date(td)
for i in range(WorkPlan.nrows):
i += 1
if i < WorkPlan.nrows: #for the first line of the project name
if WorkPlan.cell_value(i,2) != '' and WorkPlan.cell_value(i,6) != '':
Projects[WorkPlan.cell_value(i,2)] = {}
print 'order date', xlrd.xldate_as_tuple(WorkPlan.cell_value(i,3), wb.datemode)
oyear, omonth, oday, ohour, ominute, osecond = xlrd.xldate_as_tuple(WorkPlan.cell_value(i,3), wb.datemode)
if ohour < 8:
ohour = 8
OrderDates[WorkPlan.cell_value(i,2)] = dt.datetime(oyear, omonth, oday, ohour, ominute, osecond) #FIXME: perche cosi?
DueDates[WorkPlan.cell_value(i,2)] = (xlreftime + WorkPlan.cell_value(i,4))
header = i
current = WorkPlan.cell_value(header,2)
seqPrjDone[current] = {}
#for a part whose name is not in the first line
if str(WorkPlan.cell_value(i,13)).split(';'+' ')[0].upper() == 'ALL':
prerq = []
for wpid in range(header,i):
prerq.append(str(WorkPlan.cell_value(wpid,14)))
else:
prerq = str(WorkPlan.cell_value(i,13)).split(';'+' ')
if len(prerq) == 1 and prerq[0]=='':
prerq=[]
if WorkPlan.cell_value(i,6) == '':
continue
Projects[current].setdefault(WorkPlan.cell_value(i,6),[]).append({'id':str(WorkPlan.cell_value(i,14)), 'personnel':str(WorkPlan.cell_value(i,10)),
'pt': WorkPlan.cell_value(i,12), 'qty':WorkPlan.cell_value(i,11), 'preReq': prerq,
'operation': str(WorkPlan.cell_value(i,8)), 'sequence':WorkPlan.cell_value(i,9),
'project':current, 'part':WorkPlan.cell_value(i,6)})
seqPrjDone[current].setdefault(WorkPlan.cell_value(i,6),0)
print 'workplan', Projects
print 'sequence', seqPrjDone
#==================================
# Import shift data from json file
#==================================
offShiftTimes = {}
stRtstOp = {}
unitTime = 'Hours'
# default shift times are hard coded as there is no correspondence with json file
# 7:00 - 18:00 are standard shift times
defaultStartShift = 8.0/24
defaultEndShift = 18.0/24
stRtstOp['Default'] = [defaultStartShift,defaultEndShift]
shiftData = dataJSON['input']["shift_spreadsheet"]
for item in shiftData:
if 'Date' in item:
continue
if item[1] == '' or item[1]== None:
continue
currDate = excel_date(dateToOrdinal(item[1], "%Y/%m/%d").date())
cDate = dateToOrdinal(item[1], "%Y/%m/%d").date()
print item[2], item[3]
if item[2] == '' or item[2]== None:
shiftStart = defaultStartShift
else:
shiftStart = dt.datetime.strptime(item[2],'%H:%M')
if item[3] == '' or item[3]== None:
shiftEnd = defaultEndShift
else:
shiftEnd = dt.datetime.strptime(item[3],'%H:%M')
if item[4] == '' or item[4]== None:
offshiftPeriods = {}
else:
offshiftPeriods = offShiftFormat_2(item[4],cDate)
if item[0] != '':#the first line for an operator
currResc = item[0]
if currResc not in offShiftTimes:#no previous entry for the operator
offShiftTimes[currResc] = {}
offShiftTimes[currResc] = offshiftPeriods
stRtstOp[currResc] = {}
stRtstOp[currResc][cDate] = [shiftStart.time(),shiftEnd.time()]
else:
offShiftTimes[currResc] = offshiftPeriods
else:
offShiftTimes[currResc][cDate] = offshiftPeriods
stRtstOp[currResc][cDate] = [shiftStart,shiftEnd]
print 'off shift time', offShiftTimes
offShifts = dict((k,{}) for k in offShiftTimes.keys() + takenPeriods.keys())
for rsce in offShifts.keys():
if rsce in takenPeriods:
offShifts[rsce] = takenPeriods[rsce] #directly copy everything from the extracted dict
if rsce in offShiftTimes:#if that resource is present in the directly specified
for dte in offShiftTimes[rsce]:
if dte not in offShifts[rsce]:#if this date was not originally specified
offShifts[rsce][dte] = offShiftTimes[rsce][dte]
else:
starts = offShifts[rsce][dte]['Start']
stops = offShifts[rsce][dte]['Stop']
starts.extend(offShiftTimes[rsce][dte]['Start'])
stops.extend(offShiftTimes[rsce][dte]['Stop'])
u = list(set(starts))
v = list(set(stops))
offShifts[rsce][dte]['Start'] = u
offShifts[rsce][dte]['Stop'] = v
offShifts[rsce][dte]['Start'].sort()
offShifts[rsce][dte]['Stop'].sort()
print 'stRtstOp', stRtstOp
print 'off shift', offShifts
#==================================================
# Import machine and pm information from json file
#==================================================
MachInfo = []
MachPool = {}
PMInfo = []
PMPool = {}
stationTechnologies = {"CAD1": ["ENG", "CAD"], # XXX CAD1 is considered different than CAD2, they are not equivalent
"CAD2": ["CAD"],
"CAM": ["CAM"],
"MILL": ["MILL"],
"TURN": ["TURN"],
"DRILL": ["DRILL"],
"EDM": ["EDM"],
"WORK": ["QUAL", "MAN"], # XXX currently we consider different stations for QUAL/MAN and ASSM
"ASSM": ["ASSM"],
"INJM": ["INJM"]}
possMachines = dataJSON['graph']['node']
for mach in possMachines.keys():
if 'machine' in possMachines[mach]['_class'].lower() or 'assembly' in possMachines[mach]['_class'].lower():
capacity = 1
initials = len(mach)
while initials>0 and mach[:initials] not in stationTechnologies:
initials -= 1
pool = stationTechnologies[mach[:initials]]
MachInfo.append({'name': mach, 'cap':capacity, 'tech':pool, 'sched':'FIFO'})
for tec in pool:
MachPool.setdefault(tec,[]).append(mach)
print MachInfo
print 'mach pool', MachPool
PMskills = dataJSON['input']['operator_skills_spreadsheet']
for item in range(1,len(PMskills)):
if PMskills[item][0] == None or PMskills[item][0] == '':
continue
skills = PMskills[item][1].split(';'+' ')
if 'INJM-MAN' in skills:
skills.remove('INJM-MAN')
skills.append('INJM')
PMInfo.append({'name':PMskills[item][0], 'skills': skills, 'sched':'FIFO', 'status':''})
for sk in skills:
PMPool.setdefault(sk,[]).append(PMskills[item][0])
print PMInfo
print 'pm pool', PMPool
print '======================',offShifts
shiftRes = {}
resAvailability = {}
for item in PMInfo:
pm = item['name']
shiftRes[pm] = shiftGenerator(startSimDate,7)
resAvailability[pm] = deepcopy(shiftRes[pm])
if pm in offShifts:
for unavailDate in offShifts[pm].keys():
print pm, unavailDate, offShifts[pm][unavailDate]['endDate']-unavailDate
resAvailability[pm] = availableTime_Shift(unavailDate,offShifts[pm][unavailDate]['endDate'],resAvailability[pm])
print 'shift', pm, shiftRes[pm]
print 'shift', pm, resAvailability[pm]
for item in MachInfo:
mach = item['name']
shiftRes[mach] = shiftGenerator(startSimDate,7)
resAvailability[mach] = deepcopy(shiftRes[mach])
if mach in offShifts:
for unavailDate in offShifts[mach].keys():
print mach, unavailDate, offShifts[mach][unavailDate]['endDate']-unavailDate
resAvailability[mach] = availableTime_Shift(unavailDate,offShifts[mach][unavailDate]['endDate'],resAvailability[mach])
print 'shift', mach, shiftRes[mach]
print 'shift', mach, resAvailability[mach]
# set global variables
G.resAvailability = deepcopy(resAvailability)
G.seqPrjDone = deepcopy(seqPrjDone)
G.resAvailability = deepcopy(resAvailability)
G.MachPool = deepcopy(MachPool)
G.PMPool = deepcopy(PMPool)
G.Projects = deepcopy(Projects)
G.xlreftime = td
G.OrderDates = deepcopy(OrderDates)
G.completionDate = deepcopy(OrderDates)
'''
Created on 6 Aug 2015
@author: Anna
'''
import datetime as dt
from copy import deepcopy
def shiftGenerator(startDate, noDays):
shift = {}
day = 0
actualDays = 0
preDay = deepcopy(startDate.date())
while actualDays < noDays:
st = deepcopy(startDate)
if day:
dateStart = st.date()
dateStart += dt.timedelta(days=day)
st = dt.datetime(dateStart.year,dateStart.month, dateStart.day, 8,0)
if st.weekday() < 5:
fin = dt.datetime(st.year, st.month, st.day, 18,0)
shift[st] = {'end':fin, 'startMode':'SOS', 'endMode':'EOS', 'preDay':preDay}
preDay = st.date()
actualDays += 1
day += 1
return shift
if __name__ == '__main__':
shift = shiftGenerator(dt.datetime(2015,8,4,12,00),10)
'''
Created on 6 Aug 2015
@author: Anna
'''
import datetime as dt
from copy import deepcopy
def availableTimeInterval_Manual(manualTime, tStart, availTime):
# suitable for manual operations...returns available time until the end
sortedTime = sorted(availTime.keys())
i = 0
while i<len(sortedTime) and sortedTime[i] <= tStart:
i += 1
i -= 1
if i < 0:
i = 0
# if i == 0 and tStart + manualTime < sortedTime[i]:
# return None
if availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i]) <= dt.timedelta(seconds=0):
i += 1
if i>=len(sortedTime):
print 'WARNING-not possible'
return None, 0
return sortedTime[i], availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i])
def availableTimeInterval_MM(manualTime, autoTime, tStart, availTime):
# suitable for MM operations...requires continuous availability over consecutive shifts
sortedTime = sorted(availTime.keys())
i = 0
while i<len(sortedTime) and sortedTime[i] <= tStart:
i += 1
i -= 1
if i < 0:
i = 0
# if i == 0 and tStart + autoTime + manualTime < sortedTime[i]:
# return None
tCumulative = dt.timedelta(seconds=0)
startSorted = sortedTime[i]
while i<len(sortedTime) and (tCumulative + availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i])) < manualTime+autoTime:
if availTime[sortedTime[i]]['endMode'] == 'EOS':
if i+1 < len(sortedTime) and availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and availTime[sortedTime[i+1]]['startMode'] == 'SOS':
tCumulative += availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i])
else:
tCumulative = dt.timedelta(seconds=0)
if i+1 < len(sortedTime):
startSorted = sortedTime[i+1]
i += 1
if i>=len(sortedTime):
return None, 0
return startSorted, manualTime+autoTime-tCumulative + max(tStart,sortedTime[i]) - max(tStart,startSorted)
def availableTimeInterval_MA(manualTime, autoTime, tStart, availTime):
sortedTime = sorted(availTime.keys())
print sortedTime
i = 0
while i<len(sortedTime) and sortedTime[i] <= tStart:
i += 1
i -= 1
if i < 0:
i = 0
# if i == 0 and tStart + autoTime + manualTime < sortedTime[i]:
# return None
print 'start', sortedTime[i]
while True:
tCumulative = dt.timedelta(seconds=0)
startSorted = sortedTime[i]
while i<len(sortedTime) and (tCumulative + availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i])) < manualTime:
if availTime[sortedTime[i]]['endMode'] == 'EOS':
if i+1 < len(sortedTime) and availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and availTime[sortedTime[i+1]]['startMode'] == 'SOS':
tCumulative += availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i])
else:
tCumulative = dt.timedelta(seconds=0)
if i+1 < len(sortedTime):
startSorted = sortedTime[i+1]
i += 1
if i>=len(sortedTime):
return None, 0
tManualEnd = max(tStart, sortedTime[i]) + manualTime - tCumulative
# while i<len(sortedTime) and availTime[sortedTime[i]]['end'] - max(tStart,sortedTime[i]) < manualTime:
# i += 1
if i>=len(sortedTime):
return None
# print 'end manual', sortedTime[i]
if autoTime:
# if availTime[sortedTime[i]]['end']- max(tStart,sortedTime[i]) <= (manualTime+autoTime):
if availTime[sortedTime[i]]['end']- max(tManualEnd,sortedTime[i]) <= autoTime:
if availTime[sortedTime[i]]['endMode'] == 'EOS':
if i==len(sortedTime)-1:
break
# if availTime[sortedTime[i+1]]['startMode']=='SOS' and availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and availTime[sortedTime[i+1]]['end'] - max(tStart,sortedTime[i]) >= (manualTime+autoTime):
if availTime[sortedTime[i+1]]['startMode']=='SOS' and availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and availTime[sortedTime[i+1]]['end'] - max(tManualEnd,sortedTime[i]) >= autoTime:
break
else:
i += 1
else:
i += 1
else:
break
else:
break
# return sortedTime[i]
return startSorted, tManualEnd - max(tStart,startSorted)
def updateAvailTime(keyStart, reqTime, tStart, availTime):
# tStart e` tempo effettivo di inizio calcolato in precedenza come max(tStart,keyStart)
# print 'update', keyStart, reqTime, tStart
if reqTime <= dt.timedelta(seconds=0):
return availTime
tempSave = deepcopy(availTime[keyStart])
if keyStart == tStart:
availTime.pop(keyStart,None)
else:
availTime[keyStart]['end'] = tStart
availTime[keyStart]['endMode'] = 'IS'
# print 'inizio', keyStart, availTime[keyStart]
# case of interval ending before previous end
if tStart+reqTime < tempSave['end']:
availTime[tStart+reqTime] = {'end':tempSave['end'], 'startMode':'IS', 'endMode':tempSave['endMode'], 'preDay':tempSave['preDay']}
# case of interval ending after previous end (i.e. automatic operations)...check if goes into following available interval
elif tStart+reqTime > tempSave['end']:
sortedTime = sorted(availTime.keys())
i=0
while i<len(sortedTime) and sortedTime[i]<=keyStart:
i+=1
# if modeSim == 'avail':
# i -= 1
if i >= len(sortedTime):
print 'WARNING: beyond planning horizon'
return availTime
# print 'find next time', sortedTime[i], i
if tStart+reqTime > sortedTime[i]:
# repeat procedure
availTime = updateAvailTime(sortedTime[i], reqTime - (sortedTime[i]-tStart), sortedTime[i], availTime)
return availTime
def availableTime_Shift(tStart, tEnd, availTime):
sortedTime = sorted(availTime.keys())
i = 0
while i<len(sortedTime) and availTime[sortedTime[i]]['end'] <= tStart:
i += 1
# print i, sortedTime[i], availTime[sortedTime[i]]['end'], tStart, tEnd
if i>=len(sortedTime):
print 'WARNING: time interval not found'
return availTime
if availTime[sortedTime[i]]['end'] >= tEnd:
availTime = updateAvailTime(sortedTime[i], tEnd - max(tStart,sortedTime[i]), max(tStart,sortedTime[i]), availTime)
else:
if availTime[sortedTime[i]]['endMode'] == 'EOS':
if i==len(sortedTime)-1:
print 'WARNING: beyond last interval'
availTime= updateAvailTime(sortedTime[i], tEnd - max(tStart,sortedTime[i]), max(tStart,sortedTime[i]), availTime)
if availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and sortedTime[i+1] >= tEnd:
availTime = updateAvailTime(sortedTime[i], tEnd - max(tStart,sortedTime[i]), max(tStart,sortedTime[i]), availTime)
elif availTime[sortedTime[i+1]]['startMode']=='SOS' and availTime[sortedTime[i+1]]['preDay'] == sortedTime[i].date() and availTime[sortedTime[i+1]]['end'] >= tEnd:
print 'beyond eos', max(tStart,sortedTime[i]), tEnd - max(tStart,sortedTime[i])
availTime = updateAvailTime(sortedTime[i], tEnd - max(tStart,sortedTime[i]), max(tStart,sortedTime[i]), availTime)
else:
return availTime
else:
return availTime
return availTime
if __name__ == '__main__':
availTime = {dt.datetime(2015, 7, 23, 8, 0): {'end': dt.datetime(2015, 7, 23, 18, 0), 'startMode': 'SOS', 'endMode': 'EOS'},
dt.datetime(2015, 7, 24, 8, 0): {'end': dt.datetime(2015, 7, 24, 18, 0), 'startMode': 'SOS', 'endMode': 'EOS'},
dt.datetime(2015, 7, 25, 8, 0): {'end': dt.datetime(2015, 7, 27, 18, 0), 'startMode': 'SOS', 'endMode': 'EOS'}}
tStart = dt.datetime(2015,7,23,12,00)
tEnd = dt.datetime(2015,7,25,14,0)
autoTime = dt.timedelta(hours=20)
manualTime = dt.timedelta(hours=4)
print tStart
keyStart, pt = availableTimeInterval_MM(manualTime, autoTime, tStart, availTime)
print keyStart
# pt = manualTime + autoTime
print 'pt', pt
if keyStart:
availTime = updateAvailTime(keyStart, pt, max(tStart,keyStart), availTime)
else:
print 'WARNING: operation cannot be performed'
#availTime = availableTime_Shift(tStart, tEnd, availTime)
print 'updated time', availTime
\ No newline at end of file
'''
Created on 31 Aug 2015
@author: Anna
'''
import tablib
class G:
Schedule={}
seqPrjDone = None
resAvailability = None
MachPool = None
PMPool = None
Projects = None
xlreftime = None
reportResults = tablib.Databook()
tabSchedule = tablib.Dataset(title='Schedule')
tabSchedule.headers = (['Project', 'Part', 'Task ID', 'Station', 'Operator', 'Start Time', 'End Time'])
OrderDates = None
completionDate = None
jsonInput = None
excelInput = None
\ 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/>.
# ===========================================================================
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
\ No newline at end of file
'''
Created on 20 Aug 2015
@author: Anna
'''
from jsonReader import importInput
from findSequence import findSequence
from timeCalculations import availableTimeInterval_MA, updateAvailTime, availableTimeInterval_MM, availableTimeInterval_Manual
from operator import itemgetter
from copy import deepcopy
from Globals import G
import datetime as dt
def manual_allocation(currentOp):
tStart = currentOp['minStartTime'] # earliest start date for current operation
remPT = dt.timedelta(hours=currentOp['manualTime'])
print 'in manual allocation', currentOp['id']
print 'tStart manual', tStart, remPT
while remPT > dt.timedelta(seconds=0):
startTimeMach = [] # collects earliest keyDate for machines
startTimeOp = [] # collects earliest keyDate for operators
# find machines available time intervals
for mach in G.MachPool[currentOp['operation']]:
res = availableTimeInterval_Manual(remPT, tStart, G.resAvailability[mach])
startTimeMach.append({'mach':mach, 'start':res[0], 'avPT':res[1]*(-1)})
# sort available time
sorted_startTimeMach = sorted(startTimeMach, key=itemgetter('start', 'avPT'))
tStart = max(sorted_startTimeMach[0]['start'],tStart)
# verify whether PM are available in the same time
for pm in G.PMPool[currentOp['operation']]:
res = availableTimeInterval_Manual(remPT, tStart, G.resAvailability[pm])
startTimeOp.append({'pm':pm, 'start':res[0], 'avPT':res[1]*(-1)})
# sort available time
sorted_startTimeOp = sorted(startTimeOp, key=itemgetter('start', 'avPT'))
print tStart
print 'sort mach', sorted_startTimeMach
print 'sort pm', sorted_startTimeOp
# calculate available PT
if sorted_startTimeOp[0]['start'] <= tStart:
print 'first op'
availablePT = min(sorted_startTimeMach[0]['avPT']*(-1), sorted_startTimeOp[0]['avPT']*(-1), remPT)
elif sorted_startTimeOp[0]['start'] < tStart + sorted_startTimeMach[0]['avPT']:
print 'sec op'
tEnd = min(tStart+sorted_startTimeMach[0]['avPT'], sorted_startTimeOp[0]['start']+sorted_startTimeOp[0]['avPT'])
tStart = sorted_startTimeOp[0]['start']
availablePT = min(tEnd - tStart, remPT)
else:
print '3 op'
availablePT = dt.timedelta(seconds=0)
tStart = sorted_startTimeOp[0]['start']
# update remaining PT
remPT -= availablePT
print 'fine all', tStart, availablePT, remPT
if availablePT > dt.timedelta(seconds=0):
# update machine and operator availability
G.resAvailability[sorted_startTimeMach[0]['mach']] = updateAvailTime(sorted_startTimeMach[0]['start'], availablePT, tStart,
G.resAvailability[sorted_startTimeMach[0]['mach']])
G.resAvailability[sorted_startTimeOp[0]['pm']] = updateAvailTime(sorted_startTimeOp[0]['start'], availablePT, tStart,
G.resAvailability[sorted_startTimeOp[0]['pm']])
# aggiorna schedule
if currentOp['id'] not in G.Schedule.keys():
G.Schedule[currentOp['id']]={}
G.Schedule[currentOp['id']]['startDate'] = tStart
tEnd = tStart + availablePT
G.Schedule[currentOp['id']]['endDate'] = tEnd
G.Schedule[currentOp['id']].setdefault('rList',{})[(tStart,tEnd)] = {'mach':sorted_startTimeMach[0]['mach'],'operator':sorted_startTimeOp[0]['pm']}
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['id'],sorted_startTimeMach[0]['mach'],sorted_startTimeOp[0]['pm'],tStart,tEnd])
if currentOp['preID'] != None:
G.Schedule[currentOp['preID']] = G.Schedule[currentOp['id']]
if G.completionDate[currentOp['project']] < tEnd:
G.completionDate[currentOp['project']] = tEnd
tStart = tEnd
print currentOp['id'], G.Schedule[currentOp['id']]
def MAM_allocation(currentOp):
tStart = currentOp['minStartTime'] # earliest start date for current operation
print 'tStart', tStart
remPT = currentOp['manualTime'] + currentOp['autoTime']
while remPT:
startTimeMach = [] # collects earliest keyDate for machines
startTimeOp = [] # collects earliest keyDate for operators
# find machines available time intervals
for mach in G.MachPool[currentOp['operation']]:
# find available time (availableTimeInterval_MA)
print 'man', currentOp['manualTime']
mTime = dt.timedelta(hours=currentOp['manualTime'])
aTime = dt.timedelta(hours=currentOp['autoTime'])
print 'mach av', mach, G.resAvailability[mach]
if currentOp['mode'] == 'MM':
res = availableTimeInterval_MM(mTime, aTime, tStart, G.resAvailability[mach])
startTimeMach.append({'mach':mach, 'start':res[0], 'eqPT':res[1]})
else:
res = availableTimeInterval_MA(mTime, aTime, tStart, G.resAvailability[mach])
#startTimeMach.append({'mach':mach, 'start':res, 'eqPT':mTime+aTime})
startTimeMach.append({'mach':mach, 'start':res[0], 'eqPT':res[1]+aTime})
print 'start time mach', startTimeMach
# sort available time
sorted_startTimeMach = sorted(startTimeMach, key=itemgetter('start', 'eqPT'))
tStart = max(sorted_startTimeMach[0]['start'],tStart)
print 'mach tent', sorted_startTimeMach[0]['mach'], tStart
# verify whether PM are available in the same time
for pm in G.PMPool[currentOp['operation']]:
print 'operator', pm
#find available time
if currentOp['mode'] == 'MM':
res = availableTimeInterval_MM(mTime, aTime, tStart, G.resAvailability[pm])
startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':res[1]})
else:
res = availableTimeInterval_MA(mTime, dt.timedelta(hours=0), tStart, G.resAvailability[pm])
# startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':mTime})
startTimeOp.append({'pm':pm, 'start':res[0], 'eqPT':res[1]})
# sort available time
sorted_startTimeOp = sorted(startTimeOp, key=itemgetter('start', 'eqPT'))
if sorted_startTimeOp[0]['start'] <= tStart:
remPT = 0
else:
tStart = sorted_startTimeOp[0]['start']
print 'machine chosen', sorted_startTimeMach[0]['mach']
print 'operator chosen', sorted_startTimeOp[0]['pm'], sorted_startTimeOp
print G.resAvailability[sorted_startTimeMach[0]['mach']]
print G.resAvailability[sorted_startTimeOp[0]['pm']]
# update machine availability
G.resAvailability[sorted_startTimeMach[0]['mach']] = updateAvailTime(sorted_startTimeMach[0]['start'], sorted_startTimeMach[0]['eqPT'], tStart,
G.resAvailability[sorted_startTimeMach[0]['mach']])
# update operator availability
G.resAvailability[sorted_startTimeOp[0]['pm']] = updateAvailTime(sorted_startTimeOp[0]['start'], sorted_startTimeOp[0]['eqPT'], tStart,
G.resAvailability[sorted_startTimeOp[0]['pm']])
# aggiorna schedule
G.Schedule.setdefault(currentOp['id'],{})
G.Schedule[currentOp['id']]['startDate'] = tStart
tEnd = tStart + sorted_startTimeMach[0]['eqPT']
G.Schedule[currentOp['id']]['endDate'] = tEnd
G.Schedule[currentOp['id']].setdefault('rList',{})[(tStart,tEnd)] = {'mach':sorted_startTimeMach[0]['mach'],'operator':sorted_startTimeOp[0]['pm']}
if currentOp['preID'] != None:
G.Schedule[currentOp['preID']] = G.Schedule[currentOp['id']]
if G.completionDate[currentOp['project']] < tEnd:
G.completionDate[currentOp['project']] = tEnd
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['preID'],sorted_startTimeMach[0]['mach'],sorted_startTimeOp[0]['pm'],tStart,tEnd-aTime])
G.tabSchedule.append([currentOp['project'], currentOp['part'], currentOp['id'],sorted_startTimeMach[0]['mach'],'automatic',tEnd-aTime,tEnd])
print 'schedule', G.Schedule
print G.resAvailability[sorted_startTimeOp[0]['pm']]
def exeSim():
# launch import...quando si trasforma jsonReader
importInput()
# find initial operation
opDone = []
seq = deepcopy(G.seqPrjDone)
proj = deepcopy(G.Projects)
opReady = findSequence(proj, seq, opDone)
print 'opready', opReady, G.seqPrjDone
while len(opReady):
# set current operation
currentOp = opReady[0]
print 'chosen operation', currentOp['id']
# check op mode
if currentOp['mode'] == 'MA' or currentOp['mode'] == 'MM':
MAM_allocation(currentOp)
else:
manual_allocation(currentOp)
# elif currentOp['mode'] == 'MM':
# print 'MM'
# MM_allocation(currentOp)
# save results
opDone.append(currentOp['id'])
G.seqPrjDone[currentOp['project']][currentOp['part']] += 1
print 'op', currentOp
if currentOp['preID'] != None:
opDone.append(currentOp['preID'])
G.seqPrjDone[currentOp['project']][currentOp['part']] += 1
# aggiorna seqPrjDone
seq = deepcopy(G.seqPrjDone)
proj = deepcopy(G.Projects)
opReady = findSequence(proj, seq, opDone)
print opDone
print 'completion date', G.completionDate
G.reportResults.add_sheet(G.tabSchedule)
with open('schedule.xlsx', 'wb') as f: #time level schedule info
f.write(G.reportResults.xlsx)
if __name__ == '__main__':
exeSim()
\ No newline at end of file
'''
Created on 14 Aug 2015
@author: Anna
'''
from operator import itemgetter
from Globals import G
def findSequence(Projects, seqPrjDone, idDone):
opReady = []
print 'find sequence', Projects
print 'find sequence', seqPrjDone
for proj in seqPrjDone.keys():
for part in seqPrjDone[proj].keys():
if seqPrjDone[proj][part] < len(Projects[proj][part]):
possibleOp = True
print 'part', part, Projects[proj][part][seqPrjDone[proj][part]]['id']
if seqPrjDone[proj][part]==0 or Projects[proj][part][seqPrjDone[proj][part]-1]['id'] not in G.Schedule.keys():
minStartTime = max(G.xlreftime, G.OrderDates[proj])
else:
minStartTime = G.Schedule[Projects[proj][part][seqPrjDone[proj][part]-1]['id']]['endDate']
# verify whether the operation can be performed in terms of prerequisite operations
for preReq in Projects[proj][part][seqPrjDone[proj][part]]['preReq']:
if preReq not in idDone:
possibleOp = False
break
else:
if minStartTime < G.Schedule[preReq]['endDate']:
minStartTime = G.Schedule[preReq]['endDate']
if possibleOp:
newOp = Projects[proj][part][seqPrjDone[proj][part]]
print newOp['id'], 'possible'
newOp['minStartTime'] = minStartTime
newOp['project'] = proj
newOp['part'] = part
if newOp['personnel'].lower() != 'automatic':
newOp['manualTime'] = newOp['pt'] * newOp['qty']
seqPrjDone[proj][part] += 1
# newOp['manualTime']
# if it is a setup operation add the following operation
if 'SET' in newOp['operation']:
assert(seqPrjDone[proj][part] < len(Projects[proj][part]))
followOp = Projects[proj][part][seqPrjDone[proj][part]]
seqPrjDone[proj][part] += 1
# verify that the operation is the same
print followOp['operation'], newOp['operation']
assert (followOp['operation'].split('-')[0] in newOp['operation'])
# update operation (erase set)
newOp['operation'] = followOp['operation']
# update automatic time
newOp['autoTime'] = followOp['pt'] * followOp['qty']
# update opID, add followOp id
newOp['preID'] = newOp['id']
newOp['id'] = followOp['id']
else:
newOp['autoTime'] = 0
newOp['preID'] = None
if newOp['operation'] in ['INJM', 'MILL', 'EDM', 'TURN', 'DRILL']:
newOp['mode'] = 'MA'
elif newOp['operation'] == 'INJM-MAN':
newOp['mode'] = 'MM'
newOp['operation'] = 'INJM'
else:
newOp['mode'] = 'M'
opReady.append(newOp)
print 'pre', opReady
opReady = sorted(opReady, key=itemgetter('sequence', 'manualTime', 'autoTime'))
print 'seq', seqPrjDone, G.seqPrjDone
return opReady
if __name__ == '__main__':
import jsonReader as jR
seq = jR.seqPrjDone
seq['Order 1']['Order 1 - Mould'] = 2
seq['Order 1']['Order 1 - Part 01'] = 3
seq['Order 1']['Order 1 - Part 02'] = 3
seq['Order 1']['Order 1 - Part 03'] = 1
op = findSequence(jR.Projects, jR.seqPrjDone, ['ID-00001','ID-00002','ID-00003','ID-00004','ID-00005', 'ID-00006', 'ID-00007', 'ID-00008', 'ID-00009'])
print 'op', op
\ No newline at end of file
'''
Created on 7 Aug 2015
@author: Anna
'''
import json
import tablib
import datetime as dt
import xlrd
from copy import deepcopy
from shiftGeneration import shiftGenerator
from timeCalculations import availableTime_Shift
from Globals import G
def dateToOrdinal(entry, formatDate):
rec = dt.datetime.strptime(entry,formatDate)
#rec.toordinal()
return rec
def colonTimeStr(entry):
splitEntry = entry.split(':')
floatTime = int(splitEntry[0]) + float(splitEntry[1])/60
return floatTime
def excel_date(date1):
temp = dt.datetime(1899, 12, 30)
date1 = dt.datetime.combine(date1, dt.time())
delta = date1 - temp
return float(delta.days) + (float(delta.seconds) / 86400)
def offShiftFormat(colEntry):
periods = {'Start':[],'Stop':[]}
sprtdRec = colEntry.split(';'+' ')
for startANDend in sprtdRec:
splitstartANDend = str(startANDend).split('-')
for num,stAstP in enumerate(splitstartANDend):
splitstAstP = stAstP.split(':')
firstrec = int(splitstAstP[0]) + float(splitstAstP[1])/60
if num == 0:
periods['Start'].append()
else:
periods['Stop'].append(int(splitstAstP[0])+ float(splitstAstP[1])/60)
return periods
def offShiftFormat_2(colEntry, dateNow):
periods = {}
sprtdRec = colEntry.split(';'+' ')
print 'col entry', colEntry
print 'date', dateNow
for startANDend in sprtdRec:
splitstartANDend = str(startANDend).split('-')
print 'splitstartANDend', splitstartANDend
for num,stAstP in enumerate(splitstartANDend):
print 'st ast', stAstP
falseTime = dt.datetime.strptime(stAstP,'%H:%M')
if num == 0:
startTime = dt.datetime(year=dateNow.year, month=dateNow.month, day=dateNow.day, hour=falseTime.hour, minute=falseTime.minute)
else:
endTime = dt.datetime(year=dateNow.year, month=dateNow.month, day=dateNow.day, hour=falseTime.hour, minute=falseTime.minute)
periods[startTime] = {'endDate':endTime, 'taskID':'offShift'}
return periods
def combSchedules(bothSchedList,combData):
for sch in bothSchedList:
for cell in sch:
if len(cell) < 10:
cell = list(cell)
cell.extend(['Not Frozen'])
combData.append(cell)
print combData['Date']
combData = combData.sort('Date')
with open('Results\\Combined Schedule.xlsx', 'wb') as h: #completion time, cycle time and delay info in json format
h.write(combData.xlsx)
def importInput():
#===========================================================
# Import workstations and operators schedule from json file
#===========================================================
print 'in import'
with open('DemoJuly.json') as data_file:
data = json.load(data_file)
frozen ={}
takenPeriods = {}
startSimDate = dateToOrdinal(data['general']['currentDate'], '%Y/%m/%d %H:%M')
forzenOpsData=tablib.Dataset()
forzenOpsData.headers = ['Date','Part','Order Name','WP-ID','Personnel','WorkStation','Time In','Time Out','Date Out','Frozen']
schedule = data['result']['result_list'][0]['component_schedule']
for item in schedule:
if "Job ID" in item:
continue
startDate = dateToOrdinal(item[5], '%Y/%m/%d %H:%M')
pt = dt.timedelta(hours=item[6])
dateOut = startDate + pt
station = item[4]
ordinalOutDate = excel_date(dateOut.date())
order = item[1].encode('ascii', 'ignore')
part = item[0].encode('ascii', 'ignore')
#print 'startDate', startDate.date()
if pt.seconds > 0 or pt.days>0:
forzenOpsData.append([startDate.date(), part, order, item[3], item[7], station, startDate.time(), dateOut.time(), ordinalOutDate, 'X'])
frozen[item[3]] = 'X'
G.tabSchedule.append([order,part, item[3],station,item[7],startDate,dateOut])
if station not in takenPeriods:
takenPeriods[station] = {}
takenPeriods[station][startDate] = {'endDate': dateOut, 'taskID':item[3]}
PMschedule = data['result']['result_list'][0]['operator_gantt']['task_list']
for item in PMschedule:
if 'parent' in item.keys():
pm = item['parent']
startDate = dateToOrdinal(item['start_date'], "%d-%m-%Y %H:%M")
stopDate = dateToOrdinal(item['stop_date'], "%d-%m-%Y %H:%M")
ordinalOutDate = excel_date(stopDate.date())
taskID = item['text'].split()[0]
print pm, taskID
pt = float((stopDate-startDate).seconds)/3600
if taskID == 'off-shift':
continue
if pt:
print pm, taskID
if pm not in takenPeriods:
takenPeriods[pm] = {}
takenPeriods[pm][startDate] = {'endDate': stopDate, 'taskID': taskID}
print 'frozen operations', forzenOpsData
print 'taken periods', takenPeriods
#=================================
# Import Workplan from Excel file
#=================================
global numParts
scenario = 'SIMPLE_2.xlsx'
wb = xlrd.open_workbook(scenario)
WorkPlan = wb.sheet_by_index(0)
Projects = {}
OrderDates = {}
DueDates = {}
Shift = {}
seqPrjDone = {}
# FIXME: importare data riferimento
td = dt.datetime(2015,07,23)
xlreftime = excel_date(td)
for i in range(WorkPlan.nrows):
i += 1
if i < WorkPlan.nrows: #for the first line of the project name
if WorkPlan.cell_value(i,2) != '' and WorkPlan.cell_value(i,6) != '':
Projects[WorkPlan.cell_value(i,2)] = {}
print 'order date', xlrd.xldate_as_tuple(WorkPlan.cell_value(i,3), wb.datemode)
oyear, omonth, oday, ohour, ominute, osecond = xlrd.xldate_as_tuple(WorkPlan.cell_value(i,3), wb.datemode)
if ohour < 8:
ohour = 8
OrderDates[WorkPlan.cell_value(i,2)] = dt.datetime(oyear, omonth, oday, ohour, ominute, osecond) #FIXME: perche cosi?
DueDates[WorkPlan.cell_value(i,2)] = (xlreftime + WorkPlan.cell_value(i,4))
header = i
current = WorkPlan.cell_value(header,2)
seqPrjDone[current] = {}
#for a part whose name is not in the first line
if str(WorkPlan.cell_value(i,13)).split(';'+' ')[0].upper() == 'ALL':
prerq = []
for wpid in range(header,i):
prerq.append(str(WorkPlan.cell_value(wpid,14)))
else:
prerq = str(WorkPlan.cell_value(i,13)).split(';'+' ')
if len(prerq) == 1 and prerq[0]=='':
prerq=[]
if WorkPlan.cell_value(i,6) == '':
continue
Projects[current].setdefault(WorkPlan.cell_value(i,6),[]).append({'id':str(WorkPlan.cell_value(i,14)), 'personnel':str(WorkPlan.cell_value(i,10)),
'pt': WorkPlan.cell_value(i,12), 'qty':WorkPlan.cell_value(i,11), 'preReq': prerq,
'operation': str(WorkPlan.cell_value(i,8)), 'sequence':WorkPlan.cell_value(i,9),
'project':current, 'part':WorkPlan.cell_value(i,6)})
seqPrjDone[current].setdefault(WorkPlan.cell_value(i,6),0)
print 'workplan', Projects
print 'sequence', seqPrjDone
#==================================
# Import shift data from json file
#==================================
offShiftTimes = {}
stRtstOp = {}
unitTime = 'Hours'
# default shift times are hard coded as there is no correspondence with json file
# 7:00 - 18:00 are standard shift times
defaultStartShift = 8.0/24
defaultEndShift = 18.0/24
stRtstOp['Default'] = [defaultStartShift,defaultEndShift]
shiftData = data['input']["shift_spreadsheet"]
for item in shiftData:
if 'Date' in item:
continue
if item[1] == '' or item[1]== None:
continue
currDate = excel_date(dateToOrdinal(item[1], "%Y/%m/%d").date())
cDate = dateToOrdinal(item[1], "%Y/%m/%d").date()
print item[2], item[3]
if item[2] == '' or item[2]== None:
shiftStart = defaultStartShift
else:
shiftStart = dt.datetime.strptime(item[2],'%H:%M')
if item[3] == '' or item[3]== None:
shiftEnd = defaultEndShift
else:
shiftEnd = dt.datetime.strptime(item[3],'%H:%M')
if item[4] == '' or item[4]== None:
offshiftPeriods = {}
else:
offshiftPeriods = offShiftFormat_2(item[4],cDate)
if item[0] != '':#the first line for an operator
currResc = item[0]
if currResc not in offShiftTimes:#no previous entry for the operator
offShiftTimes[currResc] = {}
offShiftTimes[currResc] = offshiftPeriods
stRtstOp[currResc] = {}
stRtstOp[currResc][cDate] = [shiftStart.time(),shiftEnd.time()]
else:
offShiftTimes[currResc] = offshiftPeriods
else:
offShiftTimes[currResc][cDate] = offshiftPeriods
stRtstOp[currResc][cDate] = [shiftStart,shiftEnd]
print 'off shift time', offShiftTimes
offShifts = dict((k,{}) for k in offShiftTimes.keys() + takenPeriods.keys())
for rsce in offShifts.keys():
if rsce in takenPeriods:
offShifts[rsce] = takenPeriods[rsce] #directly copy everything from the extracted dict
if rsce in offShiftTimes:#if that resource is present in the directly specified
for dte in offShiftTimes[rsce]:
if dte not in offShifts[rsce]:#if this date was not originally specified
offShifts[rsce][dte] = offShiftTimes[rsce][dte]
else:
starts = offShifts[rsce][dte]['Start']
stops = offShifts[rsce][dte]['Stop']
starts.extend(offShiftTimes[rsce][dte]['Start'])
stops.extend(offShiftTimes[rsce][dte]['Stop'])
u = list(set(starts))
v = list(set(stops))
offShifts[rsce][dte]['Start'] = u
offShifts[rsce][dte]['Stop'] = v
offShifts[rsce][dte]['Start'].sort()
offShifts[rsce][dte]['Stop'].sort()
print 'stRtstOp', stRtstOp
print 'off shift', offShifts
#==================================================
# Import machine and pm information from json file
#==================================================
MachInfo = []
MachPool = {}
PMInfo = []
PMPool = {}
stationTechnologies = {"CAD1": ["ENG", "CAD"], # XXX CAD1 is considered different than CAD2, they are not equivalent
"CAD2": ["CAD"],
"CAM": ["CAM"],
"MILL": ["MILL"],
"TURN": ["TURN"],
"DRILL": ["DRILL"],
"EDM": ["EDM"],
"WORK": ["QUAL", "MAN"], # XXX currently we consider different stations for QUAL/MAN and ASSM
"ASSM": ["ASSM"],
"INJM": ["INJM"]}
possMachines = data['graph']['node']
for mach in possMachines.keys():
if 'machine' in possMachines[mach]['_class'].lower() or 'assembly' in possMachines[mach]['_class'].lower():
capacity = 1
initials = len(mach)
while initials>0 and mach[:initials] not in stationTechnologies:
initials -= 1
pool = stationTechnologies[mach[:initials]]
MachInfo.append({'name': mach, 'cap':capacity, 'tech':pool, 'sched':'FIFO'})
for tec in pool:
MachPool.setdefault(tec,[]).append(mach)
print MachInfo
print 'mach pool', MachPool
PMskills = data['input']['operator_skills_spreadsheet']
for item in range(1,len(PMskills)):
if PMskills[item][0] == None or PMskills[item][0] == '':
continue
skills = PMskills[item][1].split(';'+' ')
if 'INJM-MAN' in skills:
skills.remove('INJM-MAN')
skills.append('INJM')
PMInfo.append({'name':PMskills[item][0], 'skills': skills, 'sched':'FIFO', 'status':''})
for sk in skills:
PMPool.setdefault(sk,[]).append(PMskills[item][0])
print PMInfo
print 'pm pool', PMPool
print '======================',offShifts
shiftRes = {}
resAvailability = {}
for item in PMInfo:
pm = item['name']
shiftRes[pm] = shiftGenerator(startSimDate,7)
resAvailability[pm] = deepcopy(shiftRes[pm])
if pm in offShifts:
for unavailDate in offShifts[pm].keys():
print pm, unavailDate, offShifts[pm][unavailDate]['endDate']-unavailDate
resAvailability[pm] = availableTime_Shift(unavailDate,offShifts[pm][unavailDate]['endDate'],resAvailability[pm])
print 'shift', pm, shiftRes[pm]
print 'shift', pm, resAvailability[pm]
for item in MachInfo:
mach = item['name']
shiftRes[mach] = shiftGenerator(startSimDate,7)
resAvailability[mach] = deepcopy(shiftRes[mach])
if mach in offShifts:
for unavailDate in offShifts[mach].keys():
print mach, unavailDate, offShifts[mach][unavailDate]['endDate']-unavailDate
resAvailability[mach] = availableTime_Shift(unavailDate,offShifts[mach][unavailDate]['endDate'],resAvailability[mach])
print 'shift', mach, shiftRes[mach]
print 'shift', mach, resAvailability[mach]
# set global variables
G.resAvailability = deepcopy(resAvailability)
G.seqPrjDone = deepcopy(seqPrjDone)
G.resAvailability = deepcopy(resAvailability)
G.MachPool = deepcopy(MachPool)
G.PMPool = deepcopy(PMPool)
G.Projects = deepcopy(Projects)
G.xlreftime = td
G.OrderDates = deepcopy(OrderDates)
G.completionDate = deepcopy(OrderDates)
'''
Created on 6 Aug 2015
@author: Anna
'''
import datetime as dt
from copy import deepcopy
def shiftGenerator(startDate, noDays):
shift = {}
day = 0
actualDays = 0
preDay = deepcopy(startDate.date())
while actualDays < noDays:
st = deepcopy(startDate)
if day:
dateStart = st.date()
dateStart += dt.timedelta(days=day)
st = dt.datetime(dateStart.year,dateStart.month, dateStart.day, 8,0)
if st.weekday() < 5:
fin = dt.datetime(st.year, st.month, st.day, 18,0)
shift[st] = {'end':fin, 'startMode':'SOS', 'endMode':'EOS', 'preDay':preDay}
preDay = st.date()
actualDays += 1
day += 1
return shift
if __name__ == '__main__':
shift = shiftGenerator(dt.datetime(2015,8,4,12,00),10)
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