Divide Operationsmodes and types and add its functions to TrainRunCalc and EnergySaving

development
Max Kannenberg 2022-01-19 16:58:57 +01:00
parent 43a36b92db
commit 05c1bd8d52
10 changed files with 529 additions and 551 deletions

View File

@ -6,7 +6,7 @@ settings:
stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "v in m/s"
stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s)
operationModeMinimumRunningTime: true # operation mode "minimum running time"
operationModeMinimumEnergyConsumption: true # operation mode "minimum energy consumption"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
detailOfOutput: "driving course" # should the output be "minimal" or "driving course"?
csvDirectory: "~/Desktop/TrainRun"

View File

@ -29,7 +29,8 @@ for path in allPaths
for train in allTrains
# println("train: ", train)
for settings in allSettings
testDict=calculateDrivingDynamics(train, path, settings)
resultsDict=calculateDrivingDynamics(train, path, settings)
exportToCsv(resultsDict)
sleep(2)
# println("")
end

View File

@ -1,17 +1,430 @@
# INFO: EnergySaving should not be used because it is not completed yet. It was used to show the possiility of calculating different operation modes.
# TODO: It has to be optimized so that each ernergy saving merhode is working individually for every train on every path.
# TODO: calculation time for passenger trains on path1 is very long and should be reduced
#TODO: Test if enum trainType is working correctly in function calculateRecoveryTime or if only the else-pathis taken
module EnergySaving
using ..types
using ..MovingPhases
# include modules of TrainRunCalc
include("./MovingPhases.jl")
export calculateRecoveryTime, increaseCoastingSection, decreaseMaximumVelocity, combineEnergySavingMethods
# use modules of TrainRunCalc
using .MovingPhases
export addOperationModeEnergySaving!
@enum trainType passenger=1 freight=2 motorCoachTrain=3
approximationLevel = 6 # value for approximation to intersections
# TODO: define it in TrainRun and give it to each function?
## functions for calculating the operation mode for the minimum energy consumption
# calculate the train run for operation mode "minimum energy consumption"
function addOperationModeEnergySaving!(summarizedDict::Dict)
if summarizedDict[:settings][:operationModeMinimumEnergyConsumption] == true
movingSectionMinimumRunningTime = summarizedDict[:movingSectionMinimumRunningTime]
drivingCourseMinimumRunningTime = summarizedDict[:drivingCourseMinimumRunningTime]
settings = summarizedDict[:settings]
train = summarizedDict[:train]
(movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train)
println("The driving course for the lowest energy consumption has been calculated.")
# summarize data and create an output dictionary
merge!(summarizedDict, Dict(:movingSectionMinimumEnergyConsumption => movingSectionMinimumEnergyConsumption, :drivingCourseMinimumEnergyConsumption => drivingCourseMinimumEnergyConsumption))
else
println("No output for minimum energy consumption has been demanded and so none will be calculated")
end #if
return summarizedDict
end #function addOperationModeEnergySaving!
function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict, drivingCourseMinimumRunningTime::Vector{Dict}, settings::Dict, train::Dict)
# calculate a train run focussing on using the minimum possible energy consumption
# booleans for choosing which methods are used for saving energy
doMethod1=true
#doMethod1=false
doMethod2=true
#doMethod2=false
doCombinationOfMethods=true
#doCombinationOfMethods=false
# create a new driving course for the minimum energy consumption
drivingCourseOriginal = copy(drivingCourseMinimumRunningTime)
#create a new moving section for the minimum energy consumption
movingSectionOriginal=copyMovingSection(movingSectionMinimumRunningTime)
# 01/09 old not sure if just copy is enough.. : movingSectionOriginal=copy(movingSectionMinimumRunningTime)
CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections]
merge!(movingSectionOriginal, Dict(:energySavingModifications => [])) # list containing all the used energy saving modifications
# calculate the recovery time
t_recovery=calculateRecoveryTime(movingSectionOriginal[:length], movingSectionOriginal[:t], train)
merge!(movingSectionOriginal, Dict(:t_recovery=>t_recovery)) # total recovery time for energy-saving modifications (in s)
merge!(movingSectionOriginal, Dict(:t_recoveryAvailable => t_recovery)) # still available recovery time for energy-saving modifications (in s) initialized with the total recovery time
# create arrays for each method with all the available energy saving modifications
energySavingModificationsWithCoasting=Dict[]
energySavingModificationsWithMaximumSpeed=Dict[]
energySavingModificationsWithCombination=Dict[]
for csId in 1:length(CSsOrig)
# method 1: increase coasting
if doMethod1 == true
modificationType = "increasing coasting"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithCoasting, energySavingModification)
end #if doMethod1
# method 2: accelerate to a lower v_peak
if doMethod2 == true
modificationType = "decreasing maximum velocity"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithMaximumSpeed, energySavingModification)
end #if doMethod2
# calculate the combination of the previous methods
if doCombinationOfMethods == true
modificationType = "combination of energy saving methods"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithCombination, energySavingModification)
end #if
end # for
# 01/03 old wit too long calculation time: while movingSectionOriginal[:t_recoveryAvailable] > 0.0
while movingSectionOriginal[:t_recoveryAvailable] >= 1/(10^approximationLevel)
# compare modifications
ratioMax=0.0
csIdMax=0
typeMax="none"
(energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
(energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
(energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
# select the most efficient modification and update the original characteristicSection, drivingCourse and movingSection
# in case none of the modifications has a ratio>0 stop the calculation
if typeMax=="none"
break
elseif typeMax=="increasing coasting"
# println("Energy saving modification number ",length(movingSectionOriginal[:energySavingModifications])+1," (coasting) in CS ",csIdMax ," Δt=",energySavingModificationsWithCoasting[csIdMax][:Δt]," ΔE=", energySavingModificationsWithCoasting[csIdMax][:ΔE]," t_recoveryAvailable=", movingSectionOriginal[:t_recoveryAvailable]-energySavingModificationsWithCoasting[csIdMax][:Δt])
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCoasting[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=increasing coasting")
elseif typeMax=="decreasing maximum velocity"
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithMaximumSpeed[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=decreasing maximum velocity")
elseif typeMax=="combination of energy saving methods"
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCombination[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=combination of energy saving methods")
end #if
movingSectionOriginal[:t_recoveryAvailable] = movingSectionOriginal[:t_recoveryAvailable] - movingSectionOriginal[:energySavingModifications][end][:Δt]
lastIdOfSelectedCsOriginal = get(CSsOrig[csIdMax][:behaviorSections], :standstill,
get(CSsOrig[csIdMax][:behaviorSections], :braking,
get(CSsOrig[csIdMax][:behaviorSections], :coasting,
get(CSsOrig[csIdMax][:behaviorSections], :cruising,
get(CSsOrig[csIdMax][:behaviorSections], :acceleration,
get(CSsOrig[csIdMax][:behaviorSections], :clearing,
get(CSsOrig[csIdMax][:behaviorSections], :breakFree,
get(CSsOrig[csIdMax][:behaviorSections], :diminishing,
Dict(:dataPoints => [0])))))))))[:dataPoints][end]
# if there is a diminishing phase its location must be analysed seperately because it could be before acceleration, between acceleration and cruising or after cruising. All the other behavior sections occure in a fixed order.
if haskey(CSsOrig[csIdMax][:behaviorSections], :diminishing)
lastIdOfSelectedCsOriginal = max(lastIdOfSelectedCsOriginal, CSsOrig[csIdMax][:behaviorSections][:diminishing][:dataPoints][end])
end
# create new driving course
drivingCourseNew = copy(movingSectionOriginal[:energySavingModifications][end][:drivingCourseModified])
#fill up the rest of the driving course with information from the original course
drivingCourseNew[end][:F_T]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_T]
drivingCourseNew[end][:R_traction]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_traction]
drivingCourseNew[end][:R_wagons]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_wagons]
drivingCourseNew[end][:R_train]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_train]
drivingCourseNew[end][:R_path]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_path]
drivingCourseNew[end][:F_R]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_R]
drivingCourseNew[end][:a]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:a]
endOfModificationId=drivingCourseNew[end][:i] # is needed for updating the other modified driving courses
difference=endOfModificationId-lastIdOfSelectedCsOriginal
i=lastIdOfSelectedCsOriginal+1
while i <= length(drivingCourseOriginal)
push!(drivingCourseNew, copy(drivingCourseOriginal[i]))
drivingCourseNew[end][:i]=length(drivingCourseNew)
drivingCourseNew[end][:t]=drivingCourseNew[end-1][:t]+drivingCourseNew[end][:Δt]
drivingCourseNew[end][:E]=drivingCourseNew[end-1][:E]+drivingCourseNew[end][:ΔE]
drivingCourseNew[end][:W]=drivingCourseNew[end-1][:W]+drivingCourseNew[end][:ΔW]
i=i+1
end # while
# replace the original driving course and CS with the new modified ones
drivingCourseOriginal=drivingCourseNew
CSsOrig[csIdMax]=copyCharacteristicSection(movingSectionOriginal[:energySavingModifications][end][:csModified])
# 01/09 old with copy: CSsOrig[csIdMax]=copy(movingSectionOriginal[:energySavingModifications][end][:csModified])
movingSectionOriginal[:t]=drivingCourseOriginal[end][:t] # total running time (in s)
movingSectionOriginal[:E]=drivingCourseOriginal[end][:E] # total energy consumption (in Ws)
# update all the data point references in the behaviour sections of the following characteristic sections and the other modified characteristic sections
if difference!= 0
# update the data point references in the behaviour sections of the following characteristic sections
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
for csId in csIdMax+1:length(CSsOrig)
for bs in 1: length(allBs)
if haskey(CSsOrig[csId][:behaviorSections], allBs[bs])
for point in 1:length(CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints])
CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point] = CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point]+difference
end
end #if
end #for
end #for
# update the data points in the following modified charateristic sections and the following points in the driving course
energySavingModificationsWithCoasting = updateEnergySavingModifications!(energySavingModificationsWithCoasting, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
energySavingModificationsWithMaximumSpeed = updateEnergySavingModifications!(energySavingModificationsWithMaximumSpeed, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
energySavingModificationsWithCombination = updateEnergySavingModifications!(energySavingModificationsWithCombination, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
end # if difference
# modify new CS for the considered methods
# method 1: increase coasting
if doMethod1==true
modificationType = "increasing coasting"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithCoasting[csIdMax]=energySavingModification
end #if if doMethod1
# method 2: accelerate to a lower v_peak
if doMethod2==true
modificationType = "decreasing maximum velocity"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithMaximumSpeed[csIdMax]=energySavingModification
end #if if doMethod
# combination of both methods
if doCombinationOfMethods==true
modificationType = "combination of energy saving methods"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithCombination[csIdMax]=energySavingModification
end #if doCombinationOfMethods
end # while
(CSsOrig[end], drivingCourseOriginal) = addStandstill!(CSsOrig[end], drivingCourseOriginal, settings, train, CSsOrig)
println("t_recoveryAvailable=",movingSectionOriginal[:t_recoveryAvailable])
return (movingSectionOriginal, drivingCourseOriginal)
end #function calculateMinimumEnergyConsumption
## copy the different sections the whole path can be devided in
function copyMovingSection(original::Dict)
copiedCSs = Vector{Dict}()
for csId in 1:length(original[:characteristicSections])
push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId]))
# 01/07 old without copy: push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId]))
end #for
copiedMS = Dict(:id => original[:id], # identifier
:length => original[:length], # total length (in m)
:s_entry => original[:s_entry], # first position (in m)
:s_exit => original[:s_exit], # last position (in m)
:t => original[:t], # total running time (in s)
:E => original[:E], # total energy consumption (in Ws)
:characteristicSections => copiedCSs) # list of containing characteristic sections
if haskey(original, :energySavingModifications) # list of containing all the used energy saving modifications
copiedModifications = Dict[]
for modId in 1:length(original[:energySavingModifications])
push!(copiedModifications, copyEnergySavingModification(original[:energySavingModifications][modId]))
end #for
merge!(copiedMS, Dict(:energySavingModifications => copiedModifications))
end
if haskey(original, :t_recovery) # total recovery time for energy-saving modifications (in s)
merge!(copiedMS, Dict(:t_recovery => original[:t_recovery]))
end
if haskey(original, :t_recoveryAvailable) # still available recovery time for energy-saving modifications (in s)
merge!(copiedMS, Dict(:t_recoveryAvailable => original[:t_recoveryAvailable]))
end
return copiedMS
end #function copyMovingSection
function copyCharacteristicSection(originalCS::Dict)
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
copiedBSs = Dict()
for bs in 1: length(allBs)
if haskey(originalCS[:behaviorSections], allBs[bs])
merge!(copiedBSs, Dict(allBs[bs] => originalCS[:behaviorSections][allBs[bs]]))
end #if
end #for
copiedCS=Dict(:id => originalCS[:id], # identifier
:s_entry => originalCS[:s_entry], # first position (in m)
:s_exit => originalCS[:s_exit], # last position (in m)
:length => originalCS[:length], # total length (in m)
:r_path => originalCS[:r_path], # path resistance (in ‰)
# :behaviorSections => copy(originalCS[:behaviorSections]), # list of containing behavior sections
:behaviorSections => copiedBSs, # list of containing behavior sections
:t => originalCS[:t], # total running time (in s)
:E => originalCS[:E], # total energy consumption (in Ws)
:v_limit => originalCS[:v_limit], # speed limit (in m/s)
:v_peak => originalCS[:v_peak], # maximum reachable speed (in m/s)
:v_entry => originalCS[:v_entry], # maximum entry speed (in m/s)
:v_exit => originalCS[:v_exit]) # maximum exit speed (in m/s)
return copiedCS
end # CharacteristicSection
# smallest section of the path is the behavior section. It relates to the containing data points via their identifier.
function copyBehaviorSection(original::Dict)
bsDataPoints=[]
for i in 1:length(original[:dataPoints])
push!(bsDataPoints, original[:dataPoints][i])
end
copiedBS = Dict(#:type => behavior, # type of behavior section: breakFree, clearing, acceleration, cruising, diminishing, coasting, braking or standstill
:type => original[:type], # type of behavior section: "breakFree", "clearing", "acceleration", "cruising", "diminishing", "coasting", "braking" or "standstill"
:length => original[:length], # total length (in m)
:s_entry => original[:s_entry], # first position (in m)
:s_exit => original[:s_exit], # last position (in m)
:t => original[:t], # total running time (in s)
:E => original[:E], # total energy consumption (in Ws)
:v_entry => original[:v_entry], # entry speed (in m/s)
:v_exit => original[:v_exit], # exit speed (in m/s)
:dataPoints => bsDataPoints) # list of identifiers of the containing data points
return copiedBS
end #function copyBehaviorSection
## for the energy saving operation mode it is nesserary to compare different energy saving modifications. These are part of the moving section.
function createEnergySavingModification()
energySavingModification = Dict(:csId => 0, # identifier of the characteristic section
:type => "", # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:ΔE => 0.0, # saved energy (in Ws)
:Δt => 0.0, # time loss (in s)
:ratio => 0.0, # ratio of ΔE and Δt (in Ws/s)
:csModified => Dict(), # the modified characteristic section
:drivingCourseModified => []) # drivingCourse for the modified characteristic section
end #createEnergySavingModification
function updateEnergySavingModifications!(energySavingModifications::Vector{Dict}, csIdMax::Integer, drivingCourseNew::Vector{Dict}, endOfModificationId::Integer, lastIdOfSelectedCsOriginal::Integer)
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
difference = endOfModificationId-lastIdOfSelectedCsOriginal
for modNr in csIdMax+1:length(energySavingModifications)
if energySavingModifications[modNr][:ratio]>0
BSs = energySavingModifications[modNr][:csModified][:behaviorSections]
# update the behavior sections of the modified charateristic section
for bs in 1: length(allBs)
if haskey(BSs, allBs[bs])
for point in 1:length(BSs[allBs[bs]][:dataPoints])
BSs[allBs[bs]][:dataPoints][point] = BSs[allBs[bs]][:dataPoints][point] + difference
end
end #if
end #for
# correct the points of previous CS in the modified driving course. Copy the new driving course till the beginning of the current CS and change total values of the current modified CS data points accordingly
drivingCourseModifiedNew = copy(drivingCourseNew[1:endOfModificationId])
i=lastIdOfSelectedCsOriginal+1
while i <= length(energySavingModifications[modNr][:drivingCourseModified])
push!(drivingCourseModifiedNew, copy(energySavingModifications[modNr][:drivingCourseModified][i]))
drivingCourseModifiedNew[end][:i]=length(drivingCourseModifiedNew)
drivingCourseModifiedNew[end][:t]=drivingCourseModifiedNew[end-1][:t]+drivingCourseModifiedNew[end][:Δt]
drivingCourseModifiedNew[end][:E]=drivingCourseModifiedNew[end-1][:E]+drivingCourseModifiedNew[end][:ΔE]
drivingCourseModifiedNew[end][:W]=drivingCourseModifiedNew[end-1][:W]+drivingCourseModifiedNew[end][:ΔW]
i=i+1
end # while
energySavingModifications[modNr][:drivingCourseModified] = drivingCourseModifiedNew
end #if
end #for
return energySavingModifications
end #function updateEnergySavingModifications!
function copyEnergySavingModification(modificaionOriginal::Dict)
modificaionCopy = Dict(:csId => modificaionOriginal[:csId], # identifier of the characteristic section
:type => modificaionOriginal[:type], # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:ΔE => modificaionOriginal[:ΔE], # saved energy (in Ws)
:Δt => modificaionOriginal[:Δt], # time loss (in s)
:ratio => modificaionOriginal[:ratio], # ratio of ΔE and Δt (in Ws/s)
:csModified => copyCharacteristicSection(modificaionOriginal[:]), # the modified characteristic section
:drivingCourseModified => copy(modificaionOriginal[:drivingCourseModified])) # drivingCourse for the modified characteristic section
return modificaionCopy
end # copyEnergySavingModification
function modifyCs(movingSectionOriginal::Dict, drivingCourseOriginal::Vector{Dict}, csId::Integer, modificationType::String, settings::Dict, train::Dict)
# TODO: refactor and sort this function
CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections]
if modificationType == "increasing coasting"
# method 1: increase coasting
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=increaseCoastingSection(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
elseif modificationType == "decreasing maximum velocity"
# method 2: accelerate to a lower v_peak
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=decreaseMaximumVelocity(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
elseif modificationType == "combination of energy saving methods"
# calculate the combination of the previous methods
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=combineEnergySavingMethods(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
else
return createEnergySavingModification()
end
#energySavingModification = createEnergySavingModification()
if new
energySavingModification = Dict(:csId => csId, # identifier of the characteristic section
:type => modificationType, # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:csModified => characteristicSectionModified, # the modified characteristic section
:drivingCourseModified => drivingCourseModifiedUntilEndOfModifiedCS) # drivingCourse for the modified characteristic section
merge!(energySavingModification, Dict(:ΔE => CSsOrig[csId][:E] - energySavingModification[:csModified][:E])) # saved energy (in Ws)
merge!(energySavingModification, Dict(:Δt => energySavingModification[:csModified][:t] - CSsOrig[csId][:t])) # time loss (in s)
if energySavingModification[:Δt] <= movingSectionOriginal[:t_recoveryAvailable] && energySavingModification[:ΔE] >= 0.0
#*** TODO: check why "sign" is needed here
# if modificationType == "combination of energy saving methods"
ratio=sign(energySavingModification[:Δt])*energySavingModification[:ΔE]/energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s)
# else
# ratio = energySavingModification[:ΔE] / energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s)
# end
# ***
elseif energySavingModification[:Δt] == 0.0
ratio = energySavingModification[:ΔE]/0.000000001
else # Δt is to high or ΔE < 0.0 Ws
ratio = 0.0
end
merge!(energySavingModification, Dict(:ratio => ratio)) # ratio of ΔE and Δt (in Ws/s)
return energySavingModification
else
return createEnergySavingModification()
end
end #function modifyCs
function findBestModification(energySavingModifications::Vector{Dict}, ratioMax::AbstractFloat, csIdMax::Integer, typeMax::String, t_recoveryAvailable::AbstractFloat)
for modNr in 1:length(energySavingModifications)
if energySavingModifications[modNr][:ratio] > ratioMax
if energySavingModifications[modNr][:Δt] <= t_recoveryAvailable
ratioMax = energySavingModifications[modNr][:ratio]
csIdMax = energySavingModifications[modNr][:csId]
typeMax = energySavingModifications[modNr][:type]
else # Δt is to high
energySavingModifications[modNr][:ratio]=0.0
end #if
end #if
end #for
return (energySavingModifications, ratioMax, csIdMax, typeMax)
end #function findBestModification
## functions for calculating different energy saving methods that are used in calculateMinimumEnergyConsumption
function calculateRecoveryTime(s_MS::Real, t_MS::AbstractFloat, train::Dict)
# function for calculating the recovery time that can be used for energy saving
# MS: Moving Section
@ -495,7 +908,7 @@ function decreaseMaximumVelocity(csOriginal::Dict, drivingCourse, settings::Dict
energySavingStartId = accelerationSection[:dataPoints][end]
accelerationSection[:v_exit]=drivingCourse[energySavingStartId][:v] # exit speed (in m/s)
accelerationSection[:s_exit]=drivingCourse[energySavingStartId][:s] # last position (in m)
accelerationSection[:s_exit]=drivingCourse[energySavingStartId][:s] # last position (in m)
accelerationSection[:length]=accelerationSection[:s_exit]-accelerationSection[:s_entry] # total length (in m)
accelerationSection[:t]=drivingCourse[energySavingStartId][:t]-drivingCourse[accelerationSection[:dataPoints][1]][:t] # total running time (in s)
accelerationSection[:E]=drivingCourse[energySavingStartId][:E]-drivingCourse[accelerationSection[:dataPoints][1]][:E] # total energy consumption (in Ws)

View File

@ -1,6 +1,5 @@
module MovingPhases
using ..types
export addAccelerationPhase!, addAccelerationPhaseUntilBraking!, addCruisingPhase!, addCoastingPhaseUntilBraking!, addBrakingPhase!, addBrakingPhaseStepwise!, addStandstill!, calculateForces!
export createDataPoint
# addBrakingPhaseStepwise! is not used in the current version of the tool

View File

@ -1,446 +0,0 @@
module OperationModes
using ..types
include("./MovingPhases.jl")
include("./EnergySaving.jl")
using .MovingPhases
using .EnergySaving
export calculateMinimumRunningTime!, calculateMinimumEnergyConsumption
approximationLevel = 6 # TODO: define it in TrainRun and give it to each function?
# calculate a train run focussing on using the minimum possible running time
function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train::Dict)
CSs::Vector{Dict} = movingSection[:characteristicSections]
startingPoint=createDataPoint()
startingPoint[:i]=1
startingPoint[:s]=CSs[1][:s_entry]
drivingCourse::Vector{Dict} = [startingPoint] # List of data points
# for CS in CSs
for csId in 1:length(CSs)
# check if the CS has a cruising section
CS = CSs[csId]
BSs = CS[:behaviorSections]
s_breakFree = get(BSs, :breakFree, Dict(:length=>0.0))[:length]
s_clearing = get(BSs, :clearing, Dict(:length=>0.0))[:length]
s_acceleration = get(BSs, :acceleration, Dict(:length=>0.0))[:length]
s_braking = max(0.0, ceil((CS[:v_exit]^2-CS[:v_peak]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
# calculate the cruising sections length
s_cruising = CS[:length] - s_breakFree - s_clearing - s_acceleration - s_braking
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
# 01/07 old: delete!(BSs, :breakFree)
# 01/07 old: delete!(BSs, :clearing)
# 01/07 old: delete!(BSs, :acceleration)
# 01/07 old: delete!(BSs, :diminishing)
# 01/07 old: delete!(BSs, :cruising)
CS[:behaviorSections] = Dict()
CS[:E] = 0.0
CS[:t] = 0.0
if s_clearing == CS[:length]
# 09/06 TODO: thought about using "cruising" because it is used in EnergySaving and not clearing (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "cruising")
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing")
elseif s_cruising == CS[:length]
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
elseif s_cruising > 0.0 || s_braking == 0.0
# 09/21 elseif s_cruising > 0.0
# 09/21 elseif s_cruising > 0.01 # if the cruising section is longer than 1 cm (because of rounding issues not >0.0)
if drivingCourse[end][:v] < CS[:v_peak]
(CS, drivingCourse)=addAccelerationPhase!(CS, drivingCourse, settings, train, CSs)
end #if
if CS[:s_exit]-drivingCourse[end][:s]-max(0.0, (CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking]) < -0.001 # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
println("ERROR: After accelerating in CS ",csId," the braking distance is too short!")
println(" before acceleration in CS",csId, " with s=",drivingCourse[end][:s]," s_braking=",((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking])," s_exit=",CS[:s_exit])
println(" and v=",drivingCourse[end][:v]," v_peak=",CS[:v_peak]," v_exit=",CS[:v_exit])
end
s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
s_cruising=CS[:s_exit]-drivingCourse[end][:s]-s_braking
if s_cruising > 0.0
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
end
else
if CS[:v_entry] < CS[:v_peak] || s_acceleration > 0.0 # or instead of " || s_acceleration > 0.0" use "v_entry <= v_peak" or "v_i <= v_peak"
# 09/09 old (not sufficient for steep gradients): if CS[:v_entry] < CS[:v_peak]
(CS, drivingCourse)=addAccelerationPhaseUntilBraking!(CS, drivingCourse, settings, train, CSs)
end #if
end #if
s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
if drivingCourse[end][:v] > CS[:v_exit]
#(CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings[:massModel], train, CSs)
(CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings, train, CSs)
end #if
#= 09/20 old and should never be used:
if drivingCourse[end][:s] < CS[:s_exit]
if haskey(BSs, :cruising)
println("INFO: A second cruising section has been added to CS ", csId," from s=",drivingCourse[end][:s]," to s_exit=",CS[:s_exit])
end
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
end =#
end #for
(CSs[end], drivingCourse)=addStandstill!(CSs[end], drivingCourse, settings, train, CSs)
movingSection[:t] = drivingCourse[end][:t] # total running time (in s)
movingSection[:E] = drivingCourse[end][:E] # total energy consumption (in Ws)
return (movingSection, drivingCourse)
end #function calculateMinimumRunningTime
function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict, drivingCourseMinimumRunningTime::Vector{Dict}, settings::Dict, train::Dict)
# calculate a train run focussing on using the minimum possible energy consumption
# booleans for choosing which methods are used for saving energy
doMethod1=true
#doMethod1=false
doMethod2=true
#doMethod2=false
doCombinationOfMethods=true
#doCombinationOfMethods=false
# create a new driving course for the minimum energy consumption
drivingCourseOriginal = copy(drivingCourseMinimumRunningTime)
#create a new moving section for the minimum energy consumption
movingSectionOriginal=copyMovingSection(movingSectionMinimumRunningTime)
# 01/09 old not sure if just copy is enough.. : movingSectionOriginal=copy(movingSectionMinimumRunningTime)
CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections]
merge!(movingSectionOriginal, Dict(:energySavingModifications => [])) # list containing all the used energy saving modifications
# calculate the recovery time
t_recovery=calculateRecoveryTime(movingSectionOriginal[:length], movingSectionOriginal[:t], train)
merge!(movingSectionOriginal, Dict(:t_recovery=>t_recovery)) # total recovery time for energy-saving modifications (in s)
merge!(movingSectionOriginal, Dict(:t_recoveryAvailable => t_recovery)) # still available recovery time for energy-saving modifications (in s) initialized with the total recovery time
# create arrays for each method with all the available energy saving modifications
energySavingModificationsWithCoasting=Dict[]
energySavingModificationsWithMaximumSpeed=Dict[]
energySavingModificationsWithCombination=Dict[]
for csId in 1:length(CSsOrig)
# method 1: increase coasting
if doMethod1 == true
modificationType = "increasing coasting"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithCoasting, energySavingModification)
end #if doMethod1
# method 2: accelerate to a lower v_peak
if doMethod2 == true
modificationType = "decreasing maximum velocity"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithMaximumSpeed, energySavingModification)
end #if doMethod2
# calculate the combination of the previous methods
if doCombinationOfMethods == true
modificationType = "combination of energy saving methods"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train)
push!(energySavingModificationsWithCombination, energySavingModification)
end #if
end # for
# 01/03 old wit too long calculation time: while movingSectionOriginal[:t_recoveryAvailable] > 0.0
while movingSectionOriginal[:t_recoveryAvailable] >= 1/(10^approximationLevel)
# compare modifications
ratioMax=0.0
csIdMax=0
typeMax="none"
(energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
(energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
(energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable])
# select the most efficient modification and update the original characteristicSection, drivingCourse and movingSection
# in case none of the modifications has a ratio>0 stop the calculation
if typeMax=="none"
break
elseif typeMax=="increasing coasting"
# println("Energy saving modification number ",length(movingSectionOriginal[:energySavingModifications])+1," (coasting) in CS ",csIdMax ," Δt=",energySavingModificationsWithCoasting[csIdMax][:Δt]," ΔE=", energySavingModificationsWithCoasting[csIdMax][:ΔE]," t_recoveryAvailable=", movingSectionOriginal[:t_recoveryAvailable]-energySavingModificationsWithCoasting[csIdMax][:Δt])
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCoasting[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=increasing coasting")
elseif typeMax=="decreasing maximum velocity"
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithMaximumSpeed[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=decreasing maximum velocity")
elseif typeMax=="combination of energy saving methods"
push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCombination[csIdMax])
# println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=combination of energy saving methods")
end #if
movingSectionOriginal[:t_recoveryAvailable] = movingSectionOriginal[:t_recoveryAvailable] - movingSectionOriginal[:energySavingModifications][end][:Δt]
lastIdOfSelectedCsOriginal = get(CSsOrig[csIdMax][:behaviorSections], :standstill,
get(CSsOrig[csIdMax][:behaviorSections], :braking,
get(CSsOrig[csIdMax][:behaviorSections], :coasting,
get(CSsOrig[csIdMax][:behaviorSections], :cruising,
get(CSsOrig[csIdMax][:behaviorSections], :acceleration,
get(CSsOrig[csIdMax][:behaviorSections], :clearing,
get(CSsOrig[csIdMax][:behaviorSections], :breakFree,
get(CSsOrig[csIdMax][:behaviorSections], :diminishing,
Dict(:dataPoints => [0])))))))))[:dataPoints][end]
# if there is a diminishing phase its location must be analysed seperately because it could be before acceleration, between acceleration and cruising or after cruising. All the other behavior sections occure in a fixed order.
if haskey(CSsOrig[csIdMax][:behaviorSections], :diminishing)
lastIdOfSelectedCsOriginal = max(lastIdOfSelectedCsOriginal, CSsOrig[csIdMax][:behaviorSections][:diminishing][:dataPoints][end])
end
# create new driving course
drivingCourseNew = copy(movingSectionOriginal[:energySavingModifications][end][:drivingCourseModified])
#fill up the rest of the driving course with information from the original course
drivingCourseNew[end][:F_T]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_T]
drivingCourseNew[end][:R_traction]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_traction]
drivingCourseNew[end][:R_wagons]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_wagons]
drivingCourseNew[end][:R_train]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_train]
drivingCourseNew[end][:R_path]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_path]
drivingCourseNew[end][:F_R]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_R]
drivingCourseNew[end][:a]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:a]
endOfModificationId=drivingCourseNew[end][:i] # is needed for updating the other modified driving courses
difference=endOfModificationId-lastIdOfSelectedCsOriginal
i=lastIdOfSelectedCsOriginal+1
while i <= length(drivingCourseOriginal)
push!(drivingCourseNew, copy(drivingCourseOriginal[i]))
drivingCourseNew[end][:i]=length(drivingCourseNew)
drivingCourseNew[end][:t]=drivingCourseNew[end-1][:t]+drivingCourseNew[end][:Δt]
drivingCourseNew[end][:E]=drivingCourseNew[end-1][:E]+drivingCourseNew[end][:ΔE]
drivingCourseNew[end][:W]=drivingCourseNew[end-1][:W]+drivingCourseNew[end][:ΔW]
i=i+1
end # while
# replace the original driving course and CS with the new modified ones
drivingCourseOriginal=drivingCourseNew
CSsOrig[csIdMax]=copyCharacteristicSection(movingSectionOriginal[:energySavingModifications][end][:csModified])
# 01/09 old with copy: CSsOrig[csIdMax]=copy(movingSectionOriginal[:energySavingModifications][end][:csModified])
movingSectionOriginal[:t]=drivingCourseOriginal[end][:t] # total running time (in s)
movingSectionOriginal[:E]=drivingCourseOriginal[end][:E] # total energy consumption (in Ws)
# update all the data point references in the behaviour sections of the following characteristic sections and the other modified characteristic sections
if difference!= 0
# update the data point references in the behaviour sections of the following characteristic sections
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
for csId in csIdMax+1:length(CSsOrig)
for bs in 1: length(allBs)
if haskey(CSsOrig[csId][:behaviorSections], allBs[bs])
for point in 1:length(CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints])
CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point] = CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point]+difference
end
end #if
end #for
end #for
# update the data points in the following modified charateristic sections and the following points in the driving course
energySavingModificationsWithCoasting = updateEnergySavingModifications!(energySavingModificationsWithCoasting, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
energySavingModificationsWithMaximumSpeed = updateEnergySavingModifications!(energySavingModificationsWithMaximumSpeed, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
energySavingModificationsWithCombination = updateEnergySavingModifications!(energySavingModificationsWithCombination, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal)
end # if difference
# modify new CS for the considered methods
# method 1: increase coasting
if doMethod1==true
modificationType = "increasing coasting"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithCoasting[csIdMax]=energySavingModification
end #if if doMethod1
# method 2: accelerate to a lower v_peak
if doMethod2==true
modificationType = "decreasing maximum velocity"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithMaximumSpeed[csIdMax]=energySavingModification
end #if if doMethod
# combination of both methods
if doCombinationOfMethods==true
modificationType = "combination of energy saving methods"
energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train)
energySavingModificationsWithCombination[csIdMax]=energySavingModification
end #if doCombinationOfMethods
end # while
(CSsOrig[end], drivingCourseOriginal) = addStandstill!(CSsOrig[end], drivingCourseOriginal, settings, train, CSsOrig)
println("t_recoveryAvailable=",movingSectionOriginal[:t_recoveryAvailable])
return (movingSectionOriginal, drivingCourseOriginal)
end #function calculateMinimumEnergyConsumption
function modifyCs(movingSectionOriginal::Dict, drivingCourseOriginal::Vector{Dict}, csId::Integer, modificationType::String, settings::Dict, train::Dict)
# TODO: refactor and sort this function
CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections]
if modificationType == "increasing coasting"
# method 1: increase coasting
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=increaseCoastingSection(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
elseif modificationType == "decreasing maximum velocity"
# method 2: accelerate to a lower v_peak
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=decreaseMaximumVelocity(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
elseif modificationType == "combination of energy saving methods"
# calculate the combination of the previous methods
(characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=combineEnergySavingMethods(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable])
else
return createEnergySavingModification()
end
#energySavingModification = createEnergySavingModification()
if new
energySavingModification = Dict(:csId => csId, # identifier of the characteristic section
:type => modificationType, # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:csModified => characteristicSectionModified, # the modified characteristic section
:drivingCourseModified => drivingCourseModifiedUntilEndOfModifiedCS) # drivingCourse for the modified characteristic section
merge!(energySavingModification, Dict(:ΔE => CSsOrig[csId][:E] - energySavingModification[:csModified][:E])) # saved energy (in Ws)
merge!(energySavingModification, Dict(:Δt => energySavingModification[:csModified][:t] - CSsOrig[csId][:t])) # time loss (in s)
if energySavingModification[:Δt] <= movingSectionOriginal[:t_recoveryAvailable] && energySavingModification[:ΔE] >= 0.0
#*** TODO: check why "sign" is needed here
# if modificationType == "combination of energy saving methods"
ratio=sign(energySavingModification[:Δt])*energySavingModification[:ΔE]/energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s)
# else
# ratio = energySavingModification[:ΔE] / energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s)
# end
# ***
elseif energySavingModification[:Δt] == 0.0
ratio = energySavingModification[:ΔE]/0.000000001
else # Δt is to high or ΔE < 0.0 Ws
ratio = 0.0
end
merge!(energySavingModification, Dict(:ratio => ratio)) # ratio of ΔE and Δt (in Ws/s)
return energySavingModification
else
return createEnergySavingModification()
end
end #function modifyCs
function findBestModification(energySavingModifications::Vector{Dict}, ratioMax::AbstractFloat, csIdMax::Integer, typeMax::String, t_recoveryAvailable::AbstractFloat)
for modNr in 1:length(energySavingModifications)
if energySavingModifications[modNr][:ratio] > ratioMax
if energySavingModifications[modNr][:Δt] <= t_recoveryAvailable
ratioMax = energySavingModifications[modNr][:ratio]
csIdMax = energySavingModifications[modNr][:csId]
typeMax = energySavingModifications[modNr][:type]
else # Δt is to high
energySavingModifications[modNr][:ratio]=0.0
end #if
end #if
end #for
return (energySavingModifications, ratioMax, csIdMax, typeMax)
end #function findBestModification
## for the energy saving operation mode it is nesserary to compare different energy saving modifications. These are part of the moving section.
function createEnergySavingModification()
energySavingModification = Dict(:csId => 0, # identifier of the characteristic section
:type => "", # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:ΔE => 0.0, # saved energy (in Ws)
:Δt => 0.0, # time loss (in s)
:ratio => 0.0, # ratio of ΔE and Δt (in Ws/s)
:csModified => Dict(), # the modified characteristic section
:drivingCourseModified => []) # drivingCourse for the modified characteristic section
end #createEnergySavingModification
function updateEnergySavingModifications!(energySavingModifications::Vector{Dict}, csIdMax::Integer, drivingCourseNew::Vector{Dict}, endOfModificationId::Integer, lastIdOfSelectedCsOriginal::Integer)
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
difference = endOfModificationId-lastIdOfSelectedCsOriginal
for modNr in csIdMax+1:length(energySavingModifications)
if energySavingModifications[modNr][:ratio]>0
BSs = energySavingModifications[modNr][:csModified][:behaviorSections]
# update the behavior sections of the modified charateristic section
for bs in 1: length(allBs)
if haskey(BSs, allBs[bs])
for point in 1:length(BSs[allBs[bs]][:dataPoints])
BSs[allBs[bs]][:dataPoints][point] = BSs[allBs[bs]][:dataPoints][point] + difference
end
end #if
end #for
# correct the points of previous CS in the modified driving course. Copy the new driving course till the beginning of the current CS and change total values of the current modified CS data points accordingly
drivingCourseModifiedNew = copy(drivingCourseNew[1:endOfModificationId])
i=lastIdOfSelectedCsOriginal+1
while i <= length(energySavingModifications[modNr][:drivingCourseModified])
push!(drivingCourseModifiedNew, copy(energySavingModifications[modNr][:drivingCourseModified][i]))
drivingCourseModifiedNew[end][:i]=length(drivingCourseModifiedNew)
drivingCourseModifiedNew[end][:t]=drivingCourseModifiedNew[end-1][:t]+drivingCourseModifiedNew[end][:Δt]
drivingCourseModifiedNew[end][:E]=drivingCourseModifiedNew[end-1][:E]+drivingCourseModifiedNew[end][:ΔE]
drivingCourseModifiedNew[end][:W]=drivingCourseModifiedNew[end-1][:W]+drivingCourseModifiedNew[end][:ΔW]
i=i+1
end # while
energySavingModifications[modNr][:drivingCourseModified] = drivingCourseModifiedNew
end #if
end #for
return energySavingModifications
end #function updateEnergySavingModifications!
function copyMovingSection(original::Dict)
#TODO after removing the mutable structs: Is it possible to just "copy"?
copiedCSs = Vector{Dict}()
for csId in 1:length(original[:characteristicSections])
push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId]))
# 01/07 old without copy: push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId]))
end #for
copiedMS = Dict(:id => original[:id], # identifier
:length => original[:length], # total length (in m)
:s_entry => original[:s_entry], # first position (in m)
:s_exit => original[:s_exit], # last position (in m)
:t => original[:t], # total running time (in s)
:E => original[:E], # total energy consumption (in Ws)
:characteristicSections => copiedCSs) # list of containing characteristic sections
if haskey(original, :energySavingModifications) # list of containing all the used energy saving modifications
copiedModifications = Dict[]
for modId in 1:length(original[:energySavingModifications])
push!(copiedModifications, copyEnergySavingModification(original[:energySavingModifications][modId]))
end #for
merge!(copiedMS, Dict(:energySavingModifications => copiedModifications))
end
if haskey(original, :t_recovery) # total recovery time for energy-saving modifications (in s)
merge!(copiedMS, Dict(:t_recovery => original[:t_recovery]))
end
if haskey(original, :t_recoveryAvailable) # still available recovery time for energy-saving modifications (in s)
merge!(copiedMS, Dict(:t_recoveryAvailable => original[:t_recoveryAvailable]))
end
return copiedMS
end #function copyMovingSection
function copyEnergySavingModification(modificaionOriginal::Dict)
modificaionCopy = Dict(:csId => modificaionOriginal[:csId], # identifier of the characteristic section
:type => modificaionOriginal[:type], # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting"
:ΔE => modificaionOriginal[:ΔE], # saved energy (in Ws)
:Δt => modificaionOriginal[:Δt], # time loss (in s)
:ratio => modificaionOriginal[:ratio], # ratio of ΔE and Δt (in Ws/s)
:csModified => copyCharacteristicSection(modificaionOriginal[:]), # the modified characteristic section
:drivingCourseModified => copy(modificaionOriginal[:drivingCourseModified])) # drivingCourse for the modified characteristic section
return modificaionCopy
end # copyEnergySavingModification
end #module OperationModes

View File

@ -1,11 +1,8 @@
module Output
using CSV, DataFrames, Dates
export createOutputDict
function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
# method of function createOutputDict for one operation mode
outputDict=Dict{Symbol,Any}()
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
@ -15,22 +12,6 @@ function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection
elseif settings[:operationModeMinimumEnergyConsumption] == true
merge!(outputDict, Dict(:movingSectionMinimumEnergyConsumption => movingSection, :drivingCourseMinimumEnergyConsumption => drivingCourse))
end
return outputDict
end # function createOutputDict
function createOutputDict(train::Dict, settings::Dict, path::Dict, MS_MinTime::Dict, DC_MinTime::Vector{Dict}, MS_MinEnergy::Dict, DC_MinEnergy::Vector{Dict})
# method of function createOutputDict for two operation modes
outputDict=Dict{Symbol,Any}()
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
# adding moving sections and drving courses for different operation modes
if settings[:operationModeMinimumRunningTime] == true
merge!(outputDict, Dict(:movingSectionMinimumRunningTime => MS_MinTime, :drivingCourseMinimumRunningTime => DC_MinTime))
end
if settings[:operationModeMinimumEnergyConsumption] == true
merge!(outputDict, Dict(:movingSectionMinimumEnergyConsumption => MS_MinEnergy, :drivingCourseMinimumEnergyConsumption => DC_MinEnergy))
end
return outputDict
end # function createOutputDict

View File

@ -1,6 +1,5 @@
module Preparation
using ..types
include("./MovingPhases.jl")
using .MovingPhases

View File

@ -5,6 +5,7 @@ include("./TrainRunCalc.jl")
# include additional modules
include("./Import.jl")
include("./EnergySaving.jl")
include("./Export.jl")
# include additional modules that are not recommended to use in this state
@ -15,21 +16,25 @@ using .TrainRunCalc
# use additional modules
using .Import
using .EnergySaving
using .Export
# use additional modules that are not recommended to use in this state
using .AdditionalOutput
# export main function
# main function
export calculateDrivingDynamics,
# export the import functions
# import functions
importYamlFiles, importYamlFile,
# export the export functions
# functions for saving energy
addOperationModeEnergySaving!,
# export functions
exportToCsv,
# export functions for visualising results that are not recommended to use in this state
# functions for visualising results that are not recommended to use in this state
plotResults, plotDrivingCourse, printImportantValues, printSectionInformation
# approximationLevel = 6 # value for approximation to intersections

View File

@ -1,25 +1,23 @@
module TrainRunCalc
# include modules of TrainRunCalc
include("./types.jl")
include("./Input.jl")
include("./Preparation.jl")
include("./OperationModes.jl")
include("./MovingPhases.jl")
include("./Output.jl")
# use modules of TrainRunCalc
using .types
using .Input
using .Preparation
using .OperationModes
using .MovingPhases
using .Output
# export main function
export calculateDrivingDynamics
# approximationLevel = 6 # value for approximation to intersections
# TODO: define it here and give it to each function? (MovingPhases, EnergySaving)
approximationLevel = 6 # value for approximation to intersections and precisely calculated digits
# TODO: define it here and give it to each function? (MovingPhases, ...)
# Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`.
@ -40,31 +38,112 @@ function calculateDrivingDynamics(train::Dict, path::Dict, settings::Dict)
println("The input has been checked.")
# prepare the input data
movingSection=preparateSections(path, train, settings)
movingSection = preparateSections(path, train, settings)
println("The moving section has been prepared.")
# calculate the train run for oparation mode "minimum running time"
if settings[:operationModeMinimumRunningTime] ==true || settings[:operationModeMinimumEnergyConsumption] ==true
(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime)=calculateMinimumRunningTime!(movingSection, settings, train)
if settings[:operationModeMinimumRunningTime] || settings[:operationModeMinimumEnergyConsumption]
(movingSection, drivingCourse)=calculateMinimumRunningTime!(movingSection, settings, train)
println("The driving course for the shortest running time has been calculated.")
end #if
# calculate the train run for oparation mode "minimum energy consumption"
if settings[:operationModeMinimumEnergyConsumption] == true
(movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train)
println("The driving course for the lowest energy consumption has been calculated.")
# summarize data and create an output dictionary
output = createOutputDict(train, settings, path, movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)
elseif settings[:operationModeMinimumRunningTime] ==true
output = createOutputDict(train, settings, path, movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime)
# summarize data and create an output dictionary
output = createOutputDict(train, settings, path, movingSection, drivingCourse)
else
output = Dict()
end #if
# println("The output dictionary has been created.")
return output
end # function calculateDrivingDynamics
# calculate a train run focussing on using the minimum possible running time
function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train::Dict)
CSs::Vector{Dict} = movingSection[:characteristicSections]
startingPoint=createDataPoint()
startingPoint[:i]=1
startingPoint[:s]=CSs[1][:s_entry]
drivingCourse::Vector{Dict} = [startingPoint] # List of data points
# for CS in CSs
for csId in 1:length(CSs)
# check if the CS has a cruising section
CS = CSs[csId]
BSs = CS[:behaviorSections]
s_breakFree = get(BSs, :breakFree, Dict(:length=>0.0))[:length]
s_clearing = get(BSs, :clearing, Dict(:length=>0.0))[:length]
s_acceleration = get(BSs, :acceleration, Dict(:length=>0.0))[:length]
s_braking = max(0.0, ceil((CS[:v_exit]^2-CS[:v_peak]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
# calculate the cruising sections length
s_cruising = CS[:length] - s_breakFree - s_clearing - s_acceleration - s_braking
# reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit
# 01/07 old: delete!(BSs, :breakFree)
# 01/07 old: delete!(BSs, :clearing)
# 01/07 old: delete!(BSs, :acceleration)
# 01/07 old: delete!(BSs, :diminishing)
# 01/07 old: delete!(BSs, :cruising)
CS[:behaviorSections] = Dict()
CS[:E] = 0.0
CS[:t] = 0.0
if s_clearing == CS[:length]
# 09/06 TODO: thought about using "cruising" because it is used in EnergySaving and not clearing (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "cruising")
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing")
elseif s_cruising == CS[:length]
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
elseif s_cruising > 0.0 || s_braking == 0.0
# 09/21 elseif s_cruising > 0.0
# 09/21 elseif s_cruising > 0.01 # if the cruising section is longer than 1 cm (because of rounding issues not >0.0)
if drivingCourse[end][:v] < CS[:v_peak]
(CS, drivingCourse)=addAccelerationPhase!(CS, drivingCourse, settings, train, CSs)
end #if
if CS[:s_exit]-drivingCourse[end][:s]-max(0.0, (CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking]) < -0.001 # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
println("ERROR: After accelerating in CS ",csId," the braking distance is too short!")
println(" before acceleration in CS",csId, " with s=",drivingCourse[end][:s]," s_braking=",((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking])," s_exit=",CS[:s_exit])
println(" and v=",drivingCourse[end][:v]," v_peak=",CS[:v_peak]," v_exit=",CS[:v_exit])
end
s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
s_cruising=CS[:s_exit]-drivingCourse[end][:s]-s_braking
if s_cruising > 0.0
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
end
else
if CS[:v_entry] < CS[:v_peak] || s_acceleration > 0.0 # or instead of " || s_acceleration > 0.0" use "v_entry <= v_peak" or "v_i <= v_peak"
# 09/09 old (not sufficient for steep gradients): if CS[:v_entry] < CS[:v_peak]
(CS, drivingCourse)=addAccelerationPhaseUntilBraking!(CS, drivingCourse, settings, train, CSs)
end #if
end #if
s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end][:v]^2)/2/train[:a_braking], digits=approximationLevel)) # ceil is used to be sure that the train reaches v_exit at s_exit in spite of rounding errors
if drivingCourse[end][:v] > CS[:v_exit]
#(CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings[:massModel], train, CSs)
(CS, drivingCourse)=addBrakingPhase!(CS, drivingCourse, settings, train, CSs)
end #if
#= 09/20 old and should never be used:
if drivingCourse[end][:s] < CS[:s_exit]
if haskey(BSs, :cruising)
println("INFO: A second cruising section has been added to CS ", csId," from s=",drivingCourse[end][:s]," to s_exit=",CS[:s_exit])
end
(CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising")
end =#
end #for
(CSs[end], drivingCourse)=addStandstill!(CSs[end], drivingCourse, settings, train, CSs)
movingSection[:t] = drivingCourse[end][:t] # total running time (in s)
movingSection[:E] = drivingCourse[end][:E] # total energy consumption (in Ws)
return (movingSection, drivingCourse)
end #function calculateMinimumRunningTime
end # module TrainRunCalc

View File

@ -1,53 +0,0 @@
module types
export copyCharacteristicSection, copyBehaviorSection
#@enum behavior breakFree=1 clearing=2 acceleration=3 cruising=4 diminishing=6 coasting=7 braking=8 standstill=9
## different sections the whole path can be devided in the following
## smallest section of the path is the behavior section. It relates to the containing data points via their identifier.
function copyBehaviorSection(original::Dict)
bsDataPoints=[]
for i in 1:length(original[:dataPoints])
push!(bsDataPoints, original[:dataPoints][i])
end
copiedBS = Dict(#:type => behavior, # type of behavior section: breakFree, clearing, acceleration, cruising, diminishing, coasting, braking or standstill
:type => original[:type], # type of behavior section: "breakFree", "clearing", "acceleration", "cruising", "diminishing", "coasting", "braking" or "standstill"
:length => original[:length], # total length (in m)
:s_entry => original[:s_entry], # first position (in m)
:s_exit => original[:s_exit], # last position (in m)
:t => original[:t], # total running time (in s)
:E => original[:E], # total energy consumption (in Ws)
:v_entry => original[:v_entry], # entry speed (in m/s)
:v_exit => original[:v_exit], # exit speed (in m/s)
:dataPoints => bsDataPoints) # list of identifiers of the containing data points
return copiedBS
end
function copyCharacteristicSection(originalCS::Dict)
allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :braking, :standstill]
copiedBSs = Dict()
for bs in 1: length(allBs)
if haskey(originalCS[:behaviorSections], allBs[bs])
merge!(copiedBSs, Dict(allBs[bs] => originalCS[:behaviorSections][allBs[bs]]))
end #if
end #for
copiedCS=Dict(:id => originalCS[:id], # identifier
:s_entry => originalCS[:s_entry], # first position (in m)
:s_exit => originalCS[:s_exit], # last position (in m)
:length => originalCS[:length], # total length (in m)
:r_path => originalCS[:r_path], # path resistance (in ‰)
# :behaviorSections => copy(originalCS[:behaviorSections]), # list of containing behavior sections
:behaviorSections => copiedBSs, # list of containing behavior sections
:t => originalCS[:t], # total running time (in s)
:E => originalCS[:E], # total energy consumption (in Ws)
:v_limit => originalCS[:v_limit], # speed limit (in m/s)
:v_peak => originalCS[:v_peak], # maximum reachable speed (in m/s)
:v_entry => originalCS[:v_entry], # maximum entry speed (in m/s)
:v_exit => originalCS[:v_exit]) # maximum exit speed (in m/s)
return copiedCS
end # CharacteristicSection
end #module