From f5902062261aece81f6ad6d6e06919a1948c3356 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Sat, 8 Jan 2022 02:11:08 +0100 Subject: [PATCH] Refactor the mutable struct BehaviorSection as a Dictionary --- .../train_freight_V90withOreConsist.yaml | 2 +- data/trains/train_passenger_IC2.yaml | 2 +- .../train_passenger_SiemensDesiroClassic.yaml | 2 +- src/EnergySaving.jl | 164 +++---- src/Input.jl | 37 +- src/MovingPhases.jl | 432 ++++++++---------- src/OperationModes.jl | 79 ++-- src/Output.jl | 6 +- src/Preparation.jl | 11 +- src/types.jl | 70 +-- test/testEnums.jl | 12 +- 11 files changed, 394 insertions(+), 423 deletions(-) diff --git a/data/trains/train_freight_V90withOreConsist.yaml b/data/trains/train_freight_V90withOreConsist.yaml index b2e1ee9..fd2ec5e 100644 --- a/data/trains/train_freight_V90withOreConsist.yaml +++ b/data/trains/train_freight_V90withOreConsist.yaml @@ -10,7 +10,7 @@ train: rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) rotationMassFactor_w: 1.03 # (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Güterwagenzug beladen" -> 1.03 to 1.04) powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - trainType: freight # "freight" or "passenger" or "motor coach train" (source: https://dybas.de/dybas/gw/gw_f_1/g124.html) + trainType: freight # "freight" or "passenger" or "motorCoachTrain" (source: https://dybas.de/dybas/gw/gw_f_1/g124.html) v_limit: # in m/s v_limit_kmh: 80 # in km/h (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) a_braking: -0.4124 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 290 with with 10x Facs124) diff --git a/data/trains/train_passenger_IC2.yaml b/data/trains/train_passenger_IC2.yaml index 929643f..f1d5f33 100644 --- a/data/trains/train_passenger_IC2.yaml +++ b/data/trains/train_passenger_IC2.yaml @@ -10,7 +10,7 @@ train: rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) rotationMassFactor_w: 1.06 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons) powerType: electric # diesel or electric (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) - trainType: passenger # "freight" or "passenger" or "motor coach train" (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) + trainType: passenger # "freight" or "passenger" or "motorCoachTrain" (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) v_limit: # in m/s v_limit_kmh: 160 # in km/h (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) a_braking: -0.3507 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) diff --git a/data/trains/train_passenger_SiemensDesiroClassic.yaml b/data/trains/train_passenger_SiemensDesiroClassic.yaml index a233ded..695dc8a 100644 --- a/data/trains/train_passenger_SiemensDesiroClassic.yaml +++ b/data/trains/train_passenger_SiemensDesiroClassic.yaml @@ -10,7 +10,7 @@ train: rotationMassFactor_t: rotationMassFactor_w: powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - trainType: motor coach train # "freight" or "passenger" or "motor coach train" (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) + trainType: motorCoachTrain # "freight" or "passenger" or "motorCoachTrain" (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) v_limit: # in m/s v_limit_kmh: 120 # in km/h (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) a_braking: -0.4253 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 642) diff --git a/src/EnergySaving.jl b/src/EnergySaving.jl index 342d460..00c9973 100644 --- a/src/EnergySaving.jl +++ b/src/EnergySaving.jl @@ -1,3 +1,5 @@ +# TODO: calculation time for passenger trains on path1 is very long and should be reduced + module EnergySaving using ..types @@ -5,13 +7,16 @@ using ..MovingPhases export calculateRecoveryTime, increaseCoastingSection, decreaseMaximumVelocity, combineEnergySavingMethods +@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? 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 - if train[:trainType]=="motor coach train" + # 01/05 old without enum: if train[:type]=="motor coach train" + if train[:type] == motorCoachTrain::trainType if s_MS<= 30000 c_s=0.0 else s_MS> 30000 @@ -32,14 +37,16 @@ function calculateRecoveryTime(s_MS::Real, t_MS::AbstractFloat, train::Dict) t_recovery=s_MS*c_s+t_MS*c_t return t_recovery - elseif train[:trainType]=="freight" && train[:v_limit]<=120/3.6 # unit is m/s - t_recovery1=s_MS*0.0006 +t_MS*0.03 - t_recovery2=s_MS*0.0018 +t_MS*0.0 - t_recovery3=s_MS*0.0 +t_MS*0.04 - t_recovery=max(t_recovery1, t_recovery2, t_recovery3) + # 01/05 old without enum: elseif train[:type]=="freight" && train[:v_limit]<=120/3.6 # unit is m/s + elseif train[:type] == freight::trainType && train[:v_limit] <= 120/3.6 # unit is m/s + t_recovery1=s_MS*0.0006 +t_MS*0.03 + t_recovery2=s_MS*0.0018 +t_MS*0.0 + t_recovery3=s_MS*0.0 +t_MS*0.04 + t_recovery=max(t_recovery1, t_recovery2, t_recovery3) - return t_recovery - else # train[:trainType]=="passenger" || (train[:trainType]=="freight" && train[:v_limit]>120/3.6) # unit is m/s + return t_recovery + # 01/05 old without enum: else # train[:trainType]=="passenger" || (train[:trainType]=="freight" && train[:v_limit]>120/3.6) # unit is m/s + else # train[:type] == passenger::trainType || (train[:type] == freight::trainType && train[:v_limit]>120/3.6) # unit is m/s if s_MS<= 30000 c_s=0.0 else s_MS> 30000 @@ -86,7 +93,7 @@ function calculateRecoveryTime(s_MS::Real, t_MS::AbstractFloat, train::Dict) t_recovery=s_MS*c_s+t_MS*c_t return t_recovery - end # if train[:trainType] + end # if train[:type] end #function calculateRecoveryTime function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, allCSs::Vector{Dict}, t_recoveryAvailable::AbstractFloat) @@ -94,7 +101,7 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi if (haskey(BSsOriginal, :cruising) || haskey(BSsOriginal, :diminishing)) && haskey(BSsOriginal, :braking) # check if cruising or diminishing should be reduced for coasting if haskey(BSsOriginal, :cruising) && haskey(BSsOriginal, :diminishing) - if BSsOriginal[:cruising].dataPoints[1] > BSsOriginal[:diminishing].dataPoints[1] + if BSsOriginal[:cruising][:dataPoints][1] > BSsOriginal[:diminishing][:dataPoints][1] reduceCruising=true reduceDiminishing=false else @@ -111,12 +118,13 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi if reduceCruising cruisingReduction = settings[:stepSize] + # 01/07 test for a better calculation time: cruisingReduction = settings[:stepSize]*100 while cruisingReduction>=settings[:stepSize]/10^approximationLevel #while cruisingReduction>=settings[:stepSize]/100 while cruisingReduction>=settings[:stepSize]/10^approximationLevel # will be done once and then depending on approximationLevel repeated with smaller cruisingReduction unless !(drivingCourseModified[end].v<=csModified[:v_exit] && drivingCourseModified[end].s see below at the end of the while loop # create a copy for the characteristic sections drivingCourse - energySavingStartId=get(BSsOriginal, :cruising, BehaviorSection()).dataPoints[1] + energySavingStartId=get(BSsOriginal, :cruising, Dict(:dataPoints=>[0]))[:dataPoints][1] if energySavingStartId==0 error("ERROR at creating a new driving course for energy saving with coasting !") end @@ -130,21 +138,21 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi # calculating the new length of the cruising section if settings[:stepVariable]=="s in m" # distance step method - s_cruising = BSsOriginal[:cruising].length - cruisingReduction + s_cruising = BSsOriginal[:cruising][:length] - cruisingReduction elseif settings[:stepVariable]=="t in s" # time step method # 09/20 old: doesn't work for non constant cruising -> TODO: should work now - # t_cruising=BSsOriginal[:cruising].t-cruisingReduction + # t_cruising=BSsOriginal[:cruising][:t]-cruisingReduction # s_cruising=t_cruising*drivingCourseModified[end].v - distanceReduction = drivingCourse(BSsOriginal[:cruising].dataPoints[end]).v*cruisingReduction - s_cruising = BSsOriginal[:cruising].length-distanceReduction + distanceReduction = drivingCourse[BSsOriginal[:cruising][:dataPoints][end]].v*cruisingReduction + s_cruising = BSsOriginal[:cruising][:length]-distanceReduction elseif settings[:stepVariable]=="v in m/s" # velocity step method - s_cruising=BSsOriginal[:cruising].length-cruisingReduction*10 # TODO: or better: *100 ? + s_cruising=BSsOriginal[:cruising][:length]-cruisingReduction*10 # TODO: or better: *100 ? end #if s_cruising=max(0.0, s_cruising) # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, BehaviorSection}()) + # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) #TODO after removing the mutable structs: Is it possible to just "copy"? with some changes csModified=Dict(:id => csOriginal[:id], # identifier :s_entry => csOriginal[:s_entry], # first position (in m) @@ -161,28 +169,28 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi BSsModified = csModified[:behaviorSections] if haskey(BSsOriginal, :breakFree) - breakFreeSection=BehaviorSection(BSsOriginal[:breakFree]) + breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree].E - csModified[:t] = csModified[:t] + BSsModified[:breakFree].t + csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] + csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] end if haskey(BSsOriginal, :clearing) # this section is needed before acceleration if the train wants to accelerate to a speed higher than the limit in a previous CS where parts of the train are still located - clearingSection=BehaviorSection(BSsOriginal[:clearing]) + clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing].E - csModified[:t] = csModified[:t] + BSsModified[:clearing].t + csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] + csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] end if haskey(BSsOriginal, :acceleration) - accelerationSection=BehaviorSection(BSsOriginal[:acceleration]) + accelerationSection=copyBehaviorSection(BSsOriginal[:acceleration]) merge!(BSsModified, Dict(:acceleration=>accelerationSection)) - csModified[:E] = csModified[:E] + BSsModified[:acceleration].E - csModified[:t] = csModified[:t] + BSsModified[:acceleration].t + csModified[:E] = csModified[:E] + BSsModified[:acceleration][:E] + csModified[:t] = csModified[:t] + BSsModified[:acceleration][:t] end if haskey(BSsOriginal, :diminishing) - diminishingSection=BehaviorSection(BSsOriginal[:diminishing]) + diminishingSection=copyBehaviorSection(BSsOriginal[:diminishing]) merge!(BSsModified, Dict(:diminishing=>diminishingSection)) - csModified[:E] = csModified[:E] + BSsModified[:diminishing].E - csModified[:t] = csModified[:t] + BSsModified[:diminishing].t + csModified[:E] = csModified[:E] + BSsModified[:diminishing][:E] + csModified[:t] = csModified[:t] + BSsModified[:diminishing][:t] end @@ -224,7 +232,7 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi # TODO: At the moment diminishing is reduced like the acceleration in decreaseMaximumVelocity. To reduce code the methods for reducing cruising phase and reducing the diminishing phase can be combined in some parts. # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, BehaviorSection}()) + # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) csModified=Dict(:id => csOriginal[:id], # identifier :s_entry => csOriginal[:s_entry], # first position (in m) :s_exit => csOriginal[:s_exit], # last position (in m) @@ -240,49 +248,49 @@ function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{DataPoi BSsModified = csModified[:behaviorSections] if haskey(BSsOriginal, :breakFree) - breakFreeSection=BehaviorSection(BSsOriginal[:breakFree]) + breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree].E - csModified[:t] = csModified[:t] + BSsModified[:breakFree].t + csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] + csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] end if haskey(BSsOriginal, :clearing) # this section is needed before acceleration if the train wants to accelerate to a speed higher than the limit in a previous CS where parts of the train are still located - clearingSection=BehaviorSection(BSsOriginal[:clearing]) + clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing].E - csModified[:t] = csModified[:t] + BSsModified[:clearing].t + csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] + csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] end if haskey(BSsOriginal, :acceleration) - accelerationSection=BehaviorSection(BSsOriginal[:acceleration]) + accelerationSection=copyBehaviorSection(BSsOriginal[:acceleration]) merge!(BSsModified, Dict(:acceleration=>accelerationSection)) - csModified[:E] = csModified[:E] + BSsModified[:acceleration].E - csModified[:t] = csModified[:t] + BSsModified[:acceleration].t + csModified[:E] = csModified[:E] + BSsModified[:acceleration][:E] + csModified[:t] = csModified[:t] + BSsModified[:acceleration][:t] end if haskey(BSsOriginal, :cruising) - cruisingSection=BehaviorSection(BSsOriginal[:cruising]) + cruisingSection=copyBehaviorSection(BSsOriginal[:cruising]) merge!(BSsModified, Dict(:cruising=>cruisingSection)) - csModified[:E] = csModified[:E] + BSsModified[:cruising].E - csModified[:t] = csModified[:t] + BSsModified[:cruising].t + csModified[:E] = csModified[:E] + BSsModified[:cruising][:E] + csModified[:t] = csModified[:t] + BSsModified[:cruising][:t] end - diminishingSection=BehaviorSection(BSsOriginal[:diminishing]) - if length(diminishingSection.dataPoints) > 2 + diminishingSection=copyBehaviorSection(BSsOriginal[:diminishing]) + if length(diminishingSection[:dataPoints]) > 2 # remove the last diminishing waypoint - pop!(diminishingSection.dataPoints) + pop!(diminishingSection[:dataPoints]) - diminishingSection.v_exit=drivingCourse[diminishingSection.dataPoints[end]].v # exit speed (in m/s) - diminishingSection.s_exit=drivingCourse[diminishingSection.dataPoints[end]].s # last position (in m) - diminishingSection.length=diminishingSection.s_exit-diminishingSection.s_entry # total length (in m) - diminishingSection.t=drivingCourse[diminishingSection.dataPoints[end]].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s) - diminishingSection.E=drivingCourse[diminishingSection.dataPoints[end]].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws) + diminishingSection[:v_exit]=drivingCourse[diminishingSection[:dataPoints][end]].v # exit speed (in m/s) + diminishingSection[:s_exit]=drivingCourse[diminishingSection[:dataPoints][end]].s # last position (in m) + diminishingSection[:length]=diminishingSection[:s_exit]-diminishingSection[:s_entry] # total length (in m) + diminishingSection[:t]=drivingCourse[diminishingSection[:dataPoints][end]].t-drivingCourse[diminishingSection[:dataPoints][1]].t # total running time (in s) + diminishingSection[:E]=drivingCourse[diminishingSection[:dataPoints][end]].E-drivingCourse[diminishingSection[:dataPoints][1]].E # total energy consumption (in Ws) merge!(BSsModified, Dict(:diminishing => diminishingSection)) - csModified[:E] = csModified[:E] + BSsModified[:diminishing].E - csModified[:t] = csModified[:t] + BSsModified[:diminishing].t + csModified[:E] = csModified[:E] + BSsModified[:diminishing][:E] + csModified[:t] = csModified[:t] + BSsModified[:diminishing][:t] - energySavingStartId=diminishingSection.dataPoints[end] + energySavingStartId=diminishingSection[:dataPoints][end] else # The diminishing section is only one step. This step is removed and if there is a clearing section it will be combined with the new cruising section. - energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :diminishing, BehaviorSection())).dataPoints[1] + energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :diminishing, Dict(:dataPoints =>[0])))[:dataPoints][1] end # copy the driving course till the beginning of energy saving @@ -329,15 +337,15 @@ function decreaseMaximumVelocity(csOriginal::Dict, drivingCourse, settings::Dict #function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) BSsOriginal = csOriginal[:behaviorSections] if haskey(BSsOriginal, :acceleration) && csOriginal[:v_peak] > csOriginal[:v_entry] && csOriginal[:v_peak] > csOriginal[:v_exit] - accelerationSection = BehaviorSection(BSsOriginal[:acceleration]) - if drivingCourse[accelerationSection.dataPoints[end]-1].v < csOriginal[:v_exit] + accelerationSection = copyBehaviorSection(BSsOriginal[:acceleration]) + if drivingCourse[accelerationSection[:dataPoints][end]-1].v < csOriginal[:v_exit] # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? return (csOriginal, drivingCourse, false) # TODO: or calculate a new acceleration phase with v_exit as v_peak? it will be very short, shorter than the step size. end # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, BehaviorSection}()) + # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) csModified=Dict(:id => csOriginal[:id], # identifier :s_entry => csOriginal[:s_entry], # first position (in m) :s_exit => csOriginal[:s_exit], # last position (in m) @@ -352,43 +360,43 @@ function decreaseMaximumVelocity(csOriginal::Dict, drivingCourse, settings::Dict :v_exit => csOriginal[:v_exit]) # maximum exit speed (in m/s) BSsModified = csModified[:behaviorSections] if haskey(BSsOriginal, :breakFree) - breakFreeSection=BehaviorSection(BSsOriginal[:breakFree]) + breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree].E - csModified[:t] = csModified[:t] + BSsModified[:breakFree].t + csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] + csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] end - #accelerationSection = BehaviorSection(get(BSsOriginal, :acceleration, BehaviorSection())) + #accelerationSection = copyBehaviorSection(get(BSsOriginal, :acceleration, Dict())) - if length(accelerationSection.dataPoints) > 2 + if length(accelerationSection[:dataPoints]) > 2 if haskey(BSsOriginal, :clearing) - clearingSection=BehaviorSection(BSsOriginal[:clearing]) + clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing].E - csModified[:t] = csModified[:t] + BSsModified[:clearing].t + csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] + csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] end # remove the last acceleration waypoint - pop!(accelerationSection.dataPoints) + pop!(accelerationSection[:dataPoints]) - accelerationSection.v_exit=drivingCourse[accelerationSection.dataPoints[end]].v # exit speed (in m/s) - accelerationSection.s_exit=drivingCourse[accelerationSection.dataPoints[end]].s # last position (in m) - accelerationSection.length=accelerationSection.s_exit-accelerationSection.s_entry # total length (in m) - accelerationSection.t=drivingCourse[accelerationSection.dataPoints[end]].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s) - accelerationSection.E=drivingCourse[accelerationSection.dataPoints[end]].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws) + accelerationSection[:v_exit]=drivingCourse[accelerationSection[:dataPoints][end]].v # exit speed (in m/s) + accelerationSection[:s_exit]=drivingCourse[accelerationSection[:dataPoints][end]].s # last position (in m) + accelerationSection[:length]=accelerationSection[:s_exit]-accelerationSection[:s_entry] # total length (in m) + accelerationSection[:t]=drivingCourse[accelerationSection[:dataPoints][end]].t-drivingCourse[accelerationSection[:dataPoints][1]].t # total running time (in s) + accelerationSection[:E]=drivingCourse[accelerationSection[:dataPoints][end]].E-drivingCourse[accelerationSection[:dataPoints][1]].E # total energy consumption (in Ws) merge!(BSsModified, Dict(:acceleration=>accelerationSection)) - csModified[:E] = csModified[:E] + BSsModified[:acceleration].E - csModified[:t] = csModified[:t] + BSsModified[:acceleration].t + csModified[:E] = csModified[:E] + BSsModified[:acceleration][:E] + csModified[:t] = csModified[:t] + BSsModified[:acceleration][:t] - energySavingStartId=accelerationSection.dataPoints[end] + energySavingStartId=accelerationSection[:dataPoints][end] else # The acceleration section is only one step. This step is removed and if there is a clearing section it will be combined with the new cruising section. - energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :acceleration, BehaviorSection())).dataPoints[1] + energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :acceleration, Dict(:dataPoints =>[0])))[:dataPoints][1] end # TODO: should v_peak be reduced or is it enough to pop the data points? - # characteristicSection.v_peak=drivingCourse[end].v # setting v_peak to the last data point's velocity which is the highest reachable value in this characteristic section + # characteristicSection[:v_peak]=drivingCourse[end].v # setting v_peak to the last data point's velocity which is the highest reachable value in this characteristic section # copy the drivingCourse till the beginning of energy saving drivingCourseModified=Vector{DataPoint}() @@ -452,7 +460,7 @@ end # function decreaseMaximumVelocity function combineEnergySavingMethods(csOriginal::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, allCSs::Vector{Dict}, t_recoveryAvailable::AbstractFloat) BSsOriginal = csOriginal[:behaviorSections] # if haskey(BSsOriginal, :acceleration) && (haskey(BSsOriginal, :braking) || haskey(BSsOriginal, :coasting)) && csOriginal[:v_peak]>csOriginal[:v_entry] && csOriginal[:v_peak]>csOriginal[:v_exit] - if haskey(BSsOriginal, :acceleration) && (haskey(BSsOriginal, :braking) || haskey(BSsOriginal, :coasting)) && drivingCourse[get(BSsOriginal, :acceleration, BehaviorSection()).dataPoints[end]].v > max(csOriginal[:v_entry], csOriginal[:v_exit]) + if haskey(BSsOriginal, :acceleration) && (haskey(BSsOriginal, :braking) || haskey(BSsOriginal, :coasting)) && drivingCourse[get(BSsOriginal, :acceleration, Dict(:dataPoints =>[0]))[:dataPoints][end]].v > max(csOriginal[:v_entry], csOriginal[:v_exit]) # 12/28 old: csCombined=CharacteristicSection(csOriginal) #TODO after removing the mutable structs: Is it possible to just "copy"? csCombined=Dict(:id => csOriginal[:id], # identifier @@ -471,7 +479,7 @@ function combineEnergySavingMethods(csOriginal::Dict, drivingCourse::Vector{Data allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :cruisingAfterCoasting, :braking, :standstill] for bs in 1: length(allBs) if haskey(BSsOriginal, allBs[bs]) - merge!(csCombined[:behaviorSections], Dict(allBs[bs] => BehaviorSection(BSsOriginal[allBs[bs]]))) + merge!(csCombined[:behaviorSections], Dict(allBs[bs] => copyBehaviorSection(BSsOriginal[allBs[bs]]))) end #if end #for diff --git a/src/Input.jl b/src/Input.jl index aa50313..c4f09e6 100644 --- a/src/Input.jl +++ b/src/Input.jl @@ -5,6 +5,8 @@ using ..types export readInput +@enum trainType passenger=1 freight=2 motorCoachTrain=3 + """ Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them. """ @@ -34,14 +36,17 @@ function inputTrain(trainDirectory::String) id=1 # trains identifier if haskey(data["train"],"trainType") - if typeof(data["train"]["trainType"])==String && (data["train"]["trainType"]=="freight" || data["train"]["trainType"]=="motor coach train" || data["train"]["trainType"]=="passenger") - trainType=data["train"]["trainType"] # "passenger" or "freight" or "motor coach train" + # @enum trainType passenger=1 freight=2 motorCoachTrain=3 + if typeof(data["train"]["trainType"])==String && (data["train"]["trainType"]=="freight" || data["train"]["trainType"]=="motorCoachTrain" || data["train"]["trainType"]=="passenger") + # 01/05 old without enum: if typeof(data["train"]["trainType"])==String && (data["train"]["trainType"]=="freight" || data["train"]["trainType"]=="motor coach train" || data["train"]["trainType"]=="passenger") + # 01/05 old without enum: trainType=data["train"]["trainType"] # "passenger" or "freight" or "motor coach train" + type = getEnum(data["train"]["trainType"], trainType) # "passenger" or "freight" or "motorCoachTrain" delete!(data["train"], "trainType") else - error("ERROR at reading the train yaml file: The value of trainType is wrong. It has to be freight, motor coach train or passenger.") + error("ERROR at reading the train yaml file: The value of trainType is wrong. It has to be freight, motorCoachTrain or passenger.") end else - error("ERROR at reading the train yaml file: The keyword trainType is missing. It has to be added with the value freight, motor coach train or passenger.") + error("ERROR at reading the train yaml file: The keyword trainType is missing. It has to be added with the value freight, motorCoachTrain or passenger.") end if haskey(data["train"],"l_train") @@ -259,11 +264,24 @@ function inputTrain(trainDirectory::String) # coefficients for the vehicle resistance of the set of wagons (consist) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) +# if type == getEnum("passenger", trainType) || type == getEnum("motorCoachTrain", trainType) + if type == passenger::trainType || type == motorCoachTrain::trainType + # TODO: if type == trainType(:passenger) || type == trainType(:motorCoachTrain) + # TODO: ODER if trainType(type) == trainType(:passenger) || trainType(type) == trainType(:motorCoachTrain) + Δv_w=15.0/3.6 +# elseif type == getEnum("freight", trainType) + elseif type == freight::trainType + Δv_w=0.0 + end # if + + #= 01/05 old without enum + # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) if trainType=="passenger" || trainType=="motor coach train" Δv_w=15.0/3.6 elseif trainType== "freight" Δv_w=0.0 end # if + =# # coefficient for basic resistance of the set of wagons (consist) (in ‰) if haskey(data["train"],"f_Rw0") && data["train"]["f_Rw0"]!=nothing @@ -316,8 +334,9 @@ function inputTrain(trainDirectory::String) # create the train Dictionary train= Dict(:name => name, # train's name :id => id, # train's identifier - :trainType => trainType, # type of train "passenger" or "freight" or "motor coach train" - :trainLength => trainLength,# total length (in m) + :type => type, # type of train "passenger" or "freight" or "motorCoachTrain" + #= 01/05 old without enum :trainType => trainType, # type of train "passenger" or "freight" or "motor coach train" =# + :length => trainLength, # total length (in m) :v_limit => v_limit, # trains speed limit (in m/s) :a_braking => a_braking, # braking acceleration (in m/s^2) :m_train => m_train, # total mass (in kg) @@ -651,13 +670,13 @@ But only if the string matches an enumerated value. # Example ```jldoctest -julia> @enum trainTypes passenger freight +julia> @enum trainType passenger freight julia> myTrain = "passenger" "passenger" -julia> myTrainType = getEnum(myTrain, trainTypes) -passenger::trainTypes = 0 +julia> myTrainType = getEnum(myTrain, trainType) +passenger::trainType = 0 ``` """ function getEnum(string::String, enum_type::DataType) diff --git a/src/MovingPhases.jl b/src/MovingPhases.jl index 8e701cd..8249f5b 100644 --- a/src/MovingPhases.jl +++ b/src/MovingPhases.jl @@ -86,7 +86,7 @@ function calculatePathResistance(s::Real, massModel::String, train::Dict, CSs::V while s0 && s-train[:trainLength]0 && s-train[:length] 0 # if a former speed limit has been exceeded the acceleration steps of this CS will be removed and a clearing phase will be inserted before acceleration if drivingCourse[end].v > formerSpeedLimits[end][2] - while drivingCourse[end].s > get(CS[:behaviorSections], :clearing, accelerationSection).s_entry + while drivingCourse[end].s > get(CS[:behaviorSections], :clearing, accelerationSection)[:s_entry] pop!(drivingCourse) end if haskey(CS[:behaviorSections], :clearing) - CS[:t] = CS[:t]-CS[:behaviorSections][:clearing].t # reducing the total running time (in s) - CS[:E] = CS[:E]-CS[:behaviorSections][:clearing].E # reducing the total energy consumption (in Ws) + CS[:t] = CS[:t]-CS[:behaviorSections][:clearing][:t] # reducing the total running time (in s) + CS[:E] = CS[:E]-CS[:behaviorSections][:clearing][:E] # reducing the total energy consumption (in Ws) delete!(CS[:behaviorSections], :clearing) end # create a (new and longer) clearing section s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking], digits=approximationLevel)) - s_clearing=min(CS[:s_exit]-drivingCourse[end].s-s_braking, formerSpeedLimits[end][1]-(drivingCourse[end].s-train[:trainLength])) + s_clearing=min(CS[:s_exit]-drivingCourse[end].s-s_braking, formerSpeedLimits[end][1]-(drivingCourse[end].s-train[:length])) if s_clearing>0.0 (CS, drivingCourse)=addCruisingPhase!(CS, drivingCourse, s_clearing, settings, train, CSs, "clearing") @@ -238,19 +238,14 @@ function considerFormerSpeedLimits!(CS::Dict, drivingCourse::Vector{DataPoint}, # 09/22: if drivingCourse[end].s < CS[:s_exit] if drivingCourse[end].s < CS[:s_exit]-s_braking # reset the accelerationSection - accelerationSection=BehaviorSection() - accelerationSection.type="acceleration" # type of behavior section - accelerationSection.s_entry=drivingCourse[end].s # first position (in m) - accelerationSection.v_entry=drivingCourse[end].v # entry speed (in m/s) - - #currentStepSize=settings[:stepSize] # initializing the step size that can be reduced near intersections + accelerationSection = createBehaviorSection("acceleration", drivingCourse[end].s, drivingCourse[end].v, drivingCourse[end].i) else return (CS, drivingCourse, formerSpeedLimits, accelerationSection, true) end end # remove former speed limits of characteristic sections the train has left during the last step from the list - while length(formerSpeedLimits) > 0 && drivingCourse[end].s - train[:trainLength] >= formerSpeedLimits[end][1] + while length(formerSpeedLimits) > 0 && drivingCourse[end].s - train[:length] >= formerSpeedLimits[end][1] pop!(formerSpeedLimits) end end @@ -262,13 +257,9 @@ end # function considerFormerSpeedLimits! # Info: currently the values of the breakFree phase will be calculated like in the acceleration phase function addBreakFreePhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, CSs::Vector{Dict}) if drivingCourse[end].v==0.0 && drivingCourse[end].s drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - CS[:t]=CS[:t]+breakFreeSection.t # total running time (in s) - CS[:E]=CS[:E]+breakFreeSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(:breakFree => breakFreeSection)) + merge!(CS[:behaviorSections], Dict(:breakFree => BS)) end # else: return the characteristic section without a breakFree section return (CS, drivingCourse) end #function addBreakFreePhase! @@ -343,7 +334,7 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, setti end # if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept - formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:trainLength]) + formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:length]) # conditions for acceleration phase targetSpeedReached = drivingCourse[end].v >= CS[:v_peak] @@ -353,37 +344,33 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, setti # use the conditions for the acceleration phase if !targetSpeedReached && !trainAtEnd && tractionSurplus #11/23 long version: if drivingCourse[end].v < CS[:v_peak] && drivingCourse[end].s drivingCourse[end].F_R - accelerationSection=BehaviorSection() - accelerationSection.type="acceleration" # type of behavior section - accelerationSection.s_entry=drivingCourse[end].s # first position (in m) - accelerationSection.v_entry=drivingCourse[end].v # entry speed (in m/s) - push!(accelerationSection.dataPoints, drivingCourse[end].i) - drivingCourse[end].behavior = accelerationSection.type + BS = createBehaviorSection("acceleration", drivingCourse[end].s, drivingCourse[end].v, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] - currentStepSize=settings[:stepSize] # initializing the step size that can be reduced near intersections + currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation while drivingCourse[end].v drivingCourse[end].F_R # traction effort and resisting forces (in N) - # 11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + # 11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train[:m_train]/train[:ξ_train] # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end].behavior = accelerationSection.type - push!(accelerationSection.dataPoints, drivingCourse[end].i) - # calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) + # calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal - (CS, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, accelerationSection) + (CS, drivingCourse, formerSpeedLimits, BS, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, BS) if endOfCsReached return (CS, drivingCourse) end #if - currentStepSize=settings[:stepSize] # initializing the step size that can be reduced near intersections + currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections end #if - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) end #while # check which limit was reached and adjust the currentStepSize for the next cycle @@ -418,24 +405,24 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, setti end # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) - pop!(accelerationSection.dataPoints) + pop!(BS[:dataPoints]) else # if the level of approximation is reached if drivingCourse[end].v<=0.0 - # push!(accelerationSection.dataPoints, drivingCourse[end].i) + # push!(BS[:dataPoints], drivingCourse[end].i) error("ERROR: The train stops during the acceleration phase in CS",CS[:id]," because the tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", " F_T=",drivingCourse[end-1].F_T," N R_traction=",drivingCourse[end-1].R_traction," N R_wagons=",drivingCourse[end-1].R_wagons," N R_path=",drivingCourse[end-1].R_path," N.") elseif drivingCourse[end].v>CS[:v_peak] pop!(drivingCourse) - pop!(accelerationSection.dataPoints) + pop!(BS[:dataPoints]) elseif drivingCourse[end].s>CS[:s_exit] drivingCourse[end].s=CS[:s_exit] # rounding s down to s_exit elseif drivingCourse[end].F_T <= drivingCourse[end].F_R (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) else @@ -443,22 +430,23 @@ function addAccelerationPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, setti end end #for - if length(accelerationSection.dataPoints) > 1 # 11/21 new: it is possible that the acceleration starts at v_peak, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. + if length(BS[:dataPoints]) > 1 # 11/21 new: it is possible that the acceleration starts at v_peak, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. # calculate the accumulated acceleration section information - accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - accelerationSection.s_exit=drivingCourse[end].s # last position (in m) - accelerationSection.length=accelerationSection.s_exit-accelerationSection.s_entry # total length (in m) - accelerationSection.t=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s) - accelerationSection.E=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws) - CS[:t]=CS[:t]+accelerationSection.t # total running time (in s) - CS[:E]=CS[:E]+accelerationSection.E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) + + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) # TODO: this warning schould not be needed. just for testing if CS[:v_peak] < drivingCourse[end].v println("WARNING, v is getting to high at the end of the acceleration phase. v=",drivingCourse[end].v ," > v_peak=",CS[:v_peak]) end - merge!(CS[:behaviorSections], Dict(:acceleration=>accelerationSection)) + merge!(CS[:behaviorSections], Dict(:acceleration=>BS)) end end # else: just return the given data point number without changes due to the acceleration phase @@ -479,25 +467,21 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataP end # if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept - formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:trainLength]) + formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:length]) # 11/23 old without F_T>F_R: if drivingCourse[end].v < CS[:v_peak] && drivingCourse[end].s drivingCourse[end].F_R - accelerationSection=BehaviorSection() - accelerationSection.type="acceleration" # type of behavior section - accelerationSection.s_entry=drivingCourse[end].s # first position (in m) - accelerationSection.v_entry=drivingCourse[end].v # entry speed (in m/s) - push!(accelerationSection.dataPoints, drivingCourse[end].i) - drivingCourse[end].behavior = accelerationSection.type + BS = createBehaviorSection("acceleration", drivingCourse[end].s, drivingCourse[end].v, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] - currentStepSize=settings[:stepSize] # initializing the step size that can be reduced near intersections + currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking], digits=approximationLevel)) while drivingCourse[end].v < CS[:v_peak] && drivingCourse[end].s+s_braking drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend # 12/03 old with v>0 while drivingCourse[end].v < CS[:v_peak] && drivingCourse[end].s+s_braking0.0 && drivingCourse[end].F_T > drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend - #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train[:m_train]/train[:ξ_train] @@ -507,17 +491,17 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataP # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end].behavior = accelerationSection.type - push!(accelerationSection.dataPoints, drivingCourse[end].i) - # 12/03: was moved behind considerFormerSpeedLimits: calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) + # 12/03: was moved behind considerFormerSpeedLimits: calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal - (CS, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, accelerationSection) + (CS, drivingCourse, formerSpeedLimits, BS, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, BS) if endOfCsReached return (CS, drivingCourse) end end - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking], digits=approximationLevel)) end #while @@ -550,25 +534,25 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataP end # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) - pop!(accelerationSection.dataPoints) + pop!(BS[:dataPoints]) else # if the level of approximation is reached if drivingCourse[end].v<=0.0 - # push!(accelerationSection.dataPoints, drivingCourse[end].i) + # push!(BS[:dataPoints], drivingCourse[end].i) error("ERROR: The train stops during the acceleration phase in CS",CS[:id]," because the tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", " F_T=",drivingCourse[end-1].F_T," N R_traction=",drivingCourse[end-1].R_traction," N R_wagons=",drivingCourse[end-1].R_wagons," N R_path=",drivingCourse[end-1].R_path," N.") elseif drivingCourse[end].v>CS[:v_peak] pop!(drivingCourse) - pop!(accelerationSection.dataPoints) + pop!(BS[:dataPoints]) elseif drivingCourse[end].s + s_braking > CS[:s_exit] pop!(drivingCourse) - pop!(accelerationSection.dataPoints) + pop!(BS[:dataPoints]) elseif drivingCourse[end].F_T <= drivingCourse[end].F_R (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, accelerationSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) else @@ -576,19 +560,19 @@ function addAccelerationPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataP end end #for - if length(accelerationSection.dataPoints) > 1 # TODO: is it still possible that it is <=1 although there is a sepaate diminishing phase? + if length(BS[:dataPoints]) > 1 # TODO: is it still possible that it is <=1 although there is a separate diminishing phase? # calculate the accumulated acceleration section information - accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - accelerationSection.s_exit=drivingCourse[end].s # last position (in m) - accelerationSection.length=accelerationSection.s_exit-accelerationSection.s_entry # total length (in m) - accelerationSection.t=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s) - accelerationSection.E=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) CS[:v_peak]=max(drivingCourse[end].v, CS[:v_entry]) # setting v_peak to the last data points velocity which is the highest reachable value in this characteristic section or to v_entry in case it is higher when driving on a path with high resistances - CS[:t]=CS[:t]+accelerationSection.t # total running time (in s) - CS[:E]=CS[:E]+accelerationSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(:acceleration=>accelerationSection)) + merge!(CS[:behaviorSections], Dict(:acceleration=>BS)) end end # else: just return the given data point number without changes due to the acceleration phase return (CS, drivingCourse) @@ -599,35 +583,30 @@ end #function addAccelerationPhaseUntilBraking! # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed. function addCruisingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, s_cruising::Real, settings::Dict, train::Dict, CSs::Vector{Dict}, cruisingType::String) # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") # TODO: or give cruisingSection.type instead of "cruising"? + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") if drivingCourse[end].F_T < drivingCourse[end].F_R (CS, drivingCourse) = addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) drivingCourse[end] = DataPoint(calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising")) - s_cruising = max(0.0, s_cruising-get(CS[:behaviorSections], :diminishing, BehaviorSection()).length) + s_cruising = max(0.0, s_cruising-get(CS[:behaviorSections], :diminishing, Dict(:length=>0.0))[:length]) end if drivingCourse[end].v>0.0 && drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s= drivingCourse[end].F_R # 11/22 old: if drivingCourse[end].v>0.0 && drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s 1 currentStepSize=settings[:stepSize] for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - while drivingCourse[end].s < CS[:s_entry] + train[:trainLength] && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s drivingCourse[end].F_R && drivingCourse[end].F_R > 0.0 - error("In the cruising phase of CS",cruisingSection.id,": F_T=",drivingCourse[end].F_T," != F_R=",drivingCourse[end].F_R) + push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", train[:length]/(10.0^cycle), CS[:id])) # TODO which step size should be used? end + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) # traction effort and resisting forces (in N) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") @@ -655,22 +629,22 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, s_cruisin # check which limit was reached and adjust the currentStepSize for the next cycle if cycle < approximationLevel+1 - if drivingCourse[end].s>cruisingSection.s_entry+s_cruising # TODO also the following? drivingCourse[end].s > CSs[CS[:id]].s_entry + train[:trainLength])) + if drivingCourse[end].s>BS[:s_entry]+s_cruising # TODO also the following? drivingCourse[end].s > CSs[CS[:id]][:s_entry] + train[:length])) if settings[:stepVariable] == "s in m" - currentStepSize=cruisingSection.s_entry+s_cruising-drivingCourse[end-1].s + currentStepSize=BS[:s_entry]+s_cruising-drivingCourse[end-1].s else currentStepSize = settings[:stepSize] / 10.0^cycle end - elseif drivingCourse[end].s==cruisingSection.s_entry+s_cruising # || drivingCourse[end].s==CS[:s_exit] + elseif drivingCourse[end].s==BS[:s_entry]+s_cruising # || drivingCourse[end].s==CS[:s_exit] break elseif drivingCourse[end].F_T < drivingCourse[end].F_R # if settings[:stepVariable] == "s in m" - # currentStepSize=cruisingSection.s_entry+s_cruising-drivingCourse[end-1].s + # currentStepSize=BS[:s_entry]+s_cruising-drivingCourse[end-1].s # else currentStepSize = settings[:stepSize] / 10.0^cycle # end - elseif drivingCourse[end].s >= CS[:s_entry] + train[:trainLength] - # TODO: whithout CSs should work as well, no? elseif drivingCourse[end].s >= CSs[CS[:id]].s_entry + train[:trainLength] + elseif drivingCourse[end].s >= CS[:s_entry] + train[:length] + # TODO: whithout CSs should work as well, no? elseif drivingCourse[end].s >= CSs[CS[:id]][:s_entry] + train[:length] break else # TODO copied from addAccelerationPhase -> probably not needed here !? error("ERROR at cruising phase: With the step variable ",settings[:stepVariable]," the while loop will be left although the if cases don't apply in CS",CS[:id]," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") @@ -678,17 +652,17 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, s_cruisin # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) - pop!(cruisingSection.dataPoints) + pop!(BS[:dataPoints]) else # if the level of approximation is reached - if drivingCourse[end].s>cruisingSection.s_entry+s_cruising - if cruisingSection.type == "clearing" + if drivingCourse[end].s>BS[:s_entry]+s_cruising + if BS[:type] == "clearing" else pop!(drivingCourse) - pop!(cruisingSection.dataPoints) + pop!(BS[:dataPoints]) end # 11/21 |-> - elseif drivingCourse[end].s==cruisingSection.s_entry+s_cruising + elseif drivingCourse[end].s==BS[:s_entry]+s_cruising break # 11/21 ->| elseif drivingCourse[end].F_T < drivingCourse[end].F_R @@ -696,7 +670,7 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, s_cruisin (CS, drivingCourse)=addDiminishingPhase!(CS, drivingCourse, settings, train, CSs) calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "cruising") - # s_cruising=max(0.0, s_cruising-get(CS[:behaviorSections], :diminishing, BehaviorSection()).length) + # s_cruising=max(0.0, s_cruising-get(CS[:behaviorSections], :diminishing, Dict(length=>0.0))[:length]) else @@ -706,30 +680,30 @@ function addCruisingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, s_cruisin end #if # TODO oder soll das lieber nach oben in den else des letzten Durchlaufs. Noch mal genauer ansehen, ob hier was doppelt gemoppelt ist - # if drivingCourse[end].s= drivingCourse[end].F_R + # if drivingCourse[end].s= drivingCourse[end].F_R drivingCourse[end].a=0.0 # acceleration (in m/s^2) # calculate the remaining cruising way - s_cruisingRemaining=cruisingSection.s_entry+s_cruising-drivingCourse[end].s + s_cruisingRemaining=BS[:s_entry]+s_cruising-drivingCourse[end].s # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, CS[:id])) - drivingCourse[end].behavior = cruisingSection.type - push!(cruisingSection.dataPoints, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) end # calculate the accumulated cruising section information - cruisingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - cruisingSection.s_exit=drivingCourse[end].s # last position (in m) - cruisingSection.length=cruisingSection.s_exit-cruisingSection.s_entry # total length (in m) - cruisingSection.t=drivingCourse[end].t-drivingCourse[cruisingSection.dataPoints[1]].t # total running time (in s) - cruisingSection.E=drivingCourse[end].E-drivingCourse[cruisingSection.dataPoints[1]].E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - CS[:t]=CS[:t]+cruisingSection.t # total running time (in s) - CS[:E]=CS[:E]+cruisingSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(Symbol(cruisingSection.type) => cruisingSection)) + merge!(CS[:behaviorSections], Dict(Symbol(BS[:type]) => BS)) end # else: return the characteristic section without a cruising section return (CS, drivingCourse) @@ -741,21 +715,16 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settin calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, "diminishing") if drivingCourse[end].F_T <= drivingCourse[end].F_R && drivingCourse[end].v > 0.0 && drivingCourse[end].s0.0 && drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s0.0 # as long as s_i + s_braking < s_CSend # 11/22 old without F_T<=F_R while drivingCourse[end].s+s_braking0.0 # as long as s_i + s_braking < s_CSend - #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, diminishingSection.type) + #11/22 calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train[:m_train]/train[:ξ_train] @@ -766,11 +735,11 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settin # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end].behavior = diminishingSection.type - push!(diminishingSection.dataPoints, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) s_braking=max(0.0, ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking], digits=approximationLevel)) - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, diminishingSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) end #while # check which limit was reached and adjust the currentStepSize for the next cycle @@ -793,18 +762,18 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settin end # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) - pop!(diminishingSection.dataPoints) + pop!(BS[:dataPoints]) else # if the level of approximation is reached if drivingCourse[end].v<=0.0 - # push!(diminishingSection.dataPoints, drivingCourse[end].i) + # push!(BS[:dataPoints], drivingCourse[end].i) error("ERROR: The train stops during diminishing run in CS",CS[:id]," because the maximum tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", " F_T=",drivingCourse[end-1].F_T," N R_traction=",drivingCourse[end-1].R_traction," N R_wagons=",drivingCourse[end-1].R_wagons," N R_path=",drivingCourse[end-1].R_path," N.") elseif drivingCourse[end].s + s_braking > CS[:s_exit] pop!(drivingCourse) - pop!(diminishingSection.dataPoints) + pop!(BS[:dataPoints]) elseif drivingCourse[end].F_T > drivingCourse[end].F_R break @@ -815,17 +784,18 @@ function addDiminishingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settin end end #for - if length(diminishingSection.dataPoints) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start + if length(BS[:dataPoints]) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start # calculate the accumulated diminishing section information - diminishingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - diminishingSection.s_exit=drivingCourse[end].s # last position (in m) - diminishingSection.length=diminishingSection.s_exit-diminishingSection.s_entry # total length (in m) - diminishingSection.t=drivingCourse[end].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s) - diminishingSection.E=drivingCourse[end].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws) - CS[:t]=CS[:t]+diminishingSection.t # total running time (in s) - CS[:E]=CS[:E]+diminishingSection.E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - merge!(CS[:behaviorSections], Dict(:diminishing=>diminishingSection)) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) + + merge!(CS[:behaviorSections], Dict(:diminishing=>BS)) end end @@ -837,31 +807,27 @@ end #function addDiminishingPhase! # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the coasting section function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, CSs::Vector{Dict}) ## if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept - #formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:trainLength]) + #formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:length]) if drivingCourse[end].v>CS[:v_exit] && drivingCourse[end].sCS[:v_exit] && drivingCourse[end].v<=CS[:v_peak] && drivingCourse[end].s + s_braking < CS[:s_exit] # as long as s_i + s_braking < s_CSend # traction effort and resisting forces (in N): - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, coastingSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train[:m_train]/train[:ξ_train] # creating the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end].behavior = coastingSection.type - push!(coastingSection.dataPoints, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) s_braking=ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking]) @@ -894,7 +860,7 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataPoint end # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) - pop!(coastingSection.dataPoints) + pop!(BS[:dataPoints]) else # if the level of approximation is reached if drivingCourse[end].v<=0.0 @@ -905,7 +871,7 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataPoint elseif drivingCourse[end].s + s_braking > CS[:s_exit] # delete last data point because it went to far pop!(drivingCourse) - pop!(coastingSection.dataPoints) + pop!(BS[:dataPoints]) elseif drivingCourse[end].v > CS[:v_peak] # if the train gets to fast it has to brake # TODO: if accelereation and coasting functions will be combined this case is different for coasting and also the order of if cases is different # while coasting the train brakes to hold v_peak (only one data point in the end of coasting is calculated like cruising at v_peak) @@ -937,16 +903,16 @@ function addCoastingPhaseUntilBraking!(CS::Dict, drivingCourse::Vector{DataPoint end #for # calculate the accumulated coasting section information - coastingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - coastingSection.s_exit=drivingCourse[end].s # last position (in m) - coastingSection.length=coastingSection.s_exit-coastingSection.s_entry # total length (in m) - coastingSection.t=drivingCourse[end].t-drivingCourse[coastingSection.dataPoints[1]].t # total running time (in s) - coastingSection.E=drivingCourse[end].E-drivingCourse[coastingSection.dataPoints[1]].E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - CS[:t]=CS[:t]+coastingSection.t # total running time (in s) - CS[:E]=CS[:E]+coastingSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(:coasting=>coastingSection)) + merge!(CS[:behaviorSections], Dict(:coasting=>BS)) end ## else: just return the given data point number without changes due to the coasting phase return (CS, drivingCourse) end #function addCoastingPhaseUntilBraking! @@ -957,24 +923,20 @@ end #function addCoastingPhaseUntilBraking! function addBrakingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, CSs::Vector{Dict}) #, s_braking::AbstractFloat) # function addBrakingPhase!(CS::Dict, drivingCourse::Vector{DataPoint}, massModel::String, train::Dict, CSs::Vector{Dict}) #, s_braking::AbstractFloat) if drivingCourse[end].v>CS[:v_exit] && drivingCourse[end].s drivingCourse[end].Δs, # total length (in m) + #:s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].Δt, # total running time (in s) + :E => drivingCourse[end].ΔE, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - CS[:t]=CS[:t]+brakingSection.t # total running time (in s) - CS[:E]=CS[:E]+brakingSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(:braking=>brakingSection)) + merge!(CS[:behaviorSections], Dict(:braking=>BS)) end # else: return the characteristic section without a braking section return (CS, drivingCourse) end #function addBrakingPhase! @@ -1014,18 +977,14 @@ end #function addBrakingPhase! # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed. function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, CSs::Vector{Dict}) #, s_braking::AbstractFloat) if drivingCourse[end].v > CS[:v_exit] && drivingCourse[end].s < CS[:s_exit] - brakingSection=BehaviorSection() - brakingSection.type="braking" # type of behavior section - brakingSection.s_entry=drivingCourse[end].s # first position (in m) - brakingSection.v_entry=drivingCourse[end].v # entry speed (in m/s) - push!(brakingSection.dataPoints, drivingCourse[end].i) # refering from the breaking section to the first of its data points - drivingCourse[end].behavior = brakingSection.type + BS = createBehaviorSection("braking", drivingCourse[end].s, drivingCourse[end].v, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] - currentStepSize=settings[:stepSize] # initializing the step size that can be reduced near intersections + currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections velocityIsPositive=true while drivingCourse[end].v > CS[:v_exit] && drivingCourse[end].s < CS[:s_exit] && velocityIsPositive # traction effort and resisting forces (in N): - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, brakingSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) # acceleration (in m/s^2): drivingCourse[end].a=train[:a_braking] @@ -1041,8 +1000,8 @@ function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{DataPoint}, se end end push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end].behavior = brakingSection.type - push!(brakingSection.dataPoints, drivingCourse[end].i) + drivingCourse[end].behavior = BS[:type] + push!(BS[:dataPoints], drivingCourse[end].i) # s_braking=ceil((CS[:v_exit]^2-drivingCourse[end].v^2)/2/train[:a_braking]) end # while @@ -1056,7 +1015,6 @@ function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{DataPoint}, se #drivingCourse[end-1].a=round((drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs, digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking) drivingCourse[end-1].a=(drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs # acceleration (in m/s^2) - # println("a_braking_last=",drivingCourse[end-1].a," m/s^2 und a_braking_standard=" , train[:a_braking]) # if drivingCourse[end-1].a=0.0 # println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",drivingCourse[end-1].a ," > ",train[:a_braking]) @@ -1075,16 +1033,16 @@ function addBrakingPhaseStepwise!(CS::Dict, drivingCourse::Vector{DataPoint}, se end # calculate the accumulated coasting section information - brakingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - brakingSection.s_exit=drivingCourse[end].s # last position (in m) - brakingSection.length=brakingSection.s_exit-brakingSection.s_entry # total length (in m) - brakingSection.t=drivingCourse[end].t-drivingCourse[brakingSection.dataPoints[1]].t # total running time (in s) - brakingSection.E=drivingCourse[end].E-drivingCourse[brakingSection.dataPoints[1]].E # total energy consumption (in Ws) + merge!(BS, Dict(:length => drivingCourse[end].s - BS[:s_entry], # total length (in m) + :s_exit => drivingCourse[end].s, # last position (in m) + :t => drivingCourse[end].t - drivingCourse[BS[:dataPoints][1]].t, # total running time (in s) + :E => drivingCourse[end].E - drivingCourse[BS[:dataPoints][1]].E, # total energy consumption (in Ws) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) - CS[:t]=CS[:t]+brakingSection.t # total running time (in s) - CS[:E]=CS[:E]+brakingSection.E # total energy consumption (in Ws) + CS[:t]=CS[:t]+BS[:t] # total running time (in s) + CS[:E]=CS[:E]+BS[:E] # total energy consumption (in Ws) - merge!(CS[:behaviorSections], Dict(:braking=>brakingSection)) + merge!(CS[:behaviorSections], Dict(:braking=>BS)) end # else: return the characteristic section without a braking section return (CS, drivingCourse) end #function addBrakingPhaseStepwise! @@ -1095,26 +1053,34 @@ end #function addBrakingPhaseStepwise! function addStandstill!(CS::Dict, drivingCourse::Vector{DataPoint}, settings::Dict, train::Dict, CSs::Vector{Dict}) if drivingCourse[end].v == 0.0 - standstillSection=BehaviorSection() - standstillSection.type="standstill" # type of behavior section - standstillSection.s_entry=drivingCourse[end].s # first position (in m) - standstillSection.s_exit=drivingCourse[end].s # last position (in m) - standstillSection.v_entry=drivingCourse[end].v # entry speed (in m/s) - standstillSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - standstillSection.length=0.0 # total length (in m) - standstillSection.t=0.0 # total running time (in s) - standstillSection.E=0.0 # total energy consumption (in Ws) - push!(standstillSection.dataPoints, drivingCourse[end].i) # refering from the breaking section to the first of its data points - - - drivingCourse[end].behavior = standstillSection.type + BS = createBehaviorSection("standstill", drivingCourse[end].s, drivingCourse[end].v, drivingCourse[end].i) + merge!(BS, Dict(:length => 0.0, # total length (in m) + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) + :s_exit => drivingCourse[end].s, # last position (in m) + :v_exit => drivingCourse[end].v)) # exit speed (in m/s))) + drivingCourse[end].behavior = BS[:type] # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, standstillSection.type) + calculateForces!(drivingCourse[end], train, settings[:massModel], CSs, BS[:type]) - merge!(CS[:behaviorSections], Dict(:standstill => standstillSection)) + merge!(CS[:behaviorSections], Dict(:standstill => BS)) end # else: return the characteristic section without a standstillSection section return (CS, drivingCourse) end #function addStandstill! +function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) + BS= Dict(#:type => behavior, # type of behavior section: breakFree, clearing, acceleration, cruising, diminishing, coasting, cruisingAfterCoasting, braking or standstill + :type => type, # type of behavior section: "breakFree", "clearing", "acceleration", "cruising", "diminishing", "coasting", "cruisingAfterCoasting", "braking" or "standstill" + :length => 0.0, # total length (in m) + :s_entry => s_entry, # first position (in m) + :s_exit => 0.0, # last position (in m) + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) + :v_entry => v_entry, # entry speed (in m/s) + :v_exit => 0.0, # exit speed (in m/s) + :dataPoints => [startingPoint]) # list of identifiers of the containing data points starting with the initial point + return BS +end #function createBehaviorSection + end #module MovingPhases diff --git a/src/OperationModes.jl b/src/OperationModes.jl index 0c97abf..e6999ca 100644 --- a/src/OperationModes.jl +++ b/src/OperationModes.jl @@ -25,22 +25,24 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train # check if the CS has a cruising section CS = CSs[csId] BSs = CS[:behaviorSections] - s_breakFree = get(BSs, :breakFree, BehaviorSection()).length - s_clearing = get(BSs, :clearing, BehaviorSection()).length - s_acceleration = get(BSs, :acceleration, BehaviorSection()).length + + 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 + s_cruising = CS[:length] - s_breakFree - s_clearing - s_acceleration - s_braking - # reset the moving section (MS), delete characteristic sections (CS) that were used during the preperation for setting v_entry, v_peak and v_exit - delete!(BSs, :breakFree) - delete!(BSs, :clearing) - delete!(BSs, :acceleration) - delete!(BSs, :diminishing) - delete!(BSs, :cruising) - CS[:E]=0.0 - CS[:t]=0.0 + # 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] @@ -113,6 +115,7 @@ function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict #create a new moving section for the minimum energy consumption movingSectionOriginal=copyMovingSection(movingSectionMinimumRunningTime) + # 01/01 new when Datapoint is a Dict: movingSectionOriginal=copy(movingSectionMinimumRunningTime) CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections] merge!(movingSectionOriginal, Dict(:energySavingModifications => [])) # list containing all the used energy saving modifications @@ -196,11 +199,11 @@ function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict get(CSsOrig[csIdMax][:behaviorSections], :clearing, get(CSsOrig[csIdMax][:behaviorSections], :breakFree, get(CSsOrig[csIdMax][:behaviorSections], :diminishing, - BehaviorSection()))))))))).dataPoints[end] + 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 occur in a fixed order. + # 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]) + lastIdOfSelectedCsOriginal = max(lastIdOfSelectedCsOriginal, CSsOrig[csIdMax][:behaviorSections][:diminishing][:dataPoints][end]) end # create new driving course @@ -233,7 +236,8 @@ function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict # replace the original driving course and CS with the new modified ones drivingCourseOriginal=drivingCourseNew - CSsOrig[csIdMax]=copyCharacteristicSection(movingSectionOriginal[:energySavingModifications][end][:csModified]) + CSsOrig[csIdMax]=copy(movingSectionOriginal[:energySavingModifications][end][:csModified]) + # 01/07 old without copy: CSsOrig[csIdMax]=copyCharacteristicSection(movingSectionOriginal[:energySavingModifications][end][:csModified]) movingSectionOriginal[:t]=drivingCourseOriginal[end].t # total running time (in s) movingSectionOriginal[:E]=drivingCourseOriginal[end].E # total energy consumption (in Ws) @@ -244,8 +248,8 @@ function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict 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 + 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 @@ -370,7 +374,8 @@ function copyEnergySavingModification(original::Dict) :ΔE => original[:ΔE], # saved energy (in Ws) :Δt => original[:Δt], # time loss (in s) :ratio => original[:ratio], # ratio of ΔE and Δt (in Ws/s) - :csModified => copyCharacteristicSection(original[:csModified])) # the modified characteristic section + :csModified => copy(original[:csModified])) # the modified characteristic section + # 01/07 old without copy: csModified => copyCharacteristicSection(original[:csModified])) # the modified characteristic section drivingCourseModified = DataPoint[] for i in 1:length(original[:drivingCourseModified]) @@ -378,8 +383,7 @@ function copyEnergySavingModification(original::Dict) end merge!(copy, Dict(:drivingCourseModified => drivingCourseModified)) # drivingCourse for the modified characteristic section return copy -end #function EnergySavingModification - +end #function copyEnergySavingModification function updateEnergySavingModifications!(energySavingModifications::Vector{Dict}, csIdMax::Integer, drivingCourseNew::Vector{DataPoint}, endOfModificationId::Integer, lastIdOfSelectedCsOriginal::Integer) allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :cruisingAfterCoasting, :braking, :standstill] @@ -390,8 +394,8 @@ function updateEnergySavingModifications!(energySavingModifications::Vector{Dict # 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 + 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 @@ -423,10 +427,11 @@ function copyMovingSection(original::Dict) #TODO after removing the mutable structs: Is it possible to just "copy"? CSsCopy = Vector{Dict}() for csId in 1:length(original[:characteristicSections]) - push!(CSsCopy, copyCharacteristicSection(original[:characteristicSections][csId])) + push!(CSsCopy, copy(original[:characteristicSections][csId])) + # 01/07 old without copy: push!(CSsCopy, copyCharacteristicSection(original[:characteristicSections][csId])) end #for - copy = Dict(:id => original[:id], # identifier + 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) @@ -437,28 +442,29 @@ function copyMovingSection(original::Dict) if haskey(original, :energySavingModifications) # list of containing all the used energy saving modifications ModificationsCopy = Dict[] for modId in 1:length(original[:energySavingModifications]) - push!(ModificationsCopy, EnergySavingModification(original[:energySavingModifications][modId])) + push!(ModificationsCopy, copyEnergySavingModification(original[:energySavingModifications][modId])) # TODO or should it be copyEnergySavingModification + # 01/07 new when DataPoint is a Dict: push!(ModificationsCopy, copy(original[:energySavingModifications][modId])) end #for - merge!(copy, Dict(:energySavingModifications => ModificationsCopy)) + merge!(copiedMS, Dict(:energySavingModifications => ModificationsCopy)) end if haskey(original, :t_recovery) # total recovery time for energy-saving modifications (in s) - merge!(copy, Dict(:t_recovery => original[:t_recovery])) + 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!(copy, Dict(:t_recoveryAvailable => original[:t_recoveryAvailable])) + merge!(copiedMS, Dict(:t_recoveryAvailable => original[:t_recoveryAvailable])) end - return copy + return copiedMS end #function copyMovingSection - +#= function copyCharacteristicSection(original::Dict) #TODO after removing the mutable structs: Is it possible to just "copy"? - copy = Dict(:id => original[:id], # identifier + copiedCS = Dict(:id => original[:id], # identifier :s_entry => original[:s_entry], # first position (in m) :s_exit => original[:s_exit], # last position (in m) :length => original[:length], # total length (in m) - :r_path => original[:r_path], # path resistance (in ‰) + :r_path => original[:r_path], # path resistance (in ‰) :behaviorSections => Dict(), # empty list of containing behavior sections :t => original[:t], # total running time (in s) :E => original[:E], # total energy consumption (in Ws) @@ -470,10 +476,11 @@ function copyCharacteristicSection(original::Dict) allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :cruisingAfterCoasting, :braking, :standstill] for bs in 1: length(allBs) if haskey(original[:behaviorSections], allBs[bs]) - merge!(copy[:behaviorSections], Dict(allBs[bs] => BehaviorSection(original[:behaviorSections][allBs[bs]]))) + #merge!(copiedCS[:behaviorSections], Dict(allBs[bs] => copyBehaviorSection(original[:behaviorSections][allBs[bs]]))) + merge!(copiedCS[:behaviorSections], Dict(allBs[bs] => copy(original[:behaviorSections][allBs[bs]]))) end #if end #for - return copy + return copiedCS end #function copyCharacteristicSection - +=# end #module OperationModes diff --git a/src/Output.jl b/src/Output.jl index 74861a4..65ef8bc 100644 --- a/src/Output.jl +++ b/src/Output.jl @@ -263,9 +263,9 @@ function printSectionInformation(movingSection::Dict) println("CS ",csId," mit length=", CSs[csId][:length]," mit t=", CSs[csId][:t]) for bs in 1: length(allBs) if haskey(CSs[csId][:behaviorSections], allBs[bs]) - println("BS ",allBs[bs], " mit s_entry=", CSs[csId][:behaviorSections][allBs[bs]].s_entry, " und t=", CSs[csId][:behaviorSections][allBs[bs]].t) - # for point in 1:length(CSs[csId][:behaviorSections][allBs[bs]].dataPoints) - # println(CSs[csId][:behaviorSections][allBs[bs]].dataPoints[point]) + println("BS ",allBs[bs], " mit s_entry=", CSs[csId][:behaviorSections][allBs[bs]][:s_entry], " und t=", CSs[csId][:behaviorSections][allBs[bs]][:t]) + # for point in 1:length(CSs[csId][:behaviorSections][allBs[bs]][:dataPoints]) + # println(CSs[csId][:behaviorSections][allBs[bs]][:dataPoints][point]) # end end #if end #for diff --git a/src/Preparation.jl b/src/Preparation.jl index 7a1c4f7..df17366 100644 --- a/src/Preparation.jl +++ b/src/Preparation.jl @@ -6,7 +6,7 @@ using .MovingPhases export preparateSections -## create a moving section and its containing characteristic sections with securedd braking, acceleration and cruising behavior +## create a moving section and its containing characteristic sections with secured braking, acceleration and cruising behavior function preparateSections(path::Dict, train::Dict, settings::Dict) movingSection=createMovingSection(path, train[:v_limit]) movingSection=secureBrakingBehavior!(movingSection, train[:a_braking]) @@ -104,11 +104,10 @@ function secureAccelerationBehavior!(movingSection::Dict, settings::Dict, train: startingPoint.v=CSs[csId][:v_entry] accelerationCourse=[startingPoint] # List of data points - if CSs[csId][:v_entry] behavior, # type of behavior section: breakFree, clearing, acceleration, cruising, diminishing, coasting, cruisingAfterCoasting, braking or standstill + :type => original[:type], # type of behavior section: "breakFree", "clearing", "acceleration", "cruising", "diminishing", "coasting", "cruisingAfterCoasting", "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 -#= # a characteristic section is a part of the moving section. It contains behavior sections. -mutable struct CharacteristicSection - id::Integer # identifier - length::AbstractFloat # total length (in m) - s_entry::AbstractFloat # first position (in m) - s_exit::AbstractFloat # last position (in m) - t::AbstractFloat # total running time (in s) - E::AbstractFloat # total energy consumption (in Ws) - v_limit::AbstractFloat # speed limit (in m/s) - v_peak::AbstractFloat # maximum reachable speed (in m/s) - v_entry::AbstractFloat # maximum entry speed (in m/s) - v_exit::AbstractFloat # maximum exit speed (in m/s) - r_path::AbstractFloat # spedific path resistance (in ‰) - behaviorSections::AbstractDict{Symbol, BehaviorSection} # list of containing behavior sections -end # mutable struct CharacteristicSection -CharacteristicSection()=CharacteristicSection(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Dict{Symbol, BehaviorSection}()) -function CharacteristicSection(original::CharacteristicSection) - copy=CharacteristicSection(original.id, original.length, original.s_entry, original.s_exit, original.t, original.E, original.v_limit, original.v_peak, original.v_entry, original.v_exit, original.r_path, Dict{Symbol, BehaviorSection}()) - allBs=[:breakFree, :clearing, :acceleration, :cruising, :diminishing, :coasting, :cruisingAfterCoasting, :braking, :standstill] - for bs in 1: length(allBs) - if haskey(original.behaviorSections, allBs[bs]) - merge!(copy.behaviorSections, Dict(allBs[bs] => BehaviorSection(original.behaviorSections[allBs[bs]]))) - end #if - end #for - return copy -end #function CharacteristicSection -=# - end #module diff --git a/test/testEnums.jl b/test/testEnums.jl index e7d3cce..5303301 100644 --- a/test/testEnums.jl +++ b/test/testEnums.jl @@ -11,14 +11,14 @@ include("../src/Input.jl") using .Input using YAML, Test -@enum trainTypes passenger=1 freight=2 motorCoachTrain=3 +@enum trainType passenger=1 freight=2 motorCoachTrain=3 -@test Input.getEnum("passenger", trainTypes) == passenger::trainTypes -@test Input.getEnum("freight", trainTypes) == freight::trainTypes -@test Input.getEnum("motorCoachTrain", trainTypes) == motorCoachTrain::trainTypes +@test Input.getEnum("passenger", trainType) == passenger::trainType +@test Input.getEnum("freight", trainType) == freight::trainType +@test Input.getEnum("motorCoachTrain", trainType) == motorCoachTrain::trainType data = YAML.load(open("data/trains/train_passenger_IC2.yaml")) -@test Input.getEnum(data["train"]["trainType"], trainTypes) == passenger::trainTypes +@test Input.getEnum(data["train"]["trainType"], trainType) == passenger::trainType data = YAML.load(open("data/trains/train_freight_V90withOreConsist.yaml")) -@test Input.getEnum(data["train"]["trainType"], trainTypes) == freight::trainTypes \ No newline at end of file +@test Input.getEnum(data["train"]["trainType"], trainType) == freight::trainType