From fde1027b92d44125fb8689c166548df25dcfbc02 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Wed, 23 Feb 2022 14:03:21 +0100 Subject: [PATCH] Refactor TrainRunCalc.jl for better readability --- src/Behavior.jl | 229 +---------------------------------------- src/Characteristics.jl | 78 ++++++++------ src/TrainRunCalc.jl | 76 +++++++++++--- 3 files changed, 112 insertions(+), 271 deletions(-) diff --git a/src/Behavior.jl b/src/Behavior.jl index 4fa4575..5198b8f 100644 --- a/src/Behavior.jl +++ b/src/Behavior.jl @@ -326,163 +326,8 @@ end #function addBreakFreeSection! ## This function calculates the data points of the acceleration section. # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the acceleration section -function addAccelerationSectionWithoutBraking!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) - #=if drivingCourse would also be part of movingSectiong: function addAccelerationSection!(movingSection::Dict, csId::Integer, settings::Dict, train::Dict) - CSs = movingSection[:characteristicSections] - CS = CSs[csId] - drivingCourse = movingSection[:drivingCourse]=# - - if drivingCourse[end][:v] == 0.0 - (CS, drivingCourse) = addBreakFreeSection!(CS, drivingCourse, settings, train, CSs) - end #if - - calculateForces!(drivingCourse[end], CSs, CS[:id], "acceleration", train, settings[:massModel]) - if drivingCourse[end][:F_T] < drivingCourse[end][:F_R] - (CS, drivingCourse) = addDiminishingSection!(CS, drivingCourse, settings, train, CSs) - calculateForces!(drivingCourse[end], CSs, CS[:id], "acceleration", train, settings[:massModel]) - end - - # if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept - formerSpeedLimits = detectFormerSpeedLimits(CSs, CS[:id], drivingCourse[end], train[:length]) - - # conditions for acceleration section - targetSpeedReached = drivingCourse[end][:v] >= CS[:v_peak] - trainAtEnd = drivingCourse[end][:s] >= CS[:s_exit] - tractionSurplus = drivingCourse[end][:F_T] > drivingCourse[end][:F_R] - - # use the conditions for the acceleration section - if !targetSpeedReached && !trainAtEnd && tractionSurplus - #11/23 long version: if drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] drivingCourse[end][:F_R] - BS = createBehaviorSection("acceleration", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) - drivingCourse[end][:behavior] = BS[:type] - - while !targetSpeedReached && !trainAtEnd && tractionSurplus - currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections - nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] - - # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) - drivingCourse[end][:behavior] = BS[:type] - push!(BS[:dataPoints], drivingCourse[end][:i]) - - if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal - (CS, drivingCourse, formerSpeedLimits, BS, endOfCsReached) = considerFormerSpeedLimits!(CS, drivingCourse, settings, train, CSs, formerSpeedLimits, BS) - if endOfCsReached - return (CS, drivingCourse) - end #if - currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections - end #if - - # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) - end #while - - # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 - if drivingCourse[end][:v] <= 0.0 - currentStepSize = settings[:stepSize] / 10.0^cycle - - elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] - currentStepSize = settings[:stepSize] / 10.0^cycle - - elseif drivingCourse[end][:s] > nextPointOfInterest - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] - else - currentStepSize = settings[:stepSize] / 10.0^cycle - end - - elseif drivingCourse[end][:v] > CS[:v_peak] - if settings[:stepVariable] == "v in m/s" - currentStepSize = CS[:v_peak]-drivingCourse[end-1][:v] - else - currentStepSize = settings[:stepSize] / 10.0^cycle - end - - elseif drivingCourse[end][:s] == CS[:s_exit] - trainAtEnd = true - break - - elseif drivingCourse[end][:v] == CS[:v_peak] - targetSpeedReached = true - break - - elseif drivingCourse[end][:s] == nextPointOfInterest - break - - else - error("ERROR at acceleration section: With the step variable ", settings[:stepVariable]," the while loop will be left although v CS[:v_peak] - targetSpeedReached = true - pop!(drivingCourse) - pop!(BS[:dataPoints]) - - elseif drivingCourse[end][:s] > nextPointOfInterest - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest - drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] - - elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] - tractionSurplus = false - (CS, drivingCourse) = addDiminishingSection!(CS, drivingCourse, settings, train, CSs) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) - - else - - end #if - - # TODO is it possible to put this into to the if-fork? - if drivingCourse[end][:s] == CS[:s_exit] - trainAtEnd = true - end - end #if - end #for - end #while - - if length(BS[:dataPoints]) > 1 # it is possible that the acceleration starts at v_peak, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. - # calculate the accumulated acceleration section information - 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) - - if CS[:v_peak] < drivingCourse[end][:v] - println("WARNING: v is getting to high at the end of the acceleration section. v=",drivingCourse[end][:v] ," > v_peak=",CS[:v_peak]) - # TODO: this warning should not be needed. just for testing - end - - merge!(CS[:behaviorSections], Dict(:acceleration => BS)) - end - end - - return (CS, drivingCourse) -end #function addAccelerationSectionWithoutBraking! - - -## This function calculates the data points of the acceleration section. function addAccelerationSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}, ignoreBraking::Bool) -#function addAccelerationSectionUntilBraking!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) - #=if drivingCourse would also be part of movingSectiong: function addAccelerationSection!(movingSection::Dict, csId::Integer, settings::Dict, train::Dict) + #=if drivingCourse would also be part of movingSectiong: function addAccelerationSection!(movingSection::Dict, csId::Integer, settings::Dict, train::Dict, ignoreBraking::Bool) CSs = movingSection[:characteristicSections] CS = CSs[csId] drivingCourse = movingSection[:drivingCourse]=# @@ -1081,78 +926,6 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Di end #function addCoastingSection! -## This function calculates the data points of the braking section. (standard braking section with only two data points) -# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed. -function addBrakingSectionInOneStep!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) - #function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) - # function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, massModel::String, train::Dict, CSs::Vector{Dict}) #, s_braking::AbstractFloat) - if drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:s] < CS[:s_exit] - BS = createBehaviorSection("braking", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) - BS[:s_exit] = CS[:s_exit] # last position (in m) - drivingCourse[end][:behavior] = BS[:type] - - - while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:s] < BS[:s_exit] - nextPointOfInterest = min(BS[:s_exit], getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])) - - if nextPointOfInterest < BS[:s_exit] - # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) - drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], BS[:s_exit]-drivingCourse[end][:s]) - # TODO: or just take train[:a_braking]? difference is by 0.0000000001 m/s^2: drivingCourse[end][:a] = train[:a_braking] - # println("a_braking till ",nextPointOfInterest,": ", calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], BS[:s_exit]-drivingCourse[end][:s]), ". It should be: ",train[:a_braking]) - - # calculate the braking distance to the next point of interest - stepSize = nextPointOfInterest - drivingCourse[end][:s] - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], "s in m", stepSize, CS[:id])) - drivingCourse[end][:behavior] = BS[:type] - push!(BS[:dataPoints], drivingCourse[end][:i]) - - else # so if nextPointOfInterest == BS[:s_exit] - # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) - - push!(drivingCourse, createDataPoint()) - drivingCourse[end][:i] = drivingCourse[end-1][:i]+1 # incrementing the number of the data point - drivingCourse[end][:behavior] = BS[:type] - push!(BS[:dataPoints], drivingCourse[end][:i]) # refering from the breaking section to the last of its data points - - # calculate s, t, v - drivingCourse[end][:s] = BS[:s_exit] # position (in m) - drivingCourse[end][:v] = CS[:v_exit] # velocity (in m/s) - drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] # step size (in m) - drivingCourse[end][:Δv] = drivingCourse[end][:v] - drivingCourse[end-1][:v] # step size (in m/s) - - drivingCourse[end-1][:a] = calcBrakingAcceleration(drivingCourse[end-1][:v], drivingCourse[end][:v], drivingCourse[end][:Δs]) - drivingCourse[end][:Δt] = calc_Δt_with_Δv(drivingCourse[end][:Δv], drivingCourse[end-1][:a]) # step size (in s) - drivingCourse[end][:t] = drivingCourse[end-1][:t] + drivingCourse[end][:Δt] # point in time (in s) - - drivingCourse[end][:ΔW] = 0.0 # mechanical work in this step (in Ws) - drivingCourse[end][:W] = drivingCourse[end-1][:W] + drivingCourse[end][:ΔW] # mechanical work (in Ws) - drivingCourse[end][:ΔE] = drivingCourse[end][:ΔW] # energy consumption in this step (in Ws) - drivingCourse[end][:E] = drivingCourse[end-1][:E] + drivingCourse[end][:ΔE] # energy consumption (in Ws) - - break - end #if - end #while - - merge!(BS, Dict(:length => drivingCourse[end][:Δs], # total length (in m) - #:s_exit => drivingCourse[end][:s], # last position (in m) - :t => drivingCourse[end][:Δt], # total running time (in s) - :E => drivingCourse[end][:ΔE], # total energy consumption (in Ws) - :v_exit => drivingCourse[end][:v])) # exit speed (in m/s))) - - CS[:t] = CS[:t] + 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 - return (CS, drivingCourse) -end #function addBrakingSectionInOneStep! - - ## This function calculates the data points of the braking section. # 09/07 new braking section with more than two data points # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed. function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) diff --git a/src/Characteristics.jl b/src/Characteristics.jl index 7ec3006..3d4db14 100644 --- a/src/Characteristics.jl +++ b/src/Characteristics.jl @@ -14,10 +14,11 @@ export preparateSections ## create a moving section and its containing characteristic sections with secured braking, acceleration and cruising behavior function preparateSections(path::Dict, train::Dict, settings::Dict) - movingSection=createMovingSection(path, train[:v_limit]) - movingSection=secureBrakingBehavior!(movingSection, train[:a_braking]) - movingSection=secureAccelerationBehavior!(movingSection, settings, train) - movingSection=secureCruisingBehavior!(movingSection, settings, train) + movingSection = createMovingSection(path, train[:v_limit]) + movingSection = secureBrakingBehavior!(movingSection, train[:a_braking]) + movingSection = secureAccelerationBehavior!(movingSection, settings, train) + movingSection = secureCruisingBehavior!(movingSection, settings, train) + return movingSection end #function preparateSections @@ -95,17 +96,25 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) CSs = movingSection[:characteristicSections] csId = length(CSs) - CSs[csId][:v_exit] = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s + followingCSv_entry = 0.0 # the exit velocity of the last characteristic section is 0.0 m/s while csId >= 1 - v_entryMax = calcBrakingStartVelocity(CSs[csId][:v_exit], a_braking, CSs[csId][:length]) - #v_entryMax=floor(v_entryMax, digits=12) + CS = CSs[csId] - CSs[csId][:v_entry] = min(CSs[csId][:v_limit], v_entryMax) - CSs[csId][:v_peak] = CSs[csId][:v_entry] + 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 - if csId >= 1 - CSs[csId][:v_exit]=min(CSs[csId][:v_limit], CSs[csId+1][:v_entry]) - end #if end #while return movingSection end #function secureBrakingBehavior! @@ -120,23 +129,27 @@ function secureAccelerationBehavior!(movingSection::Dict, settings::Dict, train: startingPoint[:i] = 1 previousCSv_exit = CSs[1][:v_entry] - for csId in 1:length(CSs) - CSs[csId][:v_entry] = min(CSs[csId][:v_entry], previousCSv_exit) + for CS in CSs + CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) - startingPoint[:s] = CSs[csId][:s_entry] - startingPoint[:v] = CSs[csId][:v_entry] + startingPoint[:s] = CS[:s_entry] + startingPoint[:v] = CS[:v_entry] accelerationCourse::Vector{Dict} = [startingPoint] # List of data points - if CSs[csId][:v_entry] < CSs[csId][:v_peak] - # 02/22 old (CSs[csId], accelerationCourse) = addAccelerationSection!(CSs[csId], accelerationCourse, settings, train, CSs) # this function changes the accelerationCourse - (CSs[csId], accelerationCourse) = addAccelerationSection!(CSs[csId], accelerationCourse, settings, train, CSs, true) # this function changes the accelerationCourse - CSs[csId][:v_peak] = max(CSs[csId][:v_entry], accelerationCourse[end][:v]) - CSs[csId][:v_exit] = min(CSs[csId][:v_exit], CSs[csId][:v_peak], accelerationCourse[end][:v]) - else #CSs[csId][:v_entry]==CSs[csId][:v_peak] + if CS[:v_entry] < CS[:v_peak] + (CS, accelerationCourse) = addAccelerationSection!(CS, accelerationCourse, settings, train, CSs, true) # this function changes the accelerationCourse + CS[:v_peak] = max(CS[:v_entry], accelerationCourse[end][:v]) + CS[:v_exit] = min(CS[:v_exit], CS[:v_peak], accelerationCourse[end][:v]) + else #CS[:v_entry] == CS[:v_peak] # v_exit stays the same end #if - previousCSv_exit=CSs[csId][:v_exit] + 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 @@ -154,17 +167,22 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic previousCSv_exit = CSs[1][:v_entry] - for csId in 1:length(CSs) - CSs[csId][:v_entry] = min(CSs[csId][:v_entry], previousCSv_exit) + for CS in CSs + CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) - startingPoint[:s] = CSs[csId][:s_entry] - startingPoint[:v] = CSs[csId][:v_peak] + startingPoint[:s] = CS[:s_entry] + startingPoint[:v] = CS[:v_peak] cruisingCourse::Vector{Dict} = [startingPoint] # List of data points - (CSs[csId], cruisingCourse) = addCruisingSection!(CSs[csId], cruisingCourse, CSs[csId][:length], settings, train, CSs, "cruising") # this function changes the cruisingCourse - CSs[csId][:v_exit] = min(CSs[csId][:v_exit], cruisingCourse[end][:v]) + (CS, cruisingCourse) = addCruisingSection!(CS, cruisingCourse, CS[:length], settings, train, CSs, "cruising") # this function changes the cruisingCourse + CS[:v_exit] = min(CS[:v_exit], cruisingCourse[end][:v]) - previousCSv_exit = CSs[csId][:v_exit] + 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 diff --git a/src/TrainRunCalc.jl b/src/TrainRunCalc.jl index e7fbaec..1aed9a0 100644 --- a/src/TrainRunCalc.jl +++ b/src/TrainRunCalc.jl @@ -77,21 +77,74 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train startingPoint[:s]=CSs[1][:s_entry] drivingCourse::Vector{Dict} = [startingPoint] # List of data points - # for CS in CSs + for csId in 1:length(CSs) + CS = CSs[csId] + + # for testing + if drivingCourse[end][:s] != CS[:s_entry] + println("ERROR: In CS", csId," the train run starts at s=",drivingCourse[end][:s]," and not s_entry=",CS[:s_entry]) + end + if drivingCourse[end][:v] > CS[:v_entry] + println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_entry=",CS[:v_entry]) + end + + if drivingCourse[end][:v] < CS[:v_peak] + (CS, drivingCourse) = addAccelerationSection!(CS, drivingCourse, settings, train, CSs, false) + end #if + + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking + + + if s_cruising > 0.0 # TODO: define a minimum cruising length? + (CS, drivingCourse) = addCruisingSection!(CS, drivingCourse, s_cruising, settings, train, CSs, "cruising") + end + + if drivingCourse[end][:v] > CS[:v_exit] + (CS, drivingCourse)=addBrakingSection!(CS, drivingCourse, settings, train, CSs) + end #if + + + # for testing: + if drivingCourse[end][:s] != CS[:s_exit] + println("ERROR: In CS", csId," the train run ends at s=",drivingCourse[end][:s]," and not s_exit=",CS[:s_exit]) + end + if drivingCourse[end][:v] > CS[:v_exit] + println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_exit=",CS[:v_exit]) + end + end #for + + (CSs[end], drivingCourse) = addStandstill!(CSs[end], drivingCourse, settings, train, CSs) + + movingSection[:t] = drivingCourse[end][:t] # total running time (in s) + movingSection[:E] = drivingCourse[end][:E] # total energy consumption (in Ws) + + return (movingSection, drivingCourse) +end #function calculateMinimumRunningTime + +end # module TrainRunCalc + + + #= +# calculate a train run focussing on using the minimum possible running time +function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train::Dict) + CSs::Vector{Dict} = movingSection[:characteristicSections] + + startingPoint=createDataPoint() + startingPoint[:i]=1 + startingPoint[:s]=CSs[1][:s_entry] + drivingCourse::Vector{Dict} = [startingPoint] # List of data points + for csId in 1:length(CSs) CS = CSs[csId] BSs = CS[:behaviorSections] # for testing: if drivingCourse[end][:s] != CS[:s_entry] - if haskey(BSs, :cruising) - println("ERROR: In CS", csId," the train run starts at s=",drivingCourse[end][:s]," and not s_entry=",CS[:s_entry]) - end + println("ERROR: In CS", csId," the train run starts at s=",drivingCourse[end][:s]," and not s_entry=",CS[:s_entry]) end if drivingCourse[end][:v] > CS[:v_entry] - if haskey(BSs, :cruising) - println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_entry=",CS[:v_entry]) - end + println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_entry=",CS[:v_entry]) end # check if the CS has a cruising section @@ -151,14 +204,10 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train # for testing: if drivingCourse[end][:s] != CS[:s_exit] - if haskey(BSs, :cruising) - println("ERROR: In CS", csId," the train run ends at s=",drivingCourse[end][:s]," and not s_exit=",CS[:s_exit]) - end + println("ERROR: In CS", csId," the train run ends at s=",drivingCourse[end][:s]," and not s_exit=",CS[:s_exit]) end if drivingCourse[end][:v] > CS[:v_exit] - if haskey(BSs, :cruising) - println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_exit=",CS[:v_exit]) - end + println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_exit=",CS[:v_exit]) end end #for @@ -172,3 +221,4 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train end #function calculateMinimumRunningTime end # module TrainRunCalc + =#