refactored functions, removed characteristics.jl, and unified naming in constructors.jl

development
Martin Scheidt 2022-06-03 17:24:16 +02:00
parent 370e8cf812
commit fab1ad017a
6 changed files with 395 additions and 393 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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!
=#

View File

@ -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

View File

@ -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!
=#

View File

@ -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