From f6ea317fd492ef668831dad2076b34eb9b12f759 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Tue, 17 May 2022 18:35:58 +0200 Subject: [PATCH 01/16] Fix input directories in ExtendedWorkingExample.jl --- docs/examples/ExtendedWorkingExample.jl | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/examples/ExtendedWorkingExample.jl b/docs/examples/ExtendedWorkingExample.jl index 1dadfc7..ded58ba 100644 --- a/docs/examples/ExtendedWorkingExample.jl +++ b/docs/examples/ExtendedWorkingExample.jl @@ -1,32 +1,35 @@ #!/usr/bin/env julia -import TrainRuns +using TrainRuns paths=[] -push!(paths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) -push!(paths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) -push!(paths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) -push!(paths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) +push!(paths, Path("test/data/paths/const.yaml")) +push!(paths, Path("test/data/paths/slope.yaml")) +push!(paths, Path("test/data/paths/speed.yaml")) +push!(paths, Path("test/data/paths/realworld.yaml")) settings=[] -push!(settings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml")) +push!(settings, Settings("test/data/settings/driving_course.yaml")) trains=[] -push!(trains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml")) -push!(trains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml")) -push!(trains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml")) +push!(trains, Train("test/data/trains/freight.yaml")) +push!(trains, Train("test/data/trains/local.yaml")) +push!(trains, Train("test/data/trains/longdistance.yaml")) +driving_courses=[] for path in paths # println(" - - - - - - - - -") # println("path: ", path[:name]) for train in trains # println("train: ", train[:name]) for settings in settings - resultsDict = trainrun(train, path, settings) - if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV" - exportToCsv(resultsDict, settings) - sleep(2) - end + push!(driving_courses, trainrun(train, path, settings)) + #driving_course = trainrun(train, path, settings) + + # old: if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV" + # old: exportToCsv(resultsDict, settings) + # old: sleep(2) + # old: end end end end From 250687a85144ea7240c8cf1bc59e6a51d5cdc85a Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Thu, 19 May 2022 21:42:29 +0200 Subject: [PATCH 02/16] Split calculation of vehicle resistances for different transport types --- src/behavior.jl | 6 +++++- src/formulary.jl | 27 ++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index 7ddae8c..30fb881 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -71,7 +71,11 @@ calculate and return tractive and resisting forces for a data point function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) # calculate resisting forces dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) - dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) + if train.transportType == :freight + dataPoint[:R_wagons] = calcFreightWagonsResistance(dataPoint[:v], train) + elseif train.transportType == :passenger + dataPoint[:R_wagons] = calcPassengerWagonsResistance(dataPoint[:v], train) + end dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train) dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] diff --git a/src/formulary.jl b/src/formulary.jl index 4bf6125..982104a 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -68,17 +68,34 @@ end #function calcTractionUnitResistance """ TODO -calculate and return the wagons vehicle resistance dependend on the velocity +calculate and return the freight wagons' vehicle resistance dependend on the velocity """ -function calcWagonsResistance(v::AbstractFloat, train::Train) - # equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] with more detailled factors (Lehmann, page 135) +function calcFreightWagonsResistance(v::AbstractFloat, train::Train) + # equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] + f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) + f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰) + m_w = train.m_w # mass of the set of wagons (consist) (in kg) + + F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw2/1000 * (v /v00)^2) # vehicle resistance of freight wagons (in N) with Strahl # /1000 because of the unit ‰ + +# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ... + return F_R_wagons +end #function calcWagonsResistance + +""" +TODO +calculate and return the passenger wagons' vehicle resistance dependend on the velocity +""" +function calcPassengerWagonsResistance(v::AbstractFloat, train::Train) + # equation is based on the equations of Sauthoff [Wende:2003, page 153] f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) f_Rw1 = train.f_Rw1 # coefficient for the consists resistance to rolling (in ‰) f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰) m_w = train.m_w # mass of the set of wagons (consist) (in kg) - F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰ -# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + calcForceFromCoefficient(f_Rw1, m_w) *v /v00 + calcForceFromCoefficient(f_Rw2, m_w) * ((v + Δv_air) /v00)^2 # vehicle resistance of the wagons (in N) + F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of passenger wagons (in N) with Sauthoff # /1000 because of the unit ‰ + +# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ... return F_R_wagons end #function calcWagonsResistance From ae5cc078622fde3cef5a9dc223366790aa0f563e Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Thu, 19 May 2022 21:45:10 +0200 Subject: [PATCH 03/16] Add the approxLevel from settings to formulary --- src/behavior.jl | 26 +++++++++++++------------- src/calc.jl | 6 +++--- src/characteristics.jl | 6 +++--- src/formulary.jl | 12 ++++++------ src/types.jl | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index 30fb881..8bb361c 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -246,7 +246,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] s_braking = 0.0 else - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # reset state flags @@ -272,7 +272,7 @@ function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s]) @@ -310,7 +310,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for the accelerating section @@ -337,7 +337,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached @@ -359,7 +359,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] speedLimitReached = drivingCourse[end][:v] > CS[:v_limit] @@ -558,11 +558,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for cruising section - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] @@ -785,7 +785,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # set state flags stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit] if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit] stateFlags[:tractionDeficit] = tractionDeficit @@ -807,14 +807,14 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for diminishing section targetSpeedReached = drivingCourse[end][:v] <= 0.0 endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit] - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the diminishing section @@ -842,7 +842,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] @@ -994,7 +994,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the coasting section @@ -1022,7 +1022,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: push!(BS[:dataPoints], drivingCourse[end][:i]) # conditions for the next while cycle - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak] diff --git a/src/calc.jl b/src/calc.jl index e9ed5ef..b4526e9 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -32,7 +32,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end # determine the different flags for switching between the states for creatinge moving phases - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N) previousSpeedLimitReached = false @@ -69,7 +69,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 @@ -79,7 +79,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 # TODO: define a minimum cruising length? diff --git a/src/characteristics.jl b/src/characteristics.jl index 7abcd10..35619dc 100644 --- a/src/characteristics.jl +++ b/src/characteristics.jl @@ -8,7 +8,7 @@ ## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior function determineCharacteristics(path::Path, train::Train, settings::Settings) movingSection = createMovingSection(path, train.v_limit, train.length) - movingSection = secureBrakingBehavior!(movingSection, train.a_braking) + movingSection = secureBrakingBehavior!(movingSection, train.a_braking, settings.approxLevel) movingSection = secureAcceleratingBehavior!(movingSection, settings, train) #movingSection = secureCruisingBehavior!(movingSection, settings, train) @@ -16,7 +16,7 @@ function determineCharacteristics(path::Path, train::Train, settings::Settings) end #function determineCharacteristics ## define the intersection velocities between the characterisitc sections to secure braking behavior -function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) +function secureBrakingBehavior!(movingSection::Dict, a_braking::Real, approxLevel::Integer) # this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end CSs = movingSection[:characteristicSections] @@ -27,7 +27,7 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) CS[:v_exit] = min(CS[:v_limit], followingCSv_entry) - v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length]) + v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length], approxLevel) CS[:v_entry] = min(CS[:v_limit], v_entryMax) CS[:v_peak] = CS[:v_entry] diff --git a/src/formulary.jl b/src/formulary.jl index 982104a..93161a4 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -28,7 +28,7 @@ ## } ######################### -approxLevel = 6 +#approxLevel = 6 v00 = 100/3.6 # velocity factor (in m/s) ## calculate forces @@ -206,7 +206,7 @@ function calc_ΔE(ΔW::Real) return ΔE end #function calc_ΔW -function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real) +function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer) # equation is based on [Wende:2003, page 37] # v_start: velocity at the start of braking (in m/s) @@ -215,18 +215,18 @@ function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real) s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start) # return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors - return max(0.0, ceil(s_braking, digits=approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors + return max(0.0, ceil(s_braking, digits= approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors end #function calcBrakingDistance -function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) +function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, approxLevel::Integer) # equation is based on [Wende:2003, page 37] # v_end: target velocity at the end of braking (in m/s) # a_braking: constant braking acceleration (in m/s^2) # s_braking: braking distance (in Ws) v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) -# return floor(v_start, digits=approxLevel) - return floor(v_start, digits=approxLevel +1) +# return floor(v_start, digits= approxLevel) + return floor(v_start, digits= approxLevel +1) end #function calcBrakingStartVelocity function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) diff --git a/src/types.jl b/src/types.jl index 0441086..89e9e1a 100644 --- a/src/types.jl +++ b/src/types.jl @@ -10,7 +10,7 @@ struct Settings massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip". stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity". stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second. - approxLevel::Int # value for approximation; used when rounding or interating. + approxLevel::Int # value for approximation; used when rounding or iterating. outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest", # complete Array() ":driving_course", or Dict() ":everything". outputFormat::Symbol # output as ":dataframe" or as ":dict". From 4c7980bbe69258a300b5699274af81cfd1921866 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Tue, 24 May 2022 16:15:08 +0200 Subject: [PATCH 04/16] Change behavior section "standstill" to "halt" --- src/behavior.jl | 14 +++++++------- src/calc.jl | 6 +++--- src/constructors.jl | 42 +++++++++++++++++++++--------------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index 8bb361c..7b32a0e 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -1304,11 +1304,11 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D end #function addBrakingSection! -## This function calculates the data point of the standstill. -# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. -function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}) +## This function calculates the data point of the halt. +# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the halt if needed. +function addHalt!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}) if drivingCourse[end][:v] == 0.0 - BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = createBehaviorSection("halt", 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) @@ -1319,10 +1319,10 @@ function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Setting # traction effort and resisting forces (in N) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) - merge!(CS[:behaviorSections], Dict(:standstill => BS)) - end # else: return the characteristic section without a standstillSection section + merge!(CS[:behaviorSections], Dict(:halt => BS)) + end # else: return the characteristic section without a halt section section return (CS, drivingCourse) -end #function addStandstill! +end #function addHalt! function mergeBehaviorSection!(BSs::Dict, BS::Dict) if !haskey(BSs, Symbol(BS[:type])) diff --git a/src/calc.jl b/src/calc.jl index b4526e9..b2ad4cd 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -44,7 +44,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t :speedLimitReached => drivingCourse[end][:v] > CS[:v_limit], :error => false) - # determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "standstill") + # determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "halt") while !stateFlags[:endOfCSReached] # s < s_exit if !stateFlags[:brakingStartReached] # s+s_braking < s_exit if !stateFlags[:tractionDeficit] @@ -103,7 +103,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end end #if s == s_exit - # standstill + # halt #end @@ -116,7 +116,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end end #for - (CSs[end], drivingCourse) = addStandstill!(CSs[end], drivingCourse, settings, train, CSs) + (CSs[end], drivingCourse) = addHalt!(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) diff --git a/src/constructors.jl b/src/constructors.jl index ffa27c1..116712f 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -63,7 +63,7 @@ function Settings(file="DEFAULT") }""") settings = YAML.load(open(file))["settings"] - + ## validate the loaded file try validate(schema, settings) @@ -116,12 +116,12 @@ function Path(file, type = :YAML) data = YAML.load(open(file)) if data["schema"] != "https://railtoolkit.org/schema/running-path.json" error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/running-path (2022.05)") end if data["schema_version"] != "2022.05" error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/running-path (2022.05)") end @@ -212,7 +212,7 @@ function Path(file, type = :YAML) validate(railtoolkit_schema, paths) catch err error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/running-path (2022.05)") end if length(paths) > 1 @@ -258,7 +258,7 @@ function Path(file, type = :YAML) station = elem[1] # first point of the section (in m) label = elem[2] # paths speed limt (in m/s) measure = elem[3] # specific path resistance of the section (in ‰) - + point = Dict(:station => station, :label => label, :measure => measure) @@ -315,14 +315,14 @@ function Train(file, type = :YAML) if type == :YAML data = YAML.load(open(file)) - if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json" + if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json" error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/rolling-stock (2022.05)") end if data["schema_version"] != "2022.05" error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/rolling-stock (2022.05)") end @@ -472,14 +472,14 @@ function Train(file, type = :YAML) } } } - } + } }""") try validate(railtoolkit_schema, data) catch err error("Could not load path file '$file'.\n - YAML format is not recognized. + YAML format is not recognized. Currently supported: railtoolkit/schema/rolling-stock (2022.05)") end @@ -514,7 +514,7 @@ function Train(file, type = :YAML) push!(vehicles, (data=vehicle, n=n, propulsion=propulsion) ) end end - + ## set the variables in "train" name = train["name"] id = train["id"] @@ -529,8 +529,8 @@ function Train(file, type = :YAML) haskey(vehicle.data, "load_limit") ? m_train_full += vehicle.data["load_limit"] * vehicle.n * 1000 : # in kg nothing - haskey(vehicle.data, "speed_limit") ? - v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing : + haskey(vehicle.data, "speed_limit") ? + v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing : nothing end @@ -569,17 +569,17 @@ function Train(file, type = :YAML) resis_air = [] rotMassFac = [] for car in cars - haskey(car.data, "base_resistance") ? - append!(resis_base,repeat([car.data["base_resistance"]],car.n)) : + haskey(car.data, "base_resistance") ? + append!(resis_base,repeat([car.data["base_resistance"]],car.n)) : append!(resis_base,repeat([f_Rw0],car.n)) - haskey(car.data, "rolling_resistance") ? - append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) : + haskey(car.data, "rolling_resistance") ? + append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) : append!(resis_roll,repeat([f_Rw1],car.n)) - haskey(car.data, "air_resistance") ? - append!(resis_air,repeat([car.data["air_resistance"]],car.n)) : + haskey(car.data, "air_resistance") ? + append!(resis_air,repeat([car.data["air_resistance"]],car.n)) : append!(resis_air, repeat([f_Rw2],car.n)) haskey(car.data, "rotation_mass") ? - append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) : + append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) : append!(rotMassFac,repeat([(ξ_cars ,car.data["mass"])],car.n)) m_car_empty += car.data["mass"] * car.n * 1000 # in kg m_car_full += car.data["mass"] * car.n * 1000 # in kg @@ -727,7 +727,7 @@ BehaviorSection() TODO! """ function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) BS= Dict( - :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "standstill" + :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "halt" :length => 0.0, # total length (in m) :s_entry => s_entry, # first position (in m) :s_exit => 0.0, # last position (in m) From 09743db7ad0a4d95293d2662e81b3480b4d24b7e Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Tue, 24 May 2022 16:56:05 +0200 Subject: [PATCH 05/16] Remove calculations of mechanical work and energy consumption --- src/behavior.jl | 24 ---------------- src/calc.jl | 3 +- src/characteristics.jl | 62 ------------------------------------------ src/constructors.jl | 7 ----- src/formulary.jl | 17 ------------ 5 files changed, 1 insertion(+), 112 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index 7b32a0e..d9c2d13 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -150,11 +150,6 @@ function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, cs newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m) newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s) newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s) - newPoint[:ΔW] = calc_ΔW(previousPoint[:F_T], newPoint[:Δs]) # mechanical work in this step (in Ws) - newPoint[:W] = previousPoint[:W] + newPoint[:ΔW] # mechanical work (in Ws) - newPoint[:ΔE] = calc_ΔE(newPoint[:ΔW]) # energy consumption in this step (in Ws) - newPoint[:E] = previousPoint[:E] + newPoint[:ΔE] # energy consumption (in Ws) - return newPoint end #function moveAStep @@ -225,18 +220,15 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: # remove the accelerating section from the CS CS[:t] = CS[:t] - get(CS[:behaviorSections], :accelerating, Dict(:t=>0.0))[:t] # total running time (in s) - CS[:E] = CS[:E] - get(CS[:behaviorSections], :accelerating, Dict(:E=>0.0))[:E] # total energy consumption (in Ws) delete!(CS[:behaviorSections], :accelerating) # calculate the accumulated breakFree section information 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) merge!(CS[:behaviorSections], Dict(:breakFree => BS)) end # else: return the characteristic section without a breakFree section @@ -516,12 +508,10 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla 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))) # 03/10 old: 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 running on a path with high resistances CS[:t] = CS[:t] + BS[:t] # total running time (in s) - CS[:E] = CS[:E] + BS[:E] # total energy consumption (in Ws) mergeBehaviorSection!(CS[:behaviorSections], BS) end @@ -773,11 +763,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: 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) mergeBehaviorSection!(CS[:behaviorSections], BS) end # else: return the characteristic section without a cruising section @@ -962,11 +950,9 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag 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) mergeBehaviorSection!(CS[:behaviorSections], BS) end @@ -1127,11 +1113,9 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: 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) merge!(CS[:behaviorSections], Dict(:coasting=>BS)) end @@ -1282,11 +1266,9 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D 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) merge!(CS[:behaviorSections], Dict(:braking=>BS)) end # else: return the characteristic section without a braking section @@ -1311,7 +1293,6 @@ function addHalt!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, tra BS = createBehaviorSection("halt", 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] @@ -1355,9 +1336,4 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) # end currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s) currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s) - - currentPoint[:ΔW] = 0.0 # mechanical work in this step (in Ws) - currentPoint[:W] = previousPoint[:W] + currentPoint[:ΔW] # mechanical work (in Ws) - currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws) - currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws) end #function recalculateLastBrakingPoint diff --git a/src/calc.jl b/src/calc.jl index b2ad4cd..3dd3cdc 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -12,7 +12,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t CSs::Vector{Dict} = movingSection[:characteristicSections] if settings.massModel == :homogeneous_strip && settings.stepVariable == speed - println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") + println("WARNING: ! ! ! TrainRuns.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") end startingPoint=createDataPoint() @@ -119,7 +119,6 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t (CSs[end], drivingCourse) = addHalt!(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 diff --git a/src/characteristics.jl b/src/characteristics.jl index 35619dc..1c01b3b 100644 --- a/src/characteristics.jl +++ b/src/characteristics.jl @@ -35,7 +35,6 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real, approxLeve # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit CS[:behaviorSections] = Dict() - CS[:E] = 0.0 CS[:t] = 0.0 followingCSv_entry = CS[:v_entry] @@ -102,69 +101,8 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, tr # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit CS[:behaviorSections] = Dict() - CS[:E] = 0.0 CS[:t] = 0.0 end #for return movingSection end #function secureAcceleratingBehavior! - - -#= -## define the intersection velocities between the characterisitc sections to secure cruising behavior -function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train) - # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak - CSs = movingSection[:characteristicSections] - - startingPoint = createDataPoint() - startingPoint[:i] = 1 - - previousCSv_exit = CSs[1][:v_entry] - - for CS in CSs - # conditions for entering the cruising phase - stateFlags = Dict(:endOfCSReached => false, - :brakingStartReached => false, - :tractionDeficit => false, - :resistingForceNegative => false, - :previousSpeedLimitReached => false, - :speedLimitReached => false, - :error => false, - :usedForDefiningCharacteristics => true) - - CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) - - startingPoint[:s] = CS[:s_entry] - startingPoint[:v] = CS[:v_peak] - cruisingCourse::Vector{Dict} = [startingPoint] # List of data points - - while !stateFlags[:endOfCSReached] #&& s_cruising > 0.0 - if !stateFlags[:tractionDeficit] - s_cruising = CS[:s_exit] - cruisingCourse[end][:s] - if !stateFlags[:resistingForceNegative]# cruisingCourse[end][:F_R] >= 0 - (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") # this function changes the cruisingCourse - else - (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking") - end - else - if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length - break - else - (CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort - end - end - end - - CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v]) - - previousCSv_exit = CS[:v_exit] - - # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit - CS[:behaviorSections] = Dict() - CS[:E] = 0.0 - CS[:t] = 0.0 - end #for - - return movingSection -end #function secureCruisingBehavior! -=# diff --git a/src/constructors.jl b/src/constructors.jl index 116712f..65fef2d 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -643,7 +643,6 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real :s_entry => s_entry, # first position (in m) :s_exit => s_exit, # last position (in m) :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) :characteristicSections => CSs) # list of containing characteristic sections return movingSection @@ -659,7 +658,6 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, :r_path => section[:f_Rp], # path resistance (in ‰) :behaviorSections => Dict(), # list of containing behavior sections :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) :v_limit => v_limit, # speed limit (in m/s) # initializing :v_entry, :v_peak and :v_exit with :v_limit :v_peak => v_limit, # maximum reachable speed (in m/s) @@ -707,10 +705,6 @@ function createDataPoint() :v => 0.0, # velocity (in m/s) :Δv => 0.0, # step size (in m/s) :a => 0.0, # acceleration (in m/s^2) - :W => 0.0, # mechanical work (in Ws) - :ΔW => 0.0, # mechanical work in this step (in Ws) - :E => 0.0, # energy consumption (in Ws) - :ΔE => 0.0, # energy consumption in this step (in Ws) :F_T => 0.0, # tractive effort (in N) :F_R => 0.0, # resisting force (in N) :R_path => 0.0, # path resistance (in N) @@ -732,7 +726,6 @@ function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, start :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 diff --git a/src/formulary.jl b/src/formulary.jl index 93161a4..f0df586 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -189,23 +189,6 @@ function calc_Δv_with_Δt(Δt::Real, a_prev::Real) return Δv end #function calc_Δv_with_Δt -function calc_ΔW(F_T_prev::Real, Δs::Real) - # equation is based on [Wende:2003, page 17] - - # F_T_prev: tractive force from previous data point - # Δs: distance step - ΔW = F_T_prev * Δs # mechanical work in this step (in Ws) - return ΔW -end #function calc_ΔW - -function calc_ΔE(ΔW::Real) - # simplified equation - # TODO! - # ΔW: mechanical work in this step (in Ws) - ΔE = ΔW # energy consumption in this step (in Ws) - return ΔE -end #function calc_ΔW - function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer) # equation is based on [Wende:2003, page 37] From b0026e55c2120c6a35f0c48e1ab208ec7f4a2c57 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Mon, 30 May 2022 17:47:36 +0200 Subject: [PATCH 06/16] Fix behavior.jl for halting and for velocity step method --- src/behavior.jl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index d9c2d13..da8acc2 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -26,6 +26,11 @@ julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 6000 ``` """ function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{}) + if v < 0.0 + #println("v=",v) + return 0.0 + end + for row in 1:length(tractiveEffortVelocityPairs) nextPair = tractiveEffortVelocityPairs[row] if nextPair[1] == v @@ -81,7 +86,7 @@ function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bs dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] # calculate tractive effort - if bsType == "braking" || bsType == "coasting" + if bsType == "braking" || bsType == "coasting" || bsType == "halt" dataPoint[:F_T] = 0.0 elseif bsType == "cruising" dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)) @@ -848,11 +853,11 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag # check which limit was reached and adjust the currentStepSize for the next cycle if cycle < settings.approxLevel+1 if drivingCourse[end][:v] < 0.0 - if settings.stepVariable == velocity - currentStepSize = drivingCourse[end-1][:v] - else + # if settings.stepVariable == :velocity + # currentStepSize = drivingCourse[end-1][:v] + # else currentStepSize = settings.stepSize / 10.0^cycle - end + # end elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing currentStepSize = settings.stepSize / 10.0^cycle @@ -1033,14 +1038,14 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing - if settings.stepVariable == velocity + if settings.stepVariable == :velocity currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] else currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] > CS[:v_peak] testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing - if settings.stepVariable == velocity + if settings.stepVariable == :velocity currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v] else currentStepSize = settings.stepSize / 10.0^cycle From 191d19d3ef2eef5eda5056de0a6cb086cc07fed2 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Mon, 30 May 2022 20:10:45 +0200 Subject: [PATCH 07/16] Refactor conversion of traction unit's air resistance --- src/constructors.jl | 19 ++++++++++--------- src/formulary.jl | 10 +++++----- src/types.jl | 4 ++-- test/data/trains/freight.yaml | 2 +- test/data/trains/local.yaml | 6 +++--- test/data/trains/longdistance.yaml | 2 +- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/constructors.jl b/src/constructors.jl index 65fef2d..3500130 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -303,12 +303,12 @@ function Train(file, type = :YAML) transportType = :freight # "freight" or "passenger" for resistance calculation v_limit = 140 # in m/s (default 504 km/h) a_braking = 0 # in m/s^2, todo: implement as function - f_Rtd0 = 0 # coefficient for basic resistance due to the traction units driving axles (in ‰) - f_Rtc0 = 0 # coefficient for basic resistance due to the traction units carring axles (in ‰) - F_Rt2 = 3000 # coefficient for air resistance of the traction units (in N) - f_Rw0 = 0 # coefficient for the consists basic resistance (in ‰) - f_Rw1 = 0 # coefficient for the consists resistance to rolling (in ‰) - f_Rw2 = 0 # coefficient fo the consistsr air resistance (in ‰) + f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰) + f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰) + f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰) + f_Rw0 = 0 # coefficient for the consist's basic resistance (in ‰) + f_Rw1 = 0 # coefficient for the consist's resistance to rolling (in ‰) + f_Rw2 = 0 # coefficient for the consist's air resistance (in ‰) F_v_pairs = [] # [v in m/s, F_T in N] ## load from file @@ -520,6 +520,7 @@ function Train(file, type = :YAML) id = train["id"] haskey(train, "UUID") ? uuid = parse(UUID, train["UUID"] ) : nothing transportType == :freight ? a_braking = -0.225 : a_braking = -0.375 # set a default a_braking value depending on the train type + #TODO: add source: Brünger, Dahlhaus, 2014 p. 74 (see formulary.jl) ## set the variables for all vehicles for vehicle in vehicles @@ -553,7 +554,7 @@ function Train(file, type = :YAML) haskey(loco, "a_braking") ? a_braking = loco["a_braking"] : nothing haskey(loco, "base_resistance") ? f_Rtd0 = loco["base_resistance"] : nothing haskey(loco, "rolling_resistance") ? f_Rtc0 = loco["rolling_resistance"] : nothing - haskey(loco, "air_resistance") ? F_Rt2 = loco["air_resistance"] * g * m_loco : nothing + haskey(loco, "air_resistance") ? f_Rt2 = loco["air_resistance"] : nothing haskey(loco, "mass_traction") ? m_td = loco["mass_traction"] * 1000 : m_td = m_t haskey(loco, "rotation_mass") ? ξ_loco = loco["rotation_mass"] : nothing m_tc = m_loco- m_td @@ -607,7 +608,7 @@ function Train(file, type = :YAML) ξ_train, ξ_loco, ξ_cars, transportType, v_limit, a_braking, - f_Rtd0, f_Rtc0, F_Rt2, f_Rw0, f_Rw1, f_Rw2, + f_Rtd0, f_Rtc0, f_Rt2, f_Rw0, f_Rw1, f_Rw2, F_v_pairs ) @@ -674,7 +675,7 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, for POI in path.poi s_poi = POI[:station] if POI[:measure] == "rear" - s_poi -= s_trainLength + s_poi += s_trainLength end if s_entry < s_poi && s_poi < s_exit push!(pointsOfInterest, (s_poi, POI[:label]) ) diff --git a/src/formulary.jl b/src/formulary.jl index f0df586..a6961b6 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -55,15 +55,15 @@ function calcTractionUnitResistance(v::AbstractFloat, train::Train) # equation is based on [Wende:2003, page 151] f_Rtd0 = train.f_Rtd0 # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtc0 = train.f_Rtc0 # coefficient for basic resistance due to the traction units carring axles (in ‰) - F_Rt2 = train.F_Rt2 # coefficient for air resistance of the traction units (in N) + f_Rt2 = train.f_Rt2 # coefficient for air resistance of the traction unit (in ‰) m_td = train.m_td # mass on the traction unit's driving axles (in kg) m_tc = train.m_tc # mass on the traction unit's carrying axles (in kg) - F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ - # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) + + F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + f_Rt2/1000 * (m_td+m_tc) * g * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ + # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + calcForceFromCoefficient(f_Rt2, m_td+m_tc) * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) return F_R_tractionUnit - #TODO: same variable name like in the rest of the tool? return R_traction - #TODO: just one line? return train.f_Rtd0/1000*train.m_td*g+train.f_Rtc0/1000*train.m_tc*g+train.F_Rt2*((v+train.Δv_air)/v00)^2 # /1000 because of the unit ‰ + #TODO: same variable name like in the rest of TrainRuns? return R_traction end #function calcTractionUnitResistance """ diff --git a/src/types.jl b/src/types.jl index 89e9e1a..fd1c840 100644 --- a/src/types.jl +++ b/src/types.jl @@ -45,10 +45,10 @@ struct Train a_braking::Real # in m/s^2 # coefficients for the vehicle resistance - # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_air)/v00)^2) + # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+f_Rt2*m_loco*g*((v+Δv_air)/v00)^2) f_Rtd0::Real # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtc0::Real # coefficient for basic resistance due to the traction units carring axles (in ‰) - F_Rt2::Real # coefficient for air resistance of the traction units (in N) + f_Rt2::Real # coefficient for air resistance of the traction units (in ‰) # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_air)/v00)^2)) f_Rw0::Real # coefficient for the consists basic resistance (in ‰) diff --git a/test/data/trains/freight.yaml b/test/data/trains/freight.yaml index c23db6f..9e0025b 100644 --- a/test/data/trains/freight.yaml +++ b/test/data/trains/freight.yaml @@ -37,7 +37,7 @@ vehicles: rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit base_resistance: 2.2 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ - air_resistance: 0.01 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula + air_resistance: 10 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula tractive_effort: - [0.0, 186940] diff --git a/test/data/trains/local.yaml b/test/data/trains/local.yaml index 5c380e8..306e637 100644 --- a/test/data/trains/local.yaml +++ b/test/data/trains/local.yaml @@ -9,12 +9,12 @@ trains: vehicles: - name: Siemens Desiro Classic # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic - id: DB_BR_642 + id: DB_BR_642 UUID: c915c80d-c63d-490b-879f-c481e4b62b55 picture: https://commons.wikimedia.org/wiki/File:Liesel_28-11-10_642_055-8_im_Bahnhof_Scharfenstein.JPG power_type: diesel # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic vehicle_type: multiple unit # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic - + length: 41.7 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic mass: 68.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic @@ -26,7 +26,7 @@ vehicles: rotation_mass: 1.08 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung" base_resistance: 3.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰ rolling_resistance: 1.4 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰ - air_resistance: 0.0039 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N + air_resistance: 3.9 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N # tractive effort as pairs of speed and tractive effort tractive_effort: diff --git a/test/data/trains/longdistance.yaml b/test/data/trains/longdistance.yaml index 2369208..066b51c 100644 --- a/test/data/trains/longdistance.yaml +++ b/test/data/trains/longdistance.yaml @@ -54,7 +54,7 @@ vehicles: rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit base_resistance: 2.5 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ - air_resistance: 0.006 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula + air_resistance: 6.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula tractive_effort: - [0.0, 300000] From 6d34704f588f37fb568933d487346a9fbf376d62 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Mon, 30 May 2022 20:11:38 +0200 Subject: [PATCH 08/16] Fix example runtimes after refactoring calculations --- test/runtests.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 167e358..4baa289 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -53,18 +53,18 @@ tests = Base.Iterators.product(trains,paths) anticipated = Dict( :default => Dict( - :longdistance_speed => 499.96109564970516, - :freight_slope => 831.4768274141168, - :local_slope => 396.99313307033276, - :longdistance_const => 328.83479381353095, - :freight_realworld => 8971.50124080998, - :longdistance_slope => 329.22915822053164, - :freight_const => 727.7969403041934, - :longdistance_realworld => 2900.1198723158523, - :local_speed => 524.3948201513945, - :local_realworld => 3443.917823618831, - :freight_speed => 733.2610572579886, - :local_const => 392.7234008268302 + :freight_const => 746.6594691660882, + :freight_slope => 842.3797947097586, + :freight_speed => 751.9727357301351, + :freight_realworld => 8789.299477891092, + :local_const => 392.6801497584646, + :local_slope => 396.59291844946534, + :local_speed => 524.3734475900396, + :local_realworld => 3438.3543735577446, + :longdistance_const => 330.8511578156266, + :longdistance_slope => 331.7163794230447, + :longdistance_speed => 501.13448446081713, + :longdistance_realworld => 2913.3759609192407 ) ) From 9d26c6569fead698aa95f4e2ed4ec1cea6817752 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Tue, 31 May 2022 13:06:40 +0200 Subject: [PATCH 09/16] Add point of interest labels to data points --- src/behavior.jl | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index da8acc2..da925a4 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -180,12 +180,12 @@ function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s:: end #function getCurrentSpeedLimit """ -? +TODO """ function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real) - for s_POI in pointsOfInterest - if s_POI[1] > s - return s_POI + for POI in pointsOfInterest + if POI[1] > s + return POI end end error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.") @@ -505,6 +505,9 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla if drivingCourse[end][:s] == CS[:s_exit] endOfCSReached = true end + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end end #while @@ -591,7 +594,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # use the conditions for the cruising section while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used currentStepSize = settings.stepSize - nextPointOfInterest[1] = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) + nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation @@ -714,6 +717,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: end end end #for + + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end + end #while end #if @@ -724,7 +732,10 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: while !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used # 03/09 old: while drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] - nextPointOfInterest = min(BS[:s_entry]+s_cruising, getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1]) + nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) + if nextPointOfInterest[1] > BS[:s_entry]+s_cruising + nextPointOfInterest = [BS[:s_entry]+s_cruising, ""] + end # tractive effort (in N): #03/25 drivingCourse[end][:F_T] = min(drivingCourse[end][:F_T], max(0.0, drivingCourse[end][:F_R])) @@ -745,6 +756,9 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id])) drivingCourse[end][:behavior] = BS[:type] + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end push!(BS[:dataPoints], drivingCourse[end][:i]) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) @@ -817,7 +831,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections - nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1] + nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation @@ -948,6 +962,10 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag # end end #if end #for + + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end end #while if length(BS[:dataPoints]) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start? @@ -1110,6 +1128,11 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: end end end #for + + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end + end #while stateFlags[:speedLimitReached] = false @@ -1265,6 +1288,11 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D end end end #for + + if drivingCourse[end][:s] == nextPointOfInterest[1] + drivingCourse[end][:label] = nextPointOfInterest[2] + end + end #while # calculate the accumulated coasting section information From 8a97de3fdfdff743319f9b7056a1de45ffbf857a Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Tue, 31 May 2022 17:23:56 +0200 Subject: [PATCH 10/16] Add dataFrame as output format --- src/output.jl | 124 ++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/src/output.jl b/src/output.jl index c7165be..2282584 100644 --- a/src/output.jl +++ b/src/output.jl @@ -5,26 +5,33 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" +using DataFrames + function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) if settings.outputDetail == :running_time - output = movingSection[:t] # TODO: or use drivingCourse[end][:t] + output = drivingCourse[end][:t] elseif settings.outputDetail == :points_of_interest # add points of interest if !isempty(path.poi) - # for elem in 1:length(driving_course) - # end + # output = Dict[] + # POI = 1 + # i = 1 + # while POI <= length(path.poi) && i <= drivingCourse[end][:i] + # if path.poi[POI][:station] == drivingCourse[i][:s] + # push!(output, drivingCourse[i]) + # POI = POI+1 + # end + # i = i+1 + # end + # get only the driving course's data points with POI labels output = Dict[] - POI = 1 - i = 1 - while POI <= length(path.poi) && i <= drivingCourse[end][:i] - if path.poi[POI][:station] == drivingCourse[i][:s] - push!(output, drivingCourse[i]) - POI = POI+1 + for point in 1:length(drivingCourse) + if point[:label] != "" + push!(output, point) end - i = i+1 end end @@ -37,74 +44,61 @@ function createOutput(train::Train, settings::Settings, path::Path, movingSectio # add moving section and driving courses - if settings[:operationModeMinimumRunningTime] == true - merge!(output, Dict(:movingSectionMinimumRunningTime => movingSection, - :drivingCourseMinimumRunningTime => drivingCourse)) - elseif settings[:operationModeMinimumEnergyConsumption] == true - merge!(output, Dict(:movingSectionMinimumEnergyConsumption => movingSection, - :drivingCourseMinimumEnergyConsumption => drivingCourse)) - end + merge!(output, Dict(:movingSection => movingSection, + :drivingCourse => drivingCourse)) + # add points of interest if !isempty(path.poi) - pointsOfInterest = Vector{Dict}() - POI = 1 - i = 1 - while POI <= length(path.poi) && i <= drivingCourse[end][:i] - if path.poi[POI] == drivingCourse[i][:s] - push!(pointsOfInterest, drivingCourse[i]) - POI = POI+1 + pointsOfInterest = Dict[] + # get only the driving course's data points with POI labels + output = Dict[] + for point in 1:length(drivingCourse) + if point[:label] != "" + push!(pointsOfInterest, point) end - i = i+1 end - if settings[:operationModeMinimumRunningTime] == true - merge!(output, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest)) - elseif settings[:operationModeMinimumEnergyConsumption] == true - merge!(output, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest)) - end + merge!(output, Dict(:pointsOfInterest => pointsOfInterest)) + + end + + if settings.outputFormat == :dataframe + return createDataFrameForDataPoints(output[:drivingCourse]) + else + return output end - else - output = nothing end - return output + + if settings.outputFormat == :dataframe + return createDataFrame(output) + else + return output + end end -#= -function createOutputDict(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) - outputDict = Dict{Symbol,Any}() - merge!(outputDict, Dict(:train => train, :path => path, :settings => settings)) +function createDataFrame(runningTime::AbstractFloat) + # create DataFrame with running time information + dataFrame = DataFrame(column1=["t (in s)", runningTime]) +end - # add moving section and driving courses - if settings[:operationModeMinimumRunningTime] == true - merge!(outputDict, Dict(:movingSectionMinimumRunningTime => movingSection, - :drivingCourseMinimumRunningTime => drivingCourse)) - elseif settings[:operationModeMinimumEnergyConsumption] == true - merge!(outputDict, Dict(:movingSectionMinimumEnergyConsumption => movingSection, - :drivingCourseMinimumEnergyConsumption => drivingCourse)) - end +function createDataFrame(dataPoints::Vector{Dict}) + header = ["i", "behavior", "station label", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)","a (in m/s^2)"] + columnSymbols = [:i, :behavior, :label, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :a] - # add points of interest - if !isempty(path.poi) - pointsOfInterest = Vector{Dict}() - POI = 1 - i = 1 - while POI <= length(path.poi) && i <= drivingCourse[end][:i] - if path.poi[POI] == drivingCourse[i][:s] - push!(pointsOfInterest, drivingCourse[i]) - POI = POI+1 - end - i = i+1 + allColumns = Array{Any,1}[] + for column in 1:length(header) + currentColumn = Any[] + push!(currentColumn, header[column]) + for point in dataPoints + push!(currentColumn, point[columnSymbols[column]]) end + push!(allColumns, currentColumn) + end # for - if settings[:operationModeMinimumRunningTime] == true - merge!(outputDict, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest)) - elseif settings[:operationModeMinimumEnergyConsumption] == true - merge!(outputDict, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest)) - end - end + # combine the columns in a data frame + dataFrame = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16]) - return outputDict -end # function createOutputDict -=# + return dataFrame +end #createDataFrameForDrivingCourse From 99c873a4e7fa735cb83efdebef82a7095ed17e44 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Thu, 2 Jun 2022 12:32:00 +0200 Subject: [PATCH 11/16] Refactor output detail and format and adapt examples --- docs/examples/ExtendedWorkingExample.jl | 23 ++---- docs/examples/MinimalWorkingExample.jl | 3 +- src/TrainRuns.jl | 10 +-- src/constructors.jl | 10 +-- src/output.jl | 95 +++++++--------------- src/types.jl | 6 +- test/data/settings/driving_course.yaml | 2 +- test/data/settings/everything.yaml | 4 - test/data/settings/points_of_interest.yaml | 2 +- test/runtests.jl | 30 +++---- 10 files changed, 68 insertions(+), 117 deletions(-) delete mode 100644 test/data/settings/everything.yaml diff --git a/docs/examples/ExtendedWorkingExample.jl b/docs/examples/ExtendedWorkingExample.jl index ded58ba..97be3cb 100644 --- a/docs/examples/ExtendedWorkingExample.jl +++ b/docs/examples/ExtendedWorkingExample.jl @@ -1,6 +1,7 @@ #!/usr/bin/env julia using TrainRuns +using CSV paths=[] push!(paths, Path("test/data/paths/const.yaml")) @@ -8,28 +9,16 @@ push!(paths, Path("test/data/paths/slope.yaml")) push!(paths, Path("test/data/paths/speed.yaml")) push!(paths, Path("test/data/paths/realworld.yaml")) -settings=[] -push!(settings, Settings("test/data/settings/driving_course.yaml")) - trains=[] push!(trains, Train("test/data/trains/freight.yaml")) push!(trains, Train("test/data/trains/local.yaml")) push!(trains, Train("test/data/trains/longdistance.yaml")) -driving_courses=[] -for path in paths - # println(" - - - - - - - - -") - # println("path: ", path[:name]) - for train in trains - # println("train: ", train[:name]) - for settings in settings - push!(driving_courses, trainrun(train, path, settings)) - #driving_course = trainrun(train, path, settings) +settings = Settings("test/data/settings/driving_course.yaml") - # old: if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV" - # old: exportToCsv(resultsDict, settings) - # old: sleep(2) - # old: end - end +for p in 1:length(paths) + for t in 1:length(trains) + driving_course = trainrun(trains[t], paths[p], settings) + CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course, header=false) end end diff --git a/docs/examples/MinimalWorkingExample.jl b/docs/examples/MinimalWorkingExample.jl index 129bb2b..ba4577d 100644 --- a/docs/examples/MinimalWorkingExample.jl +++ b/docs/examples/MinimalWorkingExample.jl @@ -5,6 +5,7 @@ using TrainRuns train = Train("test/data/trains/freight.yaml") path = Path("test/data/paths/const.yaml") -runtime = trainrun(train, path) +runtime_dataFrame = trainrun(train, path) +runtime = runtime_dataFrame[!, 1][2] println("The train needs $runtime seconds for the running path.") diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl index d6de6ad..aeaa827 100644 --- a/src/TrainRuns.jl +++ b/src/TrainRuns.jl @@ -13,13 +13,13 @@ using UUIDs, Dates, Statistics ## loading external packages using YAML, JSONSchema, DataFrames -export +export ## Interface trainrun, Train, Path, Settings ## global variables global g = 9.80665 # acceleration due to gravity (in m/s^2) -global μ = 0.2 # friction as constant, todo: implement as function +global μ = 0.2 # friction as constant, TODO: implement as function global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s) ## include package files @@ -49,14 +49,14 @@ xxx.xx # in seconds function trainrun(train::Train, path::Path, settings=Settings()::Settings) # prepare the input data movingSection = determineCharacteristics(path, train, settings) - settings.outputDetail == :everything && println("The moving section has been prepared.") + # settings.outputDetail == :verbose && println("The moving section has been prepared.") # calculate the train run for oparation mode "minimum running time" (movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train) - settings.outputDetail == :everything && println("The driving course for the shortest running time has been calculated.") + # settings.outputDetail == :verbose && println("The driving course for the shortest running time has been calculated.") # accumulate data and create an output dictionary - output = createOutput(train, settings, path, movingSection, drivingCourse) + output = createOutput(settings, path, drivingCourse) return output end # function trainrun diff --git a/src/constructors.jl b/src/constructors.jl index 3500130..9e459dd 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -52,12 +52,12 @@ function Settings(file="DEFAULT") "outputDetail": { "description": "Selecting the detail of the result", "type": "string", - "enum": [ "running_time", "points_of_interest", "driving_course", "everything" ] + "enum": [ "running_time", "points_of_interest", "driving_course" ] }, "outputFormat": { "description": "Output format", "type": "string", - "enum": [ "dataframe", "dict" ] + "enum": [ "dataframe", "vector" ] } } }""") @@ -256,7 +256,7 @@ function Path(file, type = :YAML) sort!(tmp_points, by = x -> x[1]) for elem in tmp_points station = elem[1] # first point of the section (in m) - label = elem[2] # paths speed limt (in m/s) + label = elem[2] # paths speed limt (in m/s) measure = elem[3] # specific path resistance of the section (in ‰) point = Dict(:station => station, @@ -302,7 +302,7 @@ function Train(file, type = :YAML) ξ_cars = 1.06 # rotation mass factor transportType = :freight # "freight" or "passenger" for resistance calculation v_limit = 140 # in m/s (default 504 km/h) - a_braking = 0 # in m/s^2, todo: implement as function + a_braking = 0 # in m/s^2, TODO: implement as function f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰) f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰) f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰) @@ -712,7 +712,7 @@ function createDataPoint() :R_train => 0.0, # train resistance (in N) :R_traction => 0.0, # traction unit resistance (in N) :R_wagons => 0.0, # set of wagons resistance (in N) - :label => "" # a label for importend points + :label => "" # a label for important points ) return dataPoint end #function createDataPoint diff --git a/src/output.jl b/src/output.jl index 2282584..b838ac7 100644 --- a/src/output.jl +++ b/src/output.jl @@ -5,15 +5,12 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -using DataFrames - -function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) +function createOutput(settings::Settings, path::Path, drivingCourse::Vector{Dict}) if settings.outputDetail == :running_time - output = drivingCourse[end][:t] + output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])] - elseif settings.outputDetail == :points_of_interest + elseif settings.outputDetail == :points_of_interest && !isempty(path.poi) # add points of interest - if !isempty(path.poi) # output = Dict[] # POI = 1 @@ -26,79 +23,47 @@ function createOutput(train::Train, settings::Settings, path::Path, movingSectio # i = i+1 # end - # get only the driving course's data points with POI labels - output = Dict[] - for point in 1:length(drivingCourse) - if point[:label] != "" - push!(output, point) - end + # get only the driving course's data points with POI labels + output = Dict[] + for point in drivingCourse + if point[:label] != "" + push!(output, point) end end - elseif settings.outputDetail == :driving_course + else #if settings.outputDetail == :driving_course || (settings.outputDetail == :points_of_interest && !isempty(path.poi)) output = drivingCourse - - elseif settings.outputDetail == :everything - output = Dict{Symbol,Any}() - merge!(output, Dict(:train => train, :path => path, :settings => settings)) - - - # add moving section and driving courses - merge!(output, Dict(:movingSection => movingSection, - :drivingCourse => drivingCourse)) - - - # add points of interest - if !isempty(path.poi) - pointsOfInterest = Dict[] - # get only the driving course's data points with POI labels - output = Dict[] - for point in 1:length(drivingCourse) - if point[:label] != "" - push!(pointsOfInterest, point) - end - end - - merge!(output, Dict(:pointsOfInterest => pointsOfInterest)) - - end - - if settings.outputFormat == :dataframe - return createDataFrameForDataPoints(output[:drivingCourse]) - else - return output - end end if settings.outputFormat == :dataframe - return createDataFrame(output) - else + return createDataFrame(output, settings.outputDetail) + elseif settings.outputFormat == :vector return output end end -function createDataFrame(runningTime::AbstractFloat) - # create DataFrame with running time information - dataFrame = DataFrame(column1=["t (in s)", runningTime]) -end +function createDataFrame(output_vector::Vector{Dict}, outputDetail) + if outputDetail == :running_time + # create DataFrame with running time information + dataFrame = DataFrame(column1=["t (in s)", output_vector[end][:t]]) + else # :points_of_interest or :driving_course + header = ["label", "driving mode", "s (in m)", "v (in m/s)", "t (in s)", "a (in m/s^2)", "F_T (in N)", "F_R (in N)", "R_path (in N)", "R_traction (in N)", "R_wagons (in N)"] + columnSymbols = [:label, :behavior, :s, :v, :t, :a, :F_T, :F_R, :R_path, :R_traction, :R_wagons] -function createDataFrame(dataPoints::Vector{Dict}) - header = ["i", "behavior", "station label", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)","a (in m/s^2)"] - columnSymbols = [:i, :behavior, :label, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :a] + allColumns = Array{Any,1}[] + for column in 1:length(header) + currentColumn = Any[] + push!(currentColumn, header[column]) + for point in output_vector + push!(currentColumn, point[columnSymbols[column]]) + end + push!(allColumns, currentColumn) + end # for - allColumns = Array{Any,1}[] - for column in 1:length(header) - currentColumn = Any[] - push!(currentColumn, header[column]) - for point in dataPoints - push!(currentColumn, point[columnSymbols[column]]) - end - push!(allColumns, currentColumn) - end # for - - # combine the columns in a data frame - dataFrame = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16]) + # combine the columns in a data frame + dataFrame = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11]) + end return dataFrame end #createDataFrameForDrivingCourse diff --git a/src/types.jl b/src/types.jl index fd1c840..5ffee12 100644 --- a/src/types.jl +++ b/src/types.jl @@ -11,9 +11,9 @@ struct Settings stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity". stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second. approxLevel::Int # value for approximation; used when rounding or iterating. - outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest", - # complete Array() ":driving_course", or Dict() ":everything". - outputFormat::Symbol # output as ":dataframe" or as ":dict". + outputDetail::Symbol # single Float() ":running_time", Vector() of ":points_of_interest", + # or complete Vector() ":driving_course" + outputFormat::Symbol # output as ":dataframe" or as ":vector". end #struct Settings diff --git a/test/data/settings/driving_course.yaml b/test/data/settings/driving_course.yaml index 46ac088..3b5bae5 100644 --- a/test/data/settings/driving_course.yaml +++ b/test/data/settings/driving_course.yaml @@ -1,4 +1,4 @@ %YAML 1.2 --- settings: - outputDetail: "driving_course" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" + outputDetail: "driving_course" # single value "running_time", list of "points_of_interest", complete "driving_course" diff --git a/test/data/settings/everything.yaml b/test/data/settings/everything.yaml deleted file mode 100644 index 0e2cdf1..0000000 --- a/test/data/settings/everything.yaml +++ /dev/null @@ -1,4 +0,0 @@ -%YAML 1.2 ---- -settings: - outputDetail: "everything" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" diff --git a/test/data/settings/points_of_interest.yaml b/test/data/settings/points_of_interest.yaml index d0784ff..d5e9bed 100644 --- a/test/data/settings/points_of_interest.yaml +++ b/test/data/settings/points_of_interest.yaml @@ -1,4 +1,4 @@ %YAML 1.2 --- settings: - outputDetail: "points_of_interest" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" + outputDetail: "points_of_interest" # single value "running_time", list of "points_of_interest", complete "driving_course" diff --git a/test/runtests.jl b/test/runtests.jl index 4baa289..3019c23 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,25 +14,24 @@ settings = Dict() @testset "load data" begin println("testing load train data") - push!(trains, :freight => @time Train("data/trains/freight.yaml")) - push!(trains, :local => @time Train("data/trains/local.yaml")) - push!(trains, :longdistance => @time Train("data/trains/longdistance.yaml")) + push!(trains, :freight => @time Train("test/data/trains/freight.yaml")) + push!(trains, :local => @time Train("test/data/trains/local.yaml")) + push!(trains, :longdistance => @time Train("test/data/trains/longdistance.yaml")) println("testing load path data") - push!(paths, :const => @time Path("data/paths/const.yaml")) - push!(paths, :slope => @time Path("data/paths/slope.yaml")) - push!(paths, :speed => @time Path("data/paths/speed.yaml")) - push!(paths, :realworld => @time Path("data/paths/realworld.yaml")) + push!(paths, :const => @time Path("test/data/paths/const.yaml")) + push!(paths, :slope => @time Path("test/data/paths/slope.yaml")) + push!(paths, :speed => @time Path("test/data/paths/speed.yaml")) + push!(paths, :realworld => @time Path("test/data/paths/realworld.yaml")) println("testing load settings data") push!(settings, "default" => @time Settings()) - push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml")) - push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml")) - push!(settings, "everything" => @time Settings("data/settings/everything.yaml")) - push!(settings, "strip" => @time Settings("data/settings/strip.yaml")) - push!(settings, "time" => @time Settings("data/settings/time.yaml")) - push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml")) - push!(settings, "velocity" => @time Settings("data/settings/velocity.yaml")) + push!(settings, "poi" => @time Settings("test/data/settings/points_of_interest.yaml")) + push!(settings, "drivingcourse" => @time Settings("test/data/settings/driving_course.yaml")) + push!(settings, "strip" => @time Settings("test/data/settings/strip.yaml")) + push!(settings, "time" => @time Settings("test/data/settings/time.yaml")) + push!(settings, "timestrip" => @time Settings("test/data/settings/time_strip.yaml")) + push!(settings, "velocity" => @time Settings("test/data/settings/velocity.yaml")) @test typeof(first(paths)[2]) == Path @test typeof(first(settings)[2]) == Settings @@ -75,7 +74,8 @@ anticipated = Dict( for test in tests test_name = String(test[1][1]) * "_" * String(test[2][1]) println("testing $test_name") - @time result = trainrun(test[1][2],test[2][2]) + @time result_dataFrame = trainrun(test[1][2], test[2][2]) + result = result_dataFrame[!, 1][2] expected = anticipated[:default][Symbol(test_name)] # compare result to test data set @test isapprox(result, expected, rtol=0.01) From b05b9dbd0bbbb91d1dade7c062f7a5ba8c09ecff Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Fri, 3 Jun 2022 12:26:58 +0200 Subject: [PATCH 12/16] Refactor the DataFrame output --- docs/examples/ExtendedWorkingExample.jl | 2 +- docs/examples/MinimalWorkingExample.jl | 3 +-- src/output.jl | 28 ++++++++++++++---------- test/runtests.jl | 29 ++++++++++++------------- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/docs/examples/ExtendedWorkingExample.jl b/docs/examples/ExtendedWorkingExample.jl index 97be3cb..9824695 100644 --- a/docs/examples/ExtendedWorkingExample.jl +++ b/docs/examples/ExtendedWorkingExample.jl @@ -19,6 +19,6 @@ settings = Settings("test/data/settings/driving_course.yaml") for p in 1:length(paths) for t in 1:length(trains) driving_course = trainrun(trains[t], paths[p], settings) - CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course, header=false) + CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course) end end diff --git a/docs/examples/MinimalWorkingExample.jl b/docs/examples/MinimalWorkingExample.jl index ba4577d..0c7b449 100644 --- a/docs/examples/MinimalWorkingExample.jl +++ b/docs/examples/MinimalWorkingExample.jl @@ -5,7 +5,6 @@ using TrainRuns train = Train("test/data/trains/freight.yaml") path = Path("test/data/paths/const.yaml") -runtime_dataFrame = trainrun(train, path) -runtime = runtime_dataFrame[!, 1][2] +runtime = trainrun(train, path)[end, :t] println("The train needs $runtime seconds for the running path.") diff --git a/src/output.jl b/src/output.jl index b838ac7..dca58ea 100644 --- a/src/output.jl +++ b/src/output.jl @@ -45,24 +45,30 @@ end function createDataFrame(output_vector::Vector{Dict}, outputDetail) if outputDetail == :running_time - # create DataFrame with running time information - dataFrame = DataFrame(column1=["t (in s)", output_vector[end][:t]]) + # create a DataFrame with running time information + dataFrame = DataFrame(t=[output_vector[end][:t]]) else # :points_of_interest or :driving_course - header = ["label", "driving mode", "s (in m)", "v (in m/s)", "t (in s)", "a (in m/s^2)", "F_T (in N)", "F_R (in N)", "R_path (in N)", "R_traction (in N)", "R_wagons (in N)"] columnSymbols = [:label, :behavior, :s, :v, :t, :a, :F_T, :F_R, :R_path, :R_traction, :R_wagons] - allColumns = Array{Any,1}[] - for column in 1:length(header) - currentColumn = Any[] - push!(currentColumn, header[column]) - for point in output_vector - push!(currentColumn, point[columnSymbols[column]]) + allColumns = [] + for column in 1:length(columnSymbols) + if typeof(output_vector[1][columnSymbols[column]]) == String + currentStringColumn::Vector{String} = [] + for point in output_vector + push!(currentStringColumn, point[columnSymbols[column]]) + end + push!(allColumns, currentStringColumn) + elseif typeof(output_vector[1][columnSymbols[column]]) <: Real + currentRealColumn::Vector{Real} = [] + for point in output_vector + push!(currentRealColumn, point[columnSymbols[column]]) + end + push!(allColumns, currentRealColumn) end - push!(allColumns, currentColumn) end # for # combine the columns in a data frame - dataFrame = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11]) + dataFrame = DataFrame(label=allColumns[1], driving_mode=allColumns[2], s=allColumns[3], v=allColumns[4], t=allColumns[5], a=allColumns[6], F_T=allColumns[7], F_R=allColumns[8], R_path=allColumns[9], R_traction=allColumns[10], R_wagons=allColumns[11]) end return dataFrame diff --git a/test/runtests.jl b/test/runtests.jl index 3019c23..7e8de06 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,24 +14,24 @@ settings = Dict() @testset "load data" begin println("testing load train data") - push!(trains, :freight => @time Train("test/data/trains/freight.yaml")) - push!(trains, :local => @time Train("test/data/trains/local.yaml")) - push!(trains, :longdistance => @time Train("test/data/trains/longdistance.yaml")) + push!(trains, :freight => @time Train("data/trains/freight.yaml")) + push!(trains, :local => @time Train("data/trains/local.yaml")) + push!(trains, :longdistance => @time Train("data/trains/longdistance.yaml")) println("testing load path data") - push!(paths, :const => @time Path("test/data/paths/const.yaml")) - push!(paths, :slope => @time Path("test/data/paths/slope.yaml")) - push!(paths, :speed => @time Path("test/data/paths/speed.yaml")) - push!(paths, :realworld => @time Path("test/data/paths/realworld.yaml")) + push!(paths, :const => @time Path("data/paths/const.yaml")) + push!(paths, :slope => @time Path("data/paths/slope.yaml")) + push!(paths, :speed => @time Path("data/paths/speed.yaml")) + push!(paths, :realworld => @time Path("data/paths/realworld.yaml")) println("testing load settings data") push!(settings, "default" => @time Settings()) - push!(settings, "poi" => @time Settings("test/data/settings/points_of_interest.yaml")) - push!(settings, "drivingcourse" => @time Settings("test/data/settings/driving_course.yaml")) - push!(settings, "strip" => @time Settings("test/data/settings/strip.yaml")) - push!(settings, "time" => @time Settings("test/data/settings/time.yaml")) - push!(settings, "timestrip" => @time Settings("test/data/settings/time_strip.yaml")) - push!(settings, "velocity" => @time Settings("test/data/settings/velocity.yaml")) + push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml")) + push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml")) + push!(settings, "strip" => @time Settings("data/settings/strip.yaml")) + push!(settings, "time" => @time Settings("data/settings/time.yaml")) + push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml")) + push!(settings, "velocity" => @time Settings("data/settings/velocity.yaml")) @test typeof(first(paths)[2]) == Path @test typeof(first(settings)[2]) == Settings @@ -74,8 +74,7 @@ anticipated = Dict( for test in tests test_name = String(test[1][1]) * "_" * String(test[2][1]) println("testing $test_name") - @time result_dataFrame = trainrun(test[1][2], test[2][2]) - result = result_dataFrame[!, 1][2] + @time result = trainrun(test[1][2], test[2][2])[end, :t] expected = anticipated[:default][Symbol(test_name)] # compare result to test data set @test isapprox(result, expected, rtol=0.01) From fab1ad017ab12cc3d82021ecb775f2a7e65ff107 Mon Sep 17 00:00:00 2001 From: Martin Scheidt Date: Fri, 3 Jun 2022 17:24:16 +0200 Subject: [PATCH 13/16] refactored functions, removed characteristics.jl, and unified naming in constructors.jl --- CHANGELOG.md | 16 +- src/TrainRuns.jl | 1 - src/behavior.jl | 352 +++++++++++++++++++---------------------- src/calc.jl | 195 ++++++++++++++++++++++- src/characteristics.jl | 170 -------------------- src/constructors.jl | 54 +++---- 6 files changed, 395 insertions(+), 393 deletions(-) delete mode 100644 src/characteristics.jl diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ccca20..64524be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,10 +23,18 @@ Categories: Added, Changed, Deprecated, Removed, Fixed, and Security. * renamed Validate.jl into types.jl * renamed TrainRunCalc.jl into calc.jl * moved trainrun function from calc.jl to TrainRun.jl -* moved createDataPoint() from behavior.jl to types.jl -* moved createBehaviorSection() from behavior.jl to types.jl -* moved createMovingSection() from characteristics.jl to types.jl -* moved createCharacteristicSection() from characteristics.jl to types.jl +* moved createDataPoint() from behavior.jl to constructors.jl +* moved createBehaviorSection() from behavior.jl to constructors.jl +* moved createMovingSection() from characteristics.jl to constructors.jl +* moved createCharacteristicSection() from characteristics.jl to constructors.jl +* removed characteristics.jl and moved all functions inside to behavior.jl +* moved calculateTractiveEffort() from behavior.jl to calc.jl +* moved calculatePathResistance() from behavior.jl to calc.jl +* moved calculateForces!() from behavior.jl to calc.jl +* moved moveAStep() from behavior.jl to calc.jl +* moved getCurrentSpeedLimit() from behavior.jl to calc.jl +* moved getNextPointOfInterest() from behavior.jl to calc.jl +* moved determineCharacteristics() from behavior.jl to calc.jl * changed title of include files from upper case to lower case * changed seperation of submodules into a single module with file include * updated test files to railtoolkit/schema (2022.05) diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl index d6de6ad..1972ef6 100644 --- a/src/TrainRuns.jl +++ b/src/TrainRuns.jl @@ -27,7 +27,6 @@ include("types.jl") include("constructors.jl") include("formulary.jl") include("calc.jl") -include("characteristics.jl") include("behavior.jl") include("output.jl") diff --git a/src/behavior.jl b/src/behavior.jl index 7ddae8c..a4f5667 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -5,188 +5,6 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -""" - calculateTractiveEffort(v, tractiveEffortVelocityPairs) - -Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`. - -... -# Arguments -- `v::AbstractFloat`: the current velocity in m/s. -- `tractiveEffortVelocityPairs::Array{}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. -... - -# Examples -```julia-repl -julia> calculateTractiveEffort(20.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) -100000 - -julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) -80000 -``` -""" -function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{}) - for row in 1:length(tractiveEffortVelocityPairs) - nextPair = tractiveEffortVelocityPairs[row] - if nextPair[1] == v - return nextPair[2] - elseif nextPair[1] > v - # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1) - previousPair = tractiveEffortVelocityPairs[row-1] - F_T_interpolation = (v-previousPair[1]) * (nextPair[2]-previousPair[2]) / (nextPair[1]-previousPair[1]) + previousPair[2] - return F_T_interpolation - end #if - end #for - # if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used - # TODO: also an extrapolation could be used - return tractiveEffortVelocityPairs[end][2] -end #function calculateTractiveEffort - -""" -calculate and return the path resistance dependend on the trains position and mass model -""" -function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train) - - if massModel == :mass_point - pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) - elseif massModel == :homogeneous_strip - pathResistance = 0.0 - s_rear = s - train.length # position of the rear of the train - while csId > 0 && s_rear < CSs[csId][:s_exit] - pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) - csId = csId-1 - if csId == 0 - # TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used - return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * calcForceFromCoefficient(CSs[1][:r_path], train.m_train_full) - end #if - end #while - end #if - - return pathResistance -end #function calculatePathResistance - -""" -calculate and return tractive and resisting forces for a data point -""" -function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) - # calculate resisting forces - dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) - dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) - dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] - dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train) - dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] - - # calculate tractive effort - if bsType == "braking" || bsType == "coasting" - dataPoint[:F_T] = 0.0 - elseif bsType == "cruising" - dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)) - else # bsType == "accelerating" || bsType == "diminishing" || 'default' - dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train.tractiveEffort) - end - - return dataPoint -end #function calculateForces! - - -""" -TODO -""" -function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer) - # stepSize is the currentStepSize depending on the accessing function - # TODO: csId is only for error messages. Should it be removed? - #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# - - # create the next data point - newPoint = createDataPoint() - newPoint[:i] = previousPoint[:i]+1 # identifier - - # calculate s, t, v, E - if stepVariable == :distance # distance step method - newPoint[:Δs] = stepSize # step size (in m) - if previousPoint[:a] == 0.0 - if previousPoint[:v] == 0.0 - error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") - end - newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) - newPoint[:Δv] = 0.0 # step size (in m/s) - else - # check if the parts of the following square roots will be <0.0 in the functions calc_Δt_with_Δs and calc_Δv_with_Δs - squareRootPartIsNegative = (previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a] < 0.0 || previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a] < 0.0 - if previousPoint[:a] < 0.0 && squareRootPartIsNegative - error("ERROR: The train stops during the accelerating section in CS",csId," because the tractive effort is lower than the resistant forces.", - " Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,", - " F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.") - end - newPoint[:Δt] = calc_Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s) - newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) - end - - elseif stepVariable == :time # time step method - newPoint[:Δt] = stepSize # step size (in s) - newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) - newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) - - elseif stepVariable == :velocity # velocity step method - if previousPoint[:a] == 0.0 - if previousPoint[:v] == 0.0 - error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") - end - newPoint[:Δs] = stepSize # step size (in m) - # TODO what is the best default step size for constant v? define Δs or Δt? - newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) - newPoint[:Δv] = 0.0 # step size (in m/s) - else - newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s) - newPoint[:Δs] = calc_Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m) - newPoint[:Δt] = calc_Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s) - end - end #if - - newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m) - newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s) - newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s) - newPoint[:ΔW] = calc_ΔW(previousPoint[:F_T], newPoint[:Δs]) # mechanical work in this step (in Ws) - newPoint[:W] = previousPoint[:W] + newPoint[:ΔW] # mechanical work (in Ws) - newPoint[:ΔE] = calc_ΔE(newPoint[:ΔW]) # energy consumption in this step (in Ws) - newPoint[:E] = previousPoint[:E] + newPoint[:ΔE] # energy consumption (in Ws) - - - return newPoint -end #function moveAStep - -""" -# if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept -""" -function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real) - v_limit = CSs[csWithTrainHeadId][:v_limit] - s_exit = CSs[csWithTrainHeadId][:s_exit] - if csWithTrainHeadId > 1 && s -trainLength < CSs[csWithTrainHeadId][:s_entry] - formerCsId = csWithTrainHeadId-1 - while formerCsId > 0 && s -trainLength < CSs[formerCsId][:s_exit] - if CSs[formerCsId][:v_limit] < v_limit # TODO: is the position of the train's rear < movingSection[:s_entry], v_limit of the first CS is used - v_limit = CSs[formerCsId][:v_limit] - s_exit = CSs[formerCsId][:s_exit] - end - formerCsId = formerCsId -1 - end - end - currentSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength) - return currentSpeedLimit -end #function getCurrentSpeedLimit - -""" -? -""" -function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real) - for s_POI in pointsOfInterest - if s_POI[1] > s - return s_POI - end - end - error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.") -end #function getNextPointOfInterest - ## This function calculates the data points of the breakFree section. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for breakFree if needed. # Info: currently the values of the breakFree section will be calculated like in the accelerating section @@ -196,7 +14,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: trainIsHalting = drivingCourse[end][:v] == 0.0 if trainIsHalting && !endOfCSReached - BS = createBehaviorSection("breakFree", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("breakFree", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] # traction effort and resisting forces (in N) @@ -318,7 +136,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla # use the conditions for the accelerating section if !targetSpeedReached && !endOfCSReached && tractionSurplus && !brakingStartReached - BS = createBehaviorSection("accelerating", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("accelerating", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) @@ -568,7 +386,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: if speedIsValid && !brakingStartReached && !tractionDeficit && !targetPositionReached # 03/04 old: if drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] && !brakingStartReached && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] - BS = createBehaviorSection(cruisingType, drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection(cruisingType, drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] # TODO: necessary? s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry]) @@ -815,7 +633,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag # use the conditions for the diminishing section if tractionDeficit && !targetSpeedReached && !endOfCSReached - BS = createBehaviorSection("diminishing", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("diminishing", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached @@ -995,7 +813,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # use the conditions for the coasting section if !targetSpeedReached && !endOfCSReached - BS = createBehaviorSection("coasting", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("coasting", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] while !targetSpeedReached && !endOfCSReached && !brakingStartReached @@ -1152,7 +970,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D # use the conditions for the braking section if !targetSpeedReached && !endOfCSReached - BS = createBehaviorSection("braking", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("braking", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] while !targetSpeedReached && !endOfCSReached @@ -1172,7 +990,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D if settings.stepVariable == :distance && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 # create empty data point and set it for the values of s_exit and v_exit - push!(drivingCourse, createDataPoint()) + push!(drivingCourse, DataPoint()) drivingCourse[end][:i] = drivingCourse[end-1][:i]+1 drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) @@ -1304,7 +1122,7 @@ end #function addBrakingSection! # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}) if drivingCourse[end][:v] == 0.0 - BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) + BS = BehaviorSection("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) @@ -1357,3 +1175,157 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws) currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws) end #function recalculateLastBrakingPoint + +## define the intersection velocities between the characterisitc sections to secure braking behavior +function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) + # this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end + CSs = movingSection[:characteristicSections] + + csId = length(CSs) + followingCSv_entry = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s + while csId >= 1 + CS = CSs[csId] + + CS[:v_exit] = min(CS[:v_limit], followingCSv_entry) + + v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length]) + + CS[:v_entry] = min(CS[:v_limit], v_entryMax) + CS[:v_peak] = CS[:v_entry] + + + # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit + CS[:behaviorSections] = Dict() + CS[:E] = 0.0 + CS[:t] = 0.0 + + followingCSv_entry = CS[:v_entry] + csId = csId - 1 + end #while + return movingSection +end #function secureBrakingBehavior! + +## define the intersection velocities between the characterisitc sections to secure accelerating behavior +function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Train) + # this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards + CSs = movingSection[:characteristicSections] + + CSs[1][:v_entry] = 0.0 # the entry velocity of the first characteristic section is 0.0 m/s + startingPoint = DataPoint() + startingPoint[:i] = 1 + + previousCSv_exit = CSs[1][:v_entry] + for CS in CSs + CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) + startingPoint[:s] = CS[:s_entry] + startingPoint[:v] = CS[:v_entry] + calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N) + acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points + + if CS[:v_entry] < CS[:v_peak] + # conditions for entering the accelerating phase + stateFlags = Dict(:endOfCSReached => false, + :brakingStartReached => false, + :tractionDeficit => false, + :resistingForceNegative => false, + :previousSpeedLimitReached => false, + :speedLimitReached => false, + :error => false, + :usedForDefiningCharacteristics => true) # because usedForDefiningCharacteristics == true the braking distance will be ignored during securing the accelerating phase + v_peak = CS[:v_entry] + (CS, acceleratingCourse, stateFlags) = addBreakFreeSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) + while !stateFlags[:speedLimitReached] && !stateFlags[:endOfCSReached] + if !stateFlags[:tractionDeficit] + if !stateFlags[:previousSpeedLimitReached] + (CS, acceleratingCourse, stateFlags) = addAcceleratingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function changes the acceleratingCourse + + elseif stateFlags[:previousSpeedLimitReached] + (CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit + end + else + if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train.length + break + else + (CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort + end + end + v_peak = max(v_peak, acceleratingCourse[end][:v]) + end + +# CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v]) + CS[:v_peak] = v_peak + CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v]) + else #CS[:v_entry] == CS[:v_peak] + # v_exit stays the same + end #if + + previousCSv_exit = CS[:v_exit] + + # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit + CS[:behaviorSections] = Dict() + CS[:E] = 0.0 + CS[:t] = 0.0 + end #for + + return movingSection +end #function secureAcceleratingBehavior! + + +#= +## define the intersection velocities between the characterisitc sections to secure cruising behavior +function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train) + # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak + CSs = movingSection[:characteristicSections] + + startingPoint = DataPoint() + startingPoint[:i] = 1 + + previousCSv_exit = CSs[1][:v_entry] + + for CS in CSs + # conditions for entering the cruising phase + stateFlags = Dict(:endOfCSReached => false, + :brakingStartReached => false, + :tractionDeficit => false, + :resistingForceNegative => false, + :previousSpeedLimitReached => false, + :speedLimitReached => false, + :error => false, + :usedForDefiningCharacteristics => true) + + CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) + + startingPoint[:s] = CS[:s_entry] + startingPoint[:v] = CS[:v_peak] + cruisingCourse::Vector{Dict} = [startingPoint] # List of data points + + while !stateFlags[:endOfCSReached] #&& s_cruising > 0.0 + if !stateFlags[:tractionDeficit] + s_cruising = CS[:s_exit] - cruisingCourse[end][:s] + if !stateFlags[:resistingForceNegative]# cruisingCourse[end][:F_R] >= 0 + (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") # this function changes the cruisingCourse + else + (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking") + end + else + if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length + break + else + (CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort + end + end + end + + CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v]) + + previousCSv_exit = CS[:v_exit] + + # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit + CS[:behaviorSections] = Dict() + CS[:E] = 0.0 + CS[:t] = 0.0 + end #for + + return movingSection +end #function secureCruisingBehavior! +=# diff --git a/src/calc.jl b/src/calc.jl index e9ed5ef..45649ea 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -15,7 +15,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") end - startingPoint=createDataPoint() + startingPoint=DataPoint() startingPoint[:i]=1 startingPoint[:s]=CSs[1][:s_entry] calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N) @@ -123,3 +123,196 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t return (movingSection, drivingCourse) end #function calculateMinimumRunningTime + +""" + calculateTractiveEffort(v, tractiveEffortVelocityPairs) + +Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`. + +... +# Arguments +- `v::AbstractFloat`: the current velocity in m/s. +- `tractiveEffortVelocityPairs::Array{}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. +... + +# Examples +```julia-repl +julia> calculateTractiveEffort(20.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) +100000 + +julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) +80000 +``` +""" +function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{}) + for row in 1:length(tractiveEffortVelocityPairs) + nextPair = tractiveEffortVelocityPairs[row] + if nextPair[1] == v + return nextPair[2] + elseif nextPair[1] > v + # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1) + previousPair = tractiveEffortVelocityPairs[row-1] + F_T_interpolation = (v-previousPair[1]) * (nextPair[2]-previousPair[2]) / (nextPair[1]-previousPair[1]) + previousPair[2] + return F_T_interpolation + end #if + end #for + # if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used + # TODO: also an extrapolation could be used + return tractiveEffortVelocityPairs[end][2] +end #function calculateTractiveEffort + +""" +calculate and return the path resistance dependend on the trains position and mass model +""" +function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train) + + if massModel == :mass_point + pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) + elseif massModel == :homogeneous_strip + pathResistance = 0.0 + s_rear = s - train.length # position of the rear of the train + while csId > 0 && s_rear < CSs[csId][:s_exit] + pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) + csId = csId-1 + if csId == 0 + # TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used + return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * calcForceFromCoefficient(CSs[1][:r_path], train.m_train_full) + end #if + end #while + end #if + + return pathResistance +end #function calculatePathResistance + +""" +calculate and return tractive and resisting forces for a data point +""" +function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) + # calculate resisting forces + dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) + dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) + dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] + dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train) + dataPoint[:F_R] = dataPoint[:R_train] + dataPoint[:R_path] + + # calculate tractive effort + if bsType == "braking" || bsType == "coasting" + dataPoint[:F_T] = 0.0 + elseif bsType == "cruising" + dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)) + else # bsType == "accelerating" || bsType == "diminishing" || 'default' + dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train.tractiveEffort) + end + + return dataPoint +end #function calculateForces! + + +""" +TODO +""" +function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer) + # stepSize is the currentStepSize depending on the accessing function + # TODO: csId is only for error messages. Should it be removed? + #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# + + # create the next data point + newPoint = DataPoint() + newPoint[:i] = previousPoint[:i]+1 # identifier + + # calculate s, t, v, E + if stepVariable == :distance # distance step method + newPoint[:Δs] = stepSize # step size (in m) + if previousPoint[:a] == 0.0 + if previousPoint[:v] == 0.0 + error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") + end + newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) + newPoint[:Δv] = 0.0 # step size (in m/s) + else + # check if the parts of the following square roots will be <0.0 in the functions calc_Δt_with_Δs and calc_Δv_with_Δs + squareRootPartIsNegative = (previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a] < 0.0 || previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a] < 0.0 + if previousPoint[:a] < 0.0 && squareRootPartIsNegative + error("ERROR: The train stops during the accelerating section in CS",csId," because the tractive effort is lower than the resistant forces.", + " Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,", + " F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.") + end + newPoint[:Δt] = calc_Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s) + newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) + end + + elseif stepVariable == :time # time step method + newPoint[:Δt] = stepSize # step size (in s) + newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) + + elseif stepVariable == :velocity # velocity step method + if previousPoint[:a] == 0.0 + if previousPoint[:v] == 0.0 + error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") + end + newPoint[:Δs] = stepSize # step size (in m) + # TODO what is the best default step size for constant v? define Δs or Δt? + newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) + newPoint[:Δv] = 0.0 # step size (in m/s) + else + newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s) + newPoint[:Δs] = calc_Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δt] = calc_Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s) + end + end #if + + newPoint[:s] = previousPoint[:s] + newPoint[:Δs] # position (in m) + newPoint[:t] = previousPoint[:t] + newPoint[:Δt] # point in time (in s) + newPoint[:v] = previousPoint[:v] + newPoint[:Δv] # velocity (in m/s) + newPoint[:ΔW] = calc_ΔW(previousPoint[:F_T], newPoint[:Δs]) # mechanical work in this step (in Ws) + newPoint[:W] = previousPoint[:W] + newPoint[:ΔW] # mechanical work (in Ws) + newPoint[:ΔE] = calc_ΔE(newPoint[:ΔW]) # energy consumption in this step (in Ws) + newPoint[:E] = previousPoint[:E] + newPoint[:ΔE] # energy consumption (in Ws) + + + return newPoint +end #function moveAStep + +""" +# if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept +""" +function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real) + v_limit = CSs[csWithTrainHeadId][:v_limit] + s_exit = CSs[csWithTrainHeadId][:s_exit] + if csWithTrainHeadId > 1 && s -trainLength < CSs[csWithTrainHeadId][:s_entry] + formerCsId = csWithTrainHeadId-1 + while formerCsId > 0 && s -trainLength < CSs[formerCsId][:s_exit] + if CSs[formerCsId][:v_limit] < v_limit # TODO: is the position of the train's rear < movingSection[:s_entry], v_limit of the first CS is used + v_limit = CSs[formerCsId][:v_limit] + s_exit = CSs[formerCsId][:s_exit] + end + formerCsId = formerCsId -1 + end + end + currentSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength) + return currentSpeedLimit +end #function getCurrentSpeedLimit + +""" +? +""" +function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real) + for s_POI in pointsOfInterest + if s_POI[1] > s + return s_POI + end + end + error("ERROR in getNextPointOfInterest: There is no POI higher than s=",s," m.") +end #function getNextPointOfInterest + + +## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior +function determineCharacteristics(path::Path, train::Train, settings::Settings) + movingSection = MovingSection(path, train.v_limit, train.length) + movingSection = secureBrakingBehavior!(movingSection, train.a_braking) + movingSection = secureAcceleratingBehavior!(movingSection, settings, train) + #movingSection = secureCruisingBehavior!(movingSection, settings, train) + + return movingSection +end #function determineCharacteristics diff --git a/src/characteristics.jl b/src/characteristics.jl deleted file mode 100644 index 7abcd10..0000000 --- a/src/characteristics.jl +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior -function determineCharacteristics(path::Path, train::Train, settings::Settings) - movingSection = createMovingSection(path, train.v_limit, train.length) - movingSection = secureBrakingBehavior!(movingSection, train.a_braking) - movingSection = secureAcceleratingBehavior!(movingSection, settings, train) - #movingSection = secureCruisingBehavior!(movingSection, settings, train) - - return movingSection -end #function determineCharacteristics - -## define the intersection velocities between the characterisitc sections to secure braking behavior -function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) - # this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end - CSs = movingSection[:characteristicSections] - - csId = length(CSs) - followingCSv_entry = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s - while csId >= 1 - CS = CSs[csId] - - CS[:v_exit] = min(CS[:v_limit], followingCSv_entry) - - v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length]) - - CS[:v_entry] = min(CS[:v_limit], v_entryMax) - CS[:v_peak] = CS[:v_entry] - - - # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit - CS[:behaviorSections] = Dict() - CS[:E] = 0.0 - CS[:t] = 0.0 - - followingCSv_entry = CS[:v_entry] - csId = csId - 1 - end #while - return movingSection -end #function secureBrakingBehavior! - -## define the intersection velocities between the characterisitc sections to secure accelerating behavior -function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Train) - # this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards - CSs = movingSection[:characteristicSections] - - CSs[1][:v_entry] = 0.0 # the entry velocity of the first characteristic section is 0.0 m/s - startingPoint = createDataPoint() - startingPoint[:i] = 1 - - previousCSv_exit = CSs[1][:v_entry] - for CS in CSs - CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) - startingPoint[:s] = CS[:s_entry] - startingPoint[:v] = CS[:v_entry] - calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N) - acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points - - if CS[:v_entry] < CS[:v_peak] - # conditions for entering the accelerating phase - stateFlags = Dict(:endOfCSReached => false, - :brakingStartReached => false, - :tractionDeficit => false, - :resistingForceNegative => false, - :previousSpeedLimitReached => false, - :speedLimitReached => false, - :error => false, - :usedForDefiningCharacteristics => true) # because usedForDefiningCharacteristics == true the braking distance will be ignored during securing the accelerating phase - v_peak = CS[:v_entry] - (CS, acceleratingCourse, stateFlags) = addBreakFreeSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) - while !stateFlags[:speedLimitReached] && !stateFlags[:endOfCSReached] - if !stateFlags[:tractionDeficit] - if !stateFlags[:previousSpeedLimitReached] - (CS, acceleratingCourse, stateFlags) = addAcceleratingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function changes the acceleratingCourse - - elseif stateFlags[:previousSpeedLimitReached] - (CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit - end - else - if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train.length - break - else - (CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort - end - end - v_peak = max(v_peak, acceleratingCourse[end][:v]) - end - -# CS[:v_peak] = max(CS[:v_entry], acceleratingCourse[end][:v]) - CS[:v_peak] = v_peak - CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], acceleratingCourse[end][:v]) - else #CS[:v_entry] == CS[:v_peak] - # v_exit stays the same - end #if - - previousCSv_exit = CS[:v_exit] - - # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit - CS[:behaviorSections] = Dict() - CS[:E] = 0.0 - CS[:t] = 0.0 - end #for - - return movingSection -end #function secureAcceleratingBehavior! - - -#= -## define the intersection velocities between the characterisitc sections to secure cruising behavior -function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train) - # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak - CSs = movingSection[:characteristicSections] - - startingPoint = createDataPoint() - startingPoint[:i] = 1 - - previousCSv_exit = CSs[1][:v_entry] - - for CS in CSs - # conditions for entering the cruising phase - stateFlags = Dict(:endOfCSReached => false, - :brakingStartReached => false, - :tractionDeficit => false, - :resistingForceNegative => false, - :previousSpeedLimitReached => false, - :speedLimitReached => false, - :error => false, - :usedForDefiningCharacteristics => true) - - CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) - - startingPoint[:s] = CS[:s_entry] - startingPoint[:v] = CS[:v_peak] - cruisingCourse::Vector{Dict} = [startingPoint] # List of data points - - while !stateFlags[:endOfCSReached] #&& s_cruising > 0.0 - if !stateFlags[:tractionDeficit] - s_cruising = CS[:s_exit] - cruisingCourse[end][:s] - if !stateFlags[:resistingForceNegative]# cruisingCourse[end][:F_R] >= 0 - (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") # this function changes the cruisingCourse - else - (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking") - end - else - if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length - break - else - (CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort - end - end - end - - CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v]) - - previousCSv_exit = CS[:v_exit] - - # reset the characteristic section (CS), delete behavior sections (BS) that were used during the preperation for setting v_entry, v_peak and v_exit - CS[:behaviorSections] = Dict() - CS[:E] = 0.0 - CS[:t] = 0.0 - end #for - - return movingSection -end #function secureCruisingBehavior! -=# diff --git a/src/constructors.jl b/src/constructors.jl index ffa27c1..a68f956 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -614,7 +614,7 @@ function Train(file, type = :YAML) end #function Train() # outer constructor ## create a moving section containing characteristic sections -function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real) +function MovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real) # this function creates and returns a moving section dependent on the paths attributes s_entry = path.sections[1][:s_start] # first position (in m) @@ -631,12 +631,12 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp] if speedLimitIsDifferent || pathResistanceIsDifferent # 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] - push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path)) + push!(CSs, CharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path)) s_csStart = currentSection[:s_start] csId = csId+1 end #if end #for - push!(CSs, createCharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path)) + push!(CSs, CharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path)) movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore :length => pathLength, # total length (in m) @@ -647,10 +647,10 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real :characteristicSections => CSs) # list of containing characteristic sections return movingSection -end #function createMovingSection +end #function MovingSection ## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections. -function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path) +function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path) # Create and return a characteristic section dependent on the paths attributes characteristicSection= Dict(:id => id, # identifier :s_entry => s_entry, # first position (in m) @@ -690,15 +690,33 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest)) return characteristicSection -end #function createCharacteristicSection +end #function CharacteristicSection + +""" +BehaviorSection() TODO! +""" +function BehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) + BS= Dict( + :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "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 BehaviorSection """ a DataPoint is the smallest element of the driving course. One step of the step approach is between two data points """ -function createDataPoint() +function DataPoint() dataPoint = Dict( :i => 0, # identifier and counter variable of the driving course - :behavior => "", # type of behavior section the data point is part of - see createBehaviorSection() + :behavior => "", # type of behavior section the data point is part of - see BehaviorSection() # a data point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter :s => 0.0, # position (in m) :Δs => 0.0, # step size (in m) @@ -720,22 +738,4 @@ function createDataPoint() :label => "" # a label for importend points ) return dataPoint -end #function createDataPoint - -""" -BehaviorSection() TODO! -""" -function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) - BS= Dict( - :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "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 #function DataPoint From 10e877e9ec791e658c664241573091dba419f32d Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Fri, 3 Jun 2022 18:11:28 +0200 Subject: [PATCH 14/16] Fix handling and output of points of interest --- src/TrainRuns.jl | 2 +- src/constructors.jl | 44 ++++++++++++++++++++++++++------------------ src/output.jl | 30 +++++++++++------------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl index aeaa827..0c0e308 100644 --- a/src/TrainRuns.jl +++ b/src/TrainRuns.jl @@ -56,7 +56,7 @@ function trainrun(train::Train, path::Path, settings=Settings()::Settings) # settings.outputDetail == :verbose && println("The driving course for the shortest running time has been calculated.") # accumulate data and create an output dictionary - output = createOutput(settings, path, drivingCourse) + output = createOutput(settings, drivingCourse, movingSection[:pointsOfInterest]) return output end # function trainrun diff --git a/src/constructors.jl b/src/constructors.jl index 9e459dd..37a51fa 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -622,6 +622,19 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real s_exit = path.sections[end][:s_end] # last position (in m) pathLength = s_exit - s_entry # total length (in m) + ##TODO: use a tuple with naming + pointsOfInterest = Tuple[] + if !isempty(path.poi) + for POI in path.poi + s_poi = POI[:station] + if POI[:measure] == "rear" + s_poi += s_trainLength + end + push!(pointsOfInterest, (s_poi, POI[:label]) ) + end + sort!(pointsOfInterest, by = x -> x[1]) + end + CSs=Vector{Dict}() s_csStart=s_entry csId=1 @@ -631,26 +644,26 @@ function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp] if speedLimitIsDifferent || pathResistanceIsDifferent - # 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] - push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path)) + push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, pointsOfInterest)) s_csStart = currentSection[:s_start] csId = csId+1 end #if end #for - push!(CSs, createCharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path)) + push!(CSs, createCharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, pointsOfInterest)) movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore :length => pathLength, # total length (in m) :s_entry => s_entry, # first position (in m) :s_exit => s_exit, # last position (in m) :t => 0.0, # total running time (in s) - :characteristicSections => CSs) # list of containing characteristic sections + :characteristicSections => CSs, # list of containing characteristic sections + :pointsOfInterest => pointsOfInterest) # list of containing points of interest return movingSection end #function createMovingSection ## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections. -function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path) +function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, MS_poi::Vector{Tuple}) # Create and return a characteristic section dependent on the paths attributes characteristicSection= Dict(:id => id, # identifier :s_entry => s_entry, # first position (in m) @@ -670,22 +683,17 @@ function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, ##TODO: use a tuple with naming pointsOfInterest = Tuple[] - # pointsOfInterest = Real[] - if !isempty(path.poi) - for POI in path.poi - s_poi = POI[:station] - if POI[:measure] == "rear" - s_poi += s_trainLength - end - if s_entry < s_poi && s_poi < s_exit - push!(pointsOfInterest, (s_poi, POI[:label]) ) - # push!(pointsOfInterest, s_poi ) + if !isempty(MS_poi) + for POI in MS_poi + s_poi = POI[1] + if s_entry < s_poi && s_poi <= s_exit + push!(pointsOfInterest, (POI)) end end end - push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with - # push!(pointsOfInterest, s_exit) # s_exit has to be the last POI so that there will always be a POI to campare the current position with - + if isempty(pointsOfInterest) || pointsOfInterest[end][1] < s_exit + push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with + end merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest)) return characteristicSection diff --git a/src/output.jl b/src/output.jl index dca58ea..388ba38 100644 --- a/src/output.jl +++ b/src/output.jl @@ -5,34 +5,26 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -function createOutput(settings::Settings, path::Path, drivingCourse::Vector{Dict}) +function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfInterest::Vector{Tuple}) if settings.outputDetail == :running_time output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])] - elseif settings.outputDetail == :points_of_interest && !isempty(path.poi) - # add points of interest - - # output = Dict[] - # POI = 1 - # i = 1 - # while POI <= length(path.poi) && i <= drivingCourse[end][:i] - # if path.poi[POI][:station] == drivingCourse[i][:s] - # push!(output, drivingCourse[i]) - # POI = POI+1 - # end - # i = i+1 - # end - + elseif settings.outputDetail == :points_of_interest && !isempty(pointsOfInterest) # get only the driving course's data points with POI labels output = Dict[] - for point in drivingCourse - if point[:label] != "" - push!(output, point) + dataPoint = 1 + for POI in 1:length(pointsOfInterest) + while dataPoint <= length(drivingCourse) + if pointsOfInterest[POI][1] == drivingCourse[dataPoint][:s] + push!(output, drivingCourse[dataPoint]) + break + end + dataPoint += 1 end end else #if settings.outputDetail == :driving_course || (settings.outputDetail == :points_of_interest && !isempty(path.poi)) - output = drivingCourse + output = drivingCourse end if settings.outputFormat == :dataframe From 3911b33f219788b86df56deb839582ab12609c6c Mon Sep 17 00:00:00 2001 From: Martin Scheidt Date: Sun, 5 Jun 2022 15:30:48 +0200 Subject: [PATCH 15/16] removed unnecessary header line --- src/TrainRuns.jl | 1 - src/behavior.jl | 1 - src/calc.jl | 1 - src/constructors.jl | 1 - src/formulary.jl | 1 - src/output.jl | 1 - src/types.jl | 1 - 7 files changed, 7 deletions(-) diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl index 10c31e2..f5a9efa 100644 --- a/src/TrainRuns.jl +++ b/src/TrainRuns.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Max Kannenberg, Martin Scheidt" # __copyright__ = "2020-2022" # __license__ = "ISC" diff --git a/src/behavior.jl b/src/behavior.jl index 8071b4b..97f238e 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Max Kannenberg" # __copyright__ = "2020-2022" # __license__ = "ISC" diff --git a/src/calc.jl b/src/calc.jl index 024adb6..15e8f1d 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Max Kannenberg" # __copyright__ = "2020-2022" # __license__ = "ISC" diff --git a/src/constructors.jl b/src/constructors.jl index a31122d..db85eba 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Martin Scheidt, Max Kannenberg" # __copyright__ = "2022" # __license__ = "ISC" diff --git a/src/formulary.jl b/src/formulary.jl index a6961b6..fe0c5d2 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Max Kannenberg" # __copyright__ = "2022" # __license__ = "ISC" diff --git a/src/output.jl b/src/output.jl index 388ba38..cf63e93 100644 --- a/src/output.jl +++ b/src/output.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Max Kannenberg" # __copyright__ = "2020-2022" # __license__ = "ISC" diff --git a/src/types.jl b/src/types.jl index 5ffee12..f74a9cc 100644 --- a/src/types.jl +++ b/src/types.jl @@ -1,6 +1,5 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 # __author__ = "Martin Scheidt, Max Kannenberg" # __copyright__ = "2022" # __license__ = "ISC" From 8c17d0b6aea063addb2534ed2b4f8c01eb21ec9b Mon Sep 17 00:00:00 2001 From: Martin Scheidt Date: Sun, 5 Jun 2022 15:41:28 +0200 Subject: [PATCH 16/16] refactored function names with calc* --- src/behavior.jl | 40 ++++++++++++++-------------- src/calc.jl | 38 +++++++++++++-------------- src/formulary.jl | 68 ++++++++++++++++++++++++------------------------ 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/behavior.jl b/src/behavior.jl index 97f238e..eadaa8c 100644 --- a/src/behavior.jl +++ b/src/behavior.jl @@ -56,7 +56,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] s_braking = 0.0 else - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # reset state flags @@ -82,7 +82,7 @@ function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s]) @@ -120,7 +120,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for the accelerating section @@ -147,7 +147,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached @@ -158,7 +158,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla end # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) + drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) @@ -169,7 +169,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] speedLimitReached = drivingCourse[end][:v] > CS[:v_limit] @@ -369,11 +369,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for cruising section - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + #s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] @@ -605,7 +605,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # set state flags stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit] if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit] stateFlags[:tractionDeficit] = tractionDeficit @@ -627,14 +627,14 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end # conditions for diminishing section targetSpeedReached = drivingCourse[end][:v] <= 0.0 endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit] - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + #s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the diminishing section @@ -651,7 +651,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag while tractionDeficit && !brakingStartReached && !pointOfInterestReached && !targetSpeedReached # 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest[1] && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) + drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) @@ -662,7 +662,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] @@ -816,7 +816,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the coasting section @@ -836,7 +836,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) + drivingCourse[end][:a] = acceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) @@ -844,7 +844,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: push!(BS[:dataPoints], drivingCourse[end][:i]) # conditions for the next while cycle - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak] @@ -997,7 +997,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D # acceleration (in m/s^2): drivingCourse[end][:a] = train.a_braking - # TODO or: drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s]) + # TODO or: drivingCourse[end][:a] = brakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s]) if settings.stepVariable == :distance && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 # create empty data point and set it for the values of s_exit and v_exit @@ -1175,12 +1175,12 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) currentPoint[:Δv] = currentPoint[:v] - previousPoint[:v] # step size (in m/s) # calculate other values - previousPoint[:a] = calcBrakingAcceleration(previousPoint[:v], currentPoint[:v], currentPoint[:Δs]) + previousPoint[:a] = brakingAcceleration(previousPoint[:v], currentPoint[:v], currentPoint[:Δs]) # # TODO: just for testing # if previousPoint[:a]=0.0 # println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",previousPoint[:a] ," > ",train.a_braking) # end - currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s) + currentPoint[:Δt] = Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s) currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s) end #function recalculateLastBrakingPoint @@ -1196,7 +1196,7 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real, approxLeve CS[:v_exit] = min(CS[:v_limit], followingCSv_entry) - v_entryMax = calcBrakingStartVelocity(CS[:v_exit], a_braking, CS[:length], approxLevel) + v_entryMax = brakingStartVelocity(CS[:v_exit], a_braking, CS[:length], approxLevel) CS[:v_entry] = min(CS[:v_limit], v_entryMax) CS[:v_peak] = CS[:v_entry] diff --git a/src/calc.jl b/src/calc.jl index 15e8f1d..b37d8c1 100644 --- a/src/calc.jl +++ b/src/calc.jl @@ -31,7 +31,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end # determine the different flags for switching between the states for creatinge moving phases - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N) previousSpeedLimitReached = false @@ -61,14 +61,14 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t if settings.stepVariable == :distance s_cruising = settings.stepSize elseif settings.stepVariable == time - s_cruising = calc_Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v]) + s_cruising = Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v]) elseif settings.stepVariable == velocity s_cruising = train.length/(10.0) # TODO which step size should be used? end (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 @@ -78,7 +78,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, t end elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) + s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 # TODO: define a minimum cruising length? @@ -172,16 +172,16 @@ calculate and return the path resistance dependend on the trains position and ma function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train) if massModel == :mass_point - pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) + pathResistance = forceFromCoefficient(CSs[csId][:r_path], train.m_train_full) elseif massModel == :homogeneous_strip pathResistance = 0.0 s_rear = s - train.length # position of the rear of the train while csId > 0 && s_rear < CSs[csId][:s_exit] - pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) + pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * forceFromCoefficient(CSs[csId][:r_path], train.m_train_full) csId = csId-1 if csId == 0 # TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used - return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * calcForceFromCoefficient(CSs[1][:r_path], train.m_train_full) + return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * forceFromCoefficient(CSs[1][:r_path], train.m_train_full) end #if end #while end #if @@ -195,11 +195,11 @@ calculate and return tractive and resisting forces for a data point """ function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) # calculate resisting forces - dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) + dataPoint[:R_traction] = tractionUnitResistance(dataPoint[:v], train) if train.transportType == :freight - dataPoint[:R_wagons] = calcFreightWagonsResistance(dataPoint[:v], train) + dataPoint[:R_wagons] = freightWagonsResistance(dataPoint[:v], train) elseif train.transportType == :passenger - dataPoint[:R_wagons] = calcPassengerWagonsResistance(dataPoint[:v], train) + dataPoint[:R_wagons] = passengerWagonsResistance(dataPoint[:v], train) end dataPoint[:R_train] = dataPoint[:R_traction] + dataPoint[:R_wagons] dataPoint[:R_path] = calculatePathResistance(CSs, csId, dataPoint[:s], massModel, train) @@ -237,24 +237,24 @@ function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, cs if previousPoint[:v] == 0.0 error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") end - newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) + newPoint[:Δt] = Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) newPoint[:Δv] = 0.0 # step size (in m/s) else - # check if the parts of the following square roots will be <0.0 in the functions calc_Δt_with_Δs and calc_Δv_with_Δs + # check if the parts of the following square roots will be <0.0 in the functions Δt_with_Δs and Δv_with_Δs squareRootPartIsNegative = (previousPoint[:v]/previousPoint[:a])^2+2*newPoint[:Δs]/previousPoint[:a] < 0.0 || previousPoint[:v]^2+2*newPoint[:Δs]*previousPoint[:a] < 0.0 if previousPoint[:a] < 0.0 && squareRootPartIsNegative error("ERROR: The train stops during the accelerating section in CS",csId," because the tractive effort is lower than the resistant forces.", " Before the stop the last point has the values s=",previousPoint[:s]," m, v=",previousPoint[:v]," m/s, a=",previousPoint[:a]," m/s^2,", " F_T=",previousPoint[:F_T]," N, R_traction=",previousPoint[:R_traction]," N, R_wagons=",previousPoint[:R_wagons]," N, R_path=",previousPoint[:R_path]," N.") end - newPoint[:Δt] = calc_Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s) - newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) + newPoint[:Δt] = Δt_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in s) + newPoint[:Δv] = Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) end elseif stepVariable == :time # time step method newPoint[:Δt] = stepSize # step size (in s) - newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) - newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) + newPoint[:Δs] = Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δv] = Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) elseif stepVariable == :velocity # velocity step method if previousPoint[:a] == 0.0 @@ -263,12 +263,12 @@ function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, cs end newPoint[:Δs] = stepSize # step size (in m) # TODO what is the best default step size for constant v? define Δs or Δt? - newPoint[:Δt] = calc_Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) + newPoint[:Δt] = Δt_with_constant_v(newPoint[:Δs], previousPoint[:v]) # step size (in s) newPoint[:Δv] = 0.0 # step size (in m/s) else newPoint[:Δv] = stepSize * sign(previousPoint[:a]) # step size (in m/s) - newPoint[:Δs] = calc_Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m) - newPoint[:Δt] = calc_Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s) + newPoint[:Δs] = Δs_with_Δv(newPoint[:Δv], previousPoint[:a], previousPoint[:v]) # step size (in m) + newPoint[:Δt] = Δt_with_Δv(newPoint[:Δv], previousPoint[:a]) # step size (in s) end end #if diff --git a/src/formulary.jl b/src/formulary.jl index fe0c5d2..fffa909 100644 --- a/src/formulary.jl +++ b/src/formulary.jl @@ -34,7 +34,7 @@ v00 = 100/3.6 # velocity factor (in m/s) #TODO: replace the ? ? ? """ - calcTractionUnitResistance(v, train) + tractionUnitResistance(v, train) Calculate the vehicle resistance for the traction unit of the `train` dependend on the velocity `v`. @@ -46,11 +46,11 @@ Calculate the vehicle resistance for the traction unit of the `train` dependend # Examples ```julia-repl -julia> calcTractionUnitResistance(30.0, ? ? ?) +julia> tractionUnitResistance(30.0, ? ? ?) ? ? ? ``` """ -function calcTractionUnitResistance(v::AbstractFloat, train::Train) +function tractionUnitResistance(v::AbstractFloat, train::Train) # equation is based on [Wende:2003, page 151] f_Rtd0 = train.f_Rtd0 # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtc0 = train.f_Rtc0 # coefficient for basic resistance due to the traction units carring axles (in ‰) @@ -60,16 +60,16 @@ function calcTractionUnitResistance(v::AbstractFloat, train::Train) F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + f_Rt2/1000 * (m_td+m_tc) * g * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ - # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + calcForceFromCoefficient(f_Rt2, m_td+m_tc) * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) + # TODO: use forceFromCoefficient? F_R_tractionUnit = forceFromCoefficient(f_Rtd0, m_td) + forceFromCoefficient(f_Rtc0, m_tc) + forceFromCoefficient(f_Rt2, m_td+m_tc) * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) return F_R_tractionUnit #TODO: same variable name like in the rest of TrainRuns? return R_traction -end #function calcTractionUnitResistance +end #function tractionUnitResistance """ TODO calculate and return the freight wagons' vehicle resistance dependend on the velocity """ -function calcFreightWagonsResistance(v::AbstractFloat, train::Train) +function freightWagonsResistance(v::AbstractFloat, train::Train) # equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰) @@ -77,7 +77,7 @@ function calcFreightWagonsResistance(v::AbstractFloat, train::Train) F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw2/1000 * (v /v00)^2) # vehicle resistance of freight wagons (in N) with Strahl # /1000 because of the unit ‰ -# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ... +# TODO: use forceFromCoefficient? F_R_wagons = forceFromCoefficient(f_Rw0, m_w) + ... return F_R_wagons end #function calcWagonsResistance @@ -85,7 +85,7 @@ end #function calcWagonsResistance TODO calculate and return the passenger wagons' vehicle resistance dependend on the velocity """ -function calcPassengerWagonsResistance(v::AbstractFloat, train::Train) +function passengerWagonsResistance(v::AbstractFloat, train::Train) # equation is based on the equations of Sauthoff [Wende:2003, page 153] f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) f_Rw1 = train.f_Rw1 # coefficient for the consists resistance to rolling (in ‰) @@ -94,11 +94,11 @@ function calcPassengerWagonsResistance(v::AbstractFloat, train::Train) F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of passenger wagons (in N) with Sauthoff # /1000 because of the unit ‰ -# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + ... +# TODO: use forceFromCoefficient? F_R_wagons = forceFromCoefficient(f_Rw0, m_w) + ... return F_R_wagons end #function calcWagonsResistance -function calcForceFromCoefficient(f_R::Real, m::Real) +function forceFromCoefficient(f_R::Real, m::Real) # equation is based on [Wende:2003, page 8] # f_R: specific resistance (in ‰) @@ -106,9 +106,9 @@ function calcForceFromCoefficient(f_R::Real, m::Real) F_R = f_R /1000 *m *g # Resisting Force (in N) # /1000 because of the unit ‰ return F_R -end #function calcForceFromCoefficient +end #function forceFromCoefficient -function calcAcceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real) +function acceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real) # equation is based on [Bruenger:2014, page 72] with a=dv/dt # F_T: tractive effort (in N) @@ -118,9 +118,9 @@ function calcAcceleration(F_T::Real, F_R::Real, m_train::Real, ξ_train::Real) a = (F_T - F_R) /m_train /ξ_train # acceleration (in m/s) return a -end #function calcAcceleration +end #function acceleration -function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real) +function Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real) # equation is based on [Wende:2003, page 37] # Δt: time step (in s) @@ -128,9 +128,9 @@ function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real) # v_prev: velocitiy from previous data point Δs = Δt * (2*v_prev + Δt*a_prev) /2 # step size (in m) return Δs -end #function calc_Δs_with_Δt +end #function Δs_with_Δt -function calc_Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real) +function Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real) # equation is based on [Wende:2003, page 37] # Δv: velocity step (in m/s) @@ -138,9 +138,9 @@ function calc_Δs_with_Δv(Δv::Real, a_prev::Real, v_prev::Real) # v_prev: velocitiy from previous data point Δs = ((v_prev + Δv)^2 - v_prev^2)/2/a_prev # step size (in m) return Δs -end #function calc_Δs_with_Δv +end #function Δs_with_Δv -function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) +function Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) # equation is based on [Wende:2003, page 37] # Δs: distance step (in m) @@ -149,27 +149,27 @@ function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) Δt = sign(a_prev) *sqrt((v_prev /a_prev)^2 + 2 *Δs /a_prev) - v_prev /a_prev # step size (in m/s) return Δt -end #function calc_Δt_with_Δs +end #function Δt_with_Δs -function calc_Δt_with_Δv(Δv::Real, a_prev::Real) +function Δt_with_Δv(Δv::Real, a_prev::Real) # equation is based on [Wende:2003, page 37] # Δv: velocity step (in m/s) # a_prev: acceleration from previous data point Δt = Δv /a_prev # step size (in s) return Δt -end #function calc_Δt_with_Δv +end #function Δt_with_Δv -function calc_Δt_with_constant_v(Δs::Real, v::Real) +function Δt_with_constant_v(Δs::Real, v::Real) # equation is based on [Wende:2003, page 37] # Δs: distance step (in m) # v: constant velocity (in m/s) Δt = Δs /v # step size (in s) return Δt -end #function calc_Δt_with_constant_v +end #function Δt_with_constant_v -function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) +function Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) # equation is based on [Wende:2003, page 37] # Δs: distance step (in m) @@ -177,30 +177,30 @@ function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real) # v_prev: velocitiy from previous data point Δv = sqrt(v_prev^2 + 2*Δs*a_prev) - v_prev # step size (in m/s) return Δv -end #function calc_Δv_with_Δs +end #function Δv_with_Δs -function calc_Δv_with_Δt(Δt::Real, a_prev::Real) +function Δv_with_Δt(Δt::Real, a_prev::Real) # equation is based on [Wende:2003, page 37] # Δt: time step (in s) # a_prev: acceleration from previous data point Δv = Δt * a_prev # step size (in m/s) return Δv -end #function calc_Δv_with_Δt +end #function Δv_with_Δt -function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer) +function brakingDistance(v_start::Real, v_end::Real, a_braking::Real, approxLevel::Integer) # equation is based on [Wende:2003, page 37] # v_start: velocity at the start of braking (in m/s) # v_end: target velocity at the end of braking (in m/s) # a_braking: constant braking acceleration (in m/s^2) s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) - # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start) + # TODO: also possible: Δs_with_Δv(v_end-v_start, a_braking, v_start) # return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors return max(0.0, ceil(s_braking, digits= approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors -end #function calcBrakingDistance +end #function brakingDistance -function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, approxLevel::Integer) +function brakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, approxLevel::Integer) # equation is based on [Wende:2003, page 37] # v_end: target velocity at the end of braking (in m/s) @@ -209,9 +209,9 @@ function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real, v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) # return floor(v_start, digits= approxLevel) return floor(v_start, digits= approxLevel +1) -end #function calcBrakingStartVelocity +end #function brakingStartVelocity -function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) +function brakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) # equation is based on [Wende:2003, page 37] # v_start: braking start velocity (in m/s) @@ -219,4 +219,4 @@ function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) # s_braking: braking distance (in Ws) a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2) return a_braking -end #function calcBrakingAcceleration +end #function brakingAcceleration