correct lower/upper case pickup
parent
310cd013da
commit
80388e635f
1398
src/Behavior.jl
1398
src/Behavior.jl
File diff suppressed because it is too large
Load Diff
160
src/Calc.jl
160
src/Calc.jl
|
@ -1,160 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
# Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`.
|
||||
|
||||
"""
|
||||
trainRun(train::Dict, path::Dict, settings::Settings)
|
||||
|
||||
Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding dictionaries `train`, `path`, `settings`.
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> trainRun(trainDict, pathDict)
|
||||
todo !!!
|
||||
```
|
||||
"""
|
||||
function trainRun(trainInput::Dict, pathInput::Dict, settings=Settings()::Settings)
|
||||
# copy Input data for not changing them
|
||||
# TODO: or should they be changed? normally it would only make it "better" except for settings.outputDetail == :points_of_interest && !haskey(path, :pointsOfInterest)
|
||||
train = copy(trainInput)
|
||||
path = copy(pathInput)
|
||||
|
||||
# check the input data
|
||||
(train, path) = checkAndSetInput!(train, path, settings)
|
||||
settings.outputDetail == :everything && println("The input has been checked.")
|
||||
|
||||
# prepare the input data
|
||||
movingSection = determineCharacteristics(path, train, settings)
|
||||
settings.outputDetail == :everything && 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.")
|
||||
|
||||
# accumulate data and create an output dictionary
|
||||
output = createOutput(train, settings, path, movingSection, drivingCourse)
|
||||
|
||||
return output
|
||||
end # function trainRun
|
||||
|
||||
# calculate a train run focussing on using the minimum possible running time
|
||||
function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, train::Dict)
|
||||
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 ! ! !")
|
||||
end
|
||||
|
||||
startingPoint=createDataPoint()
|
||||
startingPoint[:i]=1
|
||||
startingPoint[:s]=CSs[1][:s_entry]
|
||||
calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N)
|
||||
drivingCourse::Vector{Dict} = [startingPoint] # List of data points
|
||||
|
||||
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
|
||||
|
||||
# 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])
|
||||
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N)
|
||||
|
||||
previousSpeedLimitReached = false
|
||||
stateFlags = Dict(:endOfCSReached => drivingCourse[end][:s] > CS[:s_exit],
|
||||
:brakingStartReached => drivingCourse[end][:s] + s_braking == CS[:s_exit],
|
||||
:tractionDeficit => drivingCourse[end][:F_T] < drivingCourse[end][:F_R], # or add another flag for equal forces?
|
||||
:resistingForceNegative => drivingCourse[end][:F_R] < 0.0,
|
||||
:previousSpeedLimitReached => false, #speedLimitReached, # check already at this position?
|
||||
: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")
|
||||
while !stateFlags[:endOfCSReached] # s < s_exit
|
||||
if !stateFlags[:brakingStartReached] # s+s_braking < s_exit
|
||||
if !stateFlags[:tractionDeficit]
|
||||
if drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && drivingCourse[end][:v] == 0.0
|
||||
(CS, drivingCourse, stateFlags) = addBreakFreeSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
|
||||
|
||||
elseif stateFlags[:previousSpeedLimitReached]
|
||||
(CS, drivingCourse, stateFlags) = addClearingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
|
||||
|
||||
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
|
||||
(CS, drivingCourse, stateFlags) = addAcceleratingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
|
||||
|
||||
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
|
||||
# cruise only one step
|
||||
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])
|
||||
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])
|
||||
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
|
||||
|
||||
if s_cruising > 0.0
|
||||
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking")
|
||||
else
|
||||
stateFlags[:brakingStartReached] = true
|
||||
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_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
|
||||
|
||||
if s_cruising > 0.0 # TODO: define a minimum cruising length?
|
||||
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
|
||||
else
|
||||
stateFlags[:brakingStartReached] = true
|
||||
end
|
||||
else
|
||||
error()
|
||||
end
|
||||
elseif stateFlags[:tractionDeficit]
|
||||
(CS, drivingCourse, stateFlags) = addDiminishingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
|
||||
|
||||
else
|
||||
error()
|
||||
end
|
||||
else#if !stateFlags[:endOfCSReached] # s < s_exit
|
||||
(CS, drivingCourse, stateFlags) = addBrakingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
|
||||
#else
|
||||
# error()
|
||||
end
|
||||
end
|
||||
#if s == s_exit
|
||||
# standstill
|
||||
#end
|
||||
|
||||
|
||||
# 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
|
|
@ -1,241 +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::Dict, train::Dict, settings::Settings)
|
||||
movingSection = createMovingSection(path, train[:v_limit])
|
||||
movingSection = secureBrakingBehavior!(movingSection, train[:a_braking])
|
||||
movingSection = secureAcceleratingBehavior!(movingSection, settings, train)
|
||||
#movingSection = secureCruisingBehavior!(movingSection, settings, train)
|
||||
|
||||
return movingSection
|
||||
end #function determineCharacteristics
|
||||
|
||||
## create a moving section containing characteristic sections
|
||||
function createMovingSection(path::Dict, v_trainLimit::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)
|
||||
s_exit = path[:sections][end][:s_end] # last position (in m)
|
||||
pathLength = s_exit - s_entry # total length (in m)
|
||||
|
||||
CSs=Vector{Dict}()
|
||||
s_csStart=s_entry
|
||||
csId=1
|
||||
for row in 2:length(path[:sections])
|
||||
previousSection = path[:sections][row-1]
|
||||
currentSection = path[:sections][row]
|
||||
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), 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), 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)
|
||||
: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
|
||||
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, path::Dict)
|
||||
# Create and return a characteristic section dependent on the paths attributes
|
||||
characteristicSection= Dict(:id => id, # identifier
|
||||
:s_entry => s_entry, # first position (in m)
|
||||
:s_exit => section[:s_end], # last position (in m)
|
||||
:length => section[:s_end] -s_entry, # total length (in m)
|
||||
: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)
|
||||
:v_entry => v_limit, # maximum entry speed (in m/s)
|
||||
:v_exit => v_limit) # maximum exit speed (in m/s)
|
||||
|
||||
# list of positions of every point of interest (POI) in this charateristic section for which data points should be calculated
|
||||
s_exit = characteristicSection[:s_exit]
|
||||
pointsOfInterest = Vector{Real}()
|
||||
if haskey(path, :pointsOfInterest)
|
||||
for POI in path[:pointsOfInterest]
|
||||
if s_entry < POI && 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
|
||||
|
||||
merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest))
|
||||
|
||||
return characteristicSection
|
||||
end #function createCharacteristicSection
|
||||
|
||||
## 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::Dict)
|
||||
# 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::Dict)
|
||||
# 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!
|
||||
=#
|
212
src/Export.jl
212
src/Export.jl
|
@ -1,212 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
function exportToCsv(runningTime::AbstractFloat, settings::Settings)
|
||||
createCsvFile(runningTime, settings)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function exportToCsv(dataPointsToExport::Vector{Dict}, settings::Settings)
|
||||
createCsvFile(dataPointsToExport, settings)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function exportToCsv(output::Dict)
|
||||
if output[:settings][:outputFormat] == "CSV"
|
||||
pathName = output[:path][:name]
|
||||
trainName = output[:train][:name]
|
||||
|
||||
if output[:settings][:operationModeMinimumRunningTime] == true
|
||||
operationMode = "minimum running time"
|
||||
if output[:settings][:outputDetail] == "points of interest"
|
||||
dataPointsToExport = output[:pointsOfInterestMinimumRunningTime]
|
||||
else
|
||||
dataPointsToExport = output[:drivingCourseMinimumRunningTime]
|
||||
end
|
||||
createCsvFile(dataPointsToExport, operationMode, pathName, trainName, output[:settings])
|
||||
end
|
||||
if output[:settings][:operationModeMinimumEnergyConsumption] == true
|
||||
operationMode = "minimum energy consumption"
|
||||
if output[:settings][:outputDetail] == "points of interest"
|
||||
dataPointsToExport = output[:pointsOfInterestMinimumEnergyConsumption]
|
||||
else
|
||||
dataPointsToExport = output[:drivingCourseMinimumEnergyConsumption]
|
||||
end
|
||||
createCsvFile(dataPointsToExport, operationMode, pathName, trainName, output[:settings])
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end #function exportToCsv
|
||||
|
||||
function createCsvFile(runningTime::AbstractFloat, settings::Settings)
|
||||
# create DataFrame with running time information
|
||||
df = DataFrame(column1=["t (in s)", runningTime])
|
||||
|
||||
# save DataFrame as a CSV-file at outputDir
|
||||
date = Dates.now()
|
||||
dateString = Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
|
||||
|
||||
csvFilePath = settings[:outputDir]*"/"*dateString*"_RunningTime.csv"
|
||||
|
||||
CSV.write(csvFilePath, df, header=false)
|
||||
println("The output CSV file has been created at ",csvFilePath)
|
||||
|
||||
return true
|
||||
end #function createCsvFile
|
||||
|
||||
|
||||
function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Settings)
|
||||
outputDetail = settings[:outputDetail]
|
||||
|
||||
header = ["i", "behavior", "Δ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)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]
|
||||
columnSymbols = [:i, :behavior, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :ΔW, :W, :ΔE, :E, :a]
|
||||
|
||||
allColumns = Array{Any,1}[]
|
||||
for column in 1:length(header)
|
||||
currentColumn = Any[]
|
||||
push!(currentColumn, header[column])
|
||||
for point in dataPointsToExport
|
||||
push!(currentColumn, point[columnSymbols[column]])
|
||||
end
|
||||
push!(allColumns, currentColumn)
|
||||
end # for
|
||||
|
||||
|
||||
# combine the columns in a data frame and saving it as a CSV-file at outputDir
|
||||
if outputDetail == "driving course" || outputDetail == "points of interest"
|
||||
df = 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], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
|
||||
|
||||
else
|
||||
println("")
|
||||
end
|
||||
|
||||
date = Dates.now()
|
||||
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
|
||||
csvFilePath=settings[:outputDir]*"/"*dateString*"_DataPoints.csv"
|
||||
CSV.write(csvFilePath, df, header=false)
|
||||
println("The output CSV file has been created at ",csvFilePath)
|
||||
|
||||
return true
|
||||
end #function createCsvFile
|
||||
|
||||
|
||||
function createCsvFile(dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Settings)
|
||||
outputDetail = settings[:outputDetail]
|
||||
|
||||
massModel = settings.massModel
|
||||
stepVariable = settings.stepVariable
|
||||
stepSize = string(settings.stepSize)
|
||||
|
||||
# create accumulated data block
|
||||
accumulatedData = Array{Any, 1}[]
|
||||
push!(accumulatedData, ["i", "behavior", "Δ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)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData
|
||||
for point in dataPointsToExport
|
||||
row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]]
|
||||
push!(accumulatedData, row) # push row to accumulatedData
|
||||
end
|
||||
|
||||
#create information block
|
||||
allColumns=Array{Any,1}[]
|
||||
push!(allColumns, ["path name", "train name", "operation mode", "mass model", "step variable", "step size", ""])
|
||||
push!(allColumns, [pathName, trainName, operationMode, massModel, stepVariable, stepSize, ""])
|
||||
for column in 3:length(accumulatedData[1])
|
||||
push!(allColumns, ["", "", "", "", "", "", ""])
|
||||
end # for
|
||||
|
||||
# add driving data to the array
|
||||
header = accumulatedData[1]
|
||||
for column in 1:length(accumulatedData[1])
|
||||
push!(allColumns[column], header[column])
|
||||
for row in accumulatedData[2:end]
|
||||
push!(allColumns[column], row[column])
|
||||
end
|
||||
end # for
|
||||
|
||||
# combine the columns in a data frame and saving it as a CSV-file at outputDir
|
||||
df = 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], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
|
||||
|
||||
date = Dates.now()
|
||||
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
|
||||
if operationMode == "minimum running time"
|
||||
csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumRunningTime.csv"
|
||||
elseif operationMode == "minimum energy consumption"
|
||||
csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumEnergyConsumption.csv"
|
||||
else
|
||||
# should not be possible
|
||||
end
|
||||
CSV.write(csvFilePath, df, header=false)
|
||||
println("The output CSV file has been created for ",operationMode," at ",csvFilePath)
|
||||
|
||||
return true
|
||||
end #function createCsvFile
|
||||
|
||||
|
||||
|
||||
#=
|
||||
function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Settings)
|
||||
outputDetail = settings[:outputDetail]
|
||||
|
||||
massModel = settings.massModel
|
||||
stepVariable = settings.stepVariable
|
||||
stepSize = string(settings.stepSize)
|
||||
|
||||
# create accumulated data block
|
||||
accumulatedData = Array{Any, 1}[]
|
||||
if outputDetail == "minimal"
|
||||
push!(accumulatedData, ["s (in m)", "t (in s)","E (in Ws)"]) # push header to accumulatedData
|
||||
row = [movingSection[:length], movingSection[:t], movingSection[:E]]
|
||||
push!(accumulatedData, row) # push row to accumulatedData
|
||||
elseif outputDetail == "driving course" || outputDetail == "points of interest"
|
||||
push!(accumulatedData, ["i", "behavior", "Δ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)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData
|
||||
for point in dataPointsToExport
|
||||
row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]]
|
||||
push!(accumulatedData, row) # push row to accumulatedData
|
||||
end
|
||||
end
|
||||
|
||||
#create information block
|
||||
allColumns=Array{Any,1}[]
|
||||
push!(allColumns, ["path name", "train name", "operation mode", "mass model", "step variable", "step size", ""])
|
||||
push!(allColumns, [pathName, trainName, operationMode, massModel, stepVariable, stepSize, ""])
|
||||
for column in 3:length(accumulatedData[1])
|
||||
push!(allColumns, ["", "", "", "", "", "", ""])
|
||||
end # for
|
||||
|
||||
# add driving data to the array
|
||||
header = accumulatedData[1]
|
||||
for column in 1:length(accumulatedData[1])
|
||||
push!(allColumns[column], header[column])
|
||||
for row in accumulatedData[2:end]
|
||||
push!(allColumns[column], row[column])
|
||||
end
|
||||
end # for
|
||||
|
||||
# combine the columns in a data frame and saving it as a CSV-file at outputDir
|
||||
if outputDetail == "minimal"
|
||||
df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3])
|
||||
elseif outputDetail=="driving course" || outputDetail == "points of interest"
|
||||
df = 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], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
|
||||
end
|
||||
|
||||
date = Dates.now()
|
||||
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
|
||||
if operationMode == "minimum running time"
|
||||
csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumRunningTime.csv"
|
||||
elseif operationMode == "minimum energy consumption"
|
||||
csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumEnergyConsumption.csv"
|
||||
else
|
||||
# should not be possible
|
||||
end
|
||||
CSV.write(csvFilePath, df, header=false)
|
||||
println("The output CSV file has been created for ",operationMode," at ",csvFilePath)
|
||||
|
||||
return true
|
||||
end #function createCsvFile
|
||||
=#
|
226
src/Formulary.jl
226
src/Formulary.jl
|
@ -1,226 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
#########################
|
||||
## literature the driving dynamics equations are based on:
|
||||
##
|
||||
## @incollection{Bruenger:2014, % Chapter 4
|
||||
## author = {Brünger, Olaf and Dahlhaus, Elias},
|
||||
## year = {2014},
|
||||
## title = {Running Time Estimation},
|
||||
## pages = {65--90},
|
||||
## booktitle = {Railway Timetabling \& Operations.},
|
||||
## editora = {Hansen, Ingo A.},
|
||||
## editorb = {Pachl, Jörn},
|
||||
## isbn = {978-3-777-10462-1},
|
||||
## publisher = {Eurailpress DVV Media Group},
|
||||
## }
|
||||
## @Book{Wende:2003,
|
||||
## author = {Wende, Dietrich},
|
||||
## date = {2003},
|
||||
## title = {Fahrdynamik des Schienenverkehrs},
|
||||
## isbn = {978-3-322-82961-0},
|
||||
## publisher = {Springer-Verlag},
|
||||
## }
|
||||
#########################
|
||||
|
||||
approxLevel = 6
|
||||
v00 = 100/3.6 # velocity factor (in m/s)
|
||||
g = 9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2
|
||||
|
||||
## calculate forces
|
||||
|
||||
#TODO: replace the ? ? ?
|
||||
"""
|
||||
calcTractionUnitResistance(v, train)
|
||||
|
||||
Calculate the vehicle resistance for the traction unit of the `train` dependend on the velocity `v`.
|
||||
|
||||
...
|
||||
# Arguments
|
||||
- `v::AbstractFloat`: the current velocity in m/s.
|
||||
- `train::Dict`: ? ? ?
|
||||
...
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> calcTractionUnitResistance(30.0, ? ? ?)
|
||||
? ? ?
|
||||
```
|
||||
"""
|
||||
function calcTractionUnitResistance(v::AbstractFloat, train::Dict)
|
||||
# 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)
|
||||
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)
|
||||
Δv_t = train[:Δv_t] # coefficient for velocitiy difference between traction unit and outdoor air (in m/s)
|
||||
|
||||
F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_t) /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_t) /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_t])/v00)^2 # /1000 because of the unit ‰
|
||||
end #function calcTractionUnitResistance
|
||||
|
||||
"""
|
||||
TODO
|
||||
calculate and return the wagons vehicle resistance dependend on the velocity
|
||||
"""
|
||||
function calcWagonsResistance(v::AbstractFloat, train::Dict)
|
||||
# equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] with more detailled factors (Lehmann, page 135)
|
||||
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)
|
||||
Δv_w = train[:Δv_w] # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
|
||||
|
||||
F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_w) /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_w) /v00)^2 # vehicle resistance of the wagons (in N)
|
||||
return F_R_wagons
|
||||
end #function calcWagonsResistance
|
||||
|
||||
function calcForceFromCoefficient(f_R::Real, m::Real)
|
||||
# equation is based on [Wende:2003, page 8]
|
||||
|
||||
# f_R: specific resistance (in ‰)
|
||||
# m: vehicle's mass (in kg)
|
||||
|
||||
F_R = f_R /1000 *m *g # Resisting Force (in N) # /1000 because of the unit ‰
|
||||
return F_R
|
||||
end #function calcForceFromCoefficient
|
||||
|
||||
function calcAcceleration(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)
|
||||
# F_R: resisting forces (in N)
|
||||
# m_train: train's mass (in kg)
|
||||
# ξ_train: train's rotation mass factor (without unit)
|
||||
|
||||
a = (F_T - F_R) /m_train /ξ_train # acceleration (in m/s)
|
||||
return a
|
||||
end #function calcAcceleration
|
||||
|
||||
function calc_Δs_with_Δt(Δt::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δt: time step (in s)
|
||||
# a_prev: acceleration from previous data point
|
||||
# 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
|
||||
|
||||
function calc_Δ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)
|
||||
# a_prev: acceleration from previous data point
|
||||
# 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
|
||||
|
||||
function calc_Δt_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δs: distance step (in m)
|
||||
# a_prev: acceleration from previous data point
|
||||
# v_prev: velocitiy from previous data point
|
||||
|
||||
Δ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
|
||||
|
||||
function calc_Δ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
|
||||
|
||||
function calc_Δ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
|
||||
|
||||
function calc_Δv_with_Δs(Δs::Real, a_prev::Real, v_prev::Real)
|
||||
# equation is based on [Wende:2003, page 37]
|
||||
|
||||
# Δs: distance step (in m)
|
||||
# a_prev: acceleration from previous data point
|
||||
# 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
|
||||
|
||||
function calc_Δ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
|
||||
|
||||
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)
|
||||
# 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)
|
||||
# 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
|
||||
|
||||
function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real)
|
||||
# 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)
|
||||
end #function calcBrakingStartVelocity
|
||||
|
||||
function calcBrakingAcceleration(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)
|
||||
# v_end: target velocity at the end of braking (in m/s)
|
||||
# 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
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
"""
|
||||
Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them.
|
||||
"""
|
||||
function importYamlFiles(trainDirectory::String, pathDirectory::String)
|
||||
train = importFromYaml(:train, trainDirectory)
|
||||
path = importFromYaml(:path, pathDirectory)
|
||||
|
||||
return (train, path)
|
||||
end #function importYamlFiles
|
||||
|
||||
"""
|
||||
Read the train information from a YAML file, save it in a Dict and return it.
|
||||
"""
|
||||
function importFromYaml(dataType::Symbol, directory::String)
|
||||
dataSet = String(dataType)
|
||||
data = YAML.load(open(directory))
|
||||
if collect(keys(data))[1] != dataSet
|
||||
error("ERROR at reading the ", dataSet, " yaml file: The data set is called ", collect(keys(data))[1]," and not ", dataSet, ".")
|
||||
end
|
||||
dataKeys = collect(keys(data[dataSet]))
|
||||
dataKeys = collect(keys(data[dataSet]))
|
||||
dataValues = collect(values(data[dataSet]))
|
||||
dictionary = Dict()
|
||||
for number in 1:length(dataKeys)
|
||||
merge!(dictionary, Dict(Symbol(dataKeys[number]) => dataValues[number]))
|
||||
end
|
||||
return dictionary
|
||||
end # function importFromYaml
|
106
src/Output.jl
106
src/Output.jl
|
@ -1,106 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg"
|
||||
# __copyright__ = "2020-2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
function createOutput(train::Dict, settings::Settings, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
|
||||
if settings.outputDetail == :running_time
|
||||
output = movingSection[:t] # TODO: or use drivingCourse[end][:t]
|
||||
|
||||
elseif settings.outputDetail == :points_of_interest
|
||||
# add points of interest
|
||||
if haskey(path, :pointsOfInterest)
|
||||
output = Vector{Dict}()
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i]
|
||||
if path[:pointsOfInterest][POI] == drivingCourse[i][:s]
|
||||
push!(output, drivingCourse[i])
|
||||
POI = POI+1
|
||||
end
|
||||
i = i+1
|
||||
end
|
||||
end
|
||||
|
||||
elseif settings.outputDetail == :driving_course
|
||||
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
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(output, Dict(:movingSectionMinimumRunningTime => movingSection,
|
||||
:drivingCourseMinimumRunningTime => drivingCourse))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(output, Dict(:movingSectionMinimumEnergyConsumption => movingSection,
|
||||
:drivingCourseMinimumEnergyConsumption => drivingCourse))
|
||||
end
|
||||
|
||||
# add points of interest
|
||||
if haskey(path, :pointsOfInterest)
|
||||
pointsOfInterest = Vector{Dict}()
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i]
|
||||
if path[:pointsOfInterest][POI] == drivingCourse[i][:s]
|
||||
push!(pointsOfInterest, drivingCourse[i])
|
||||
POI = POI+1
|
||||
end
|
||||
i = i+1
|
||||
end
|
||||
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(output, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(output, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
|
||||
end
|
||||
end
|
||||
else
|
||||
output = nothing
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
#=
|
||||
function createOutputDict(train::Dict, settings::Settings, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
|
||||
outputDict = Dict{Symbol,Any}()
|
||||
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
# add points of interest
|
||||
if haskey(path, :pointsOfInterest)
|
||||
pointsOfInterest = Vector{Dict}()
|
||||
POI = 1
|
||||
i = 1
|
||||
while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i]
|
||||
if path[:pointsOfInterest][POI] == drivingCourse[i][:s]
|
||||
push!(pointsOfInterest, drivingCourse[i])
|
||||
POI = POI+1
|
||||
end
|
||||
i = i+1
|
||||
end
|
||||
|
||||
if settings[:operationModeMinimumRunningTime] == true
|
||||
merge!(outputDict, Dict(:pointsOfInterestMinimumRunningTime => pointsOfInterest))
|
||||
elseif settings[:operationModeMinimumEnergyConsumption] == true
|
||||
merge!(outputDict, Dict(:pointsOfInterestMinimumEnergyConsumption => pointsOfInterest))
|
||||
end
|
||||
end
|
||||
|
||||
return outputDict
|
||||
end # function createOutputDict
|
||||
=#
|
799
src/Types.jl
799
src/Types.jl
|
@ -1,799 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
# -*- coding: UTF-8 -*-
|
||||
# __julia-version__ = 1.7.2
|
||||
# __author__ = "Max Kannenberg, Martin Scheidt"
|
||||
# __copyright__ = "2022"
|
||||
# __license__ = "ISC"
|
||||
|
||||
"""
|
||||
Settings(file)
|
||||
|
||||
Settings is a datastruture for calculation context.
|
||||
The function Settings() will create a set of settings for the train run calculation.
|
||||
`file` is optinal may be used to load settings in the YAML format.
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia> my_settings = Settings() # will generate default settings
|
||||
Settings(mass_point, :distance, 20, 3, running_time, julia_dict, ".")
|
||||
```
|
||||
"""
|
||||
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.
|
||||
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest",
|
||||
# complete Array() ":driving_course", or Dict() ":everything".
|
||||
outputFormat::Symbol # output as ":julia_dict" or as ":csv".
|
||||
outputDir::String # if outputFormat is not ":julia_dict".
|
||||
|
||||
## constructor
|
||||
function Settings(file="DEFAULT")
|
||||
|
||||
## default values
|
||||
massModel = :mass_point
|
||||
stepVariable = :distance
|
||||
stepSize = 20
|
||||
approxLevel = 3
|
||||
outputDetail = :running_time
|
||||
outputFormat = :julia_dict
|
||||
outputDir = "."
|
||||
|
||||
if file != "DEFAULT"
|
||||
## JSON schema for YAML-file validation
|
||||
schema = Schema("""{
|
||||
"properties": {
|
||||
"massModel": {
|
||||
"description": "type of train model",
|
||||
"type": "string",
|
||||
"enum": [ "mass_point", "homogeneous_strip" ]
|
||||
},
|
||||
"stepVariable": {
|
||||
"description": "variable of the linear multistep method",
|
||||
"type": "string",
|
||||
"enum": [ "distance", "time", "velocity" ]
|
||||
},
|
||||
"stepSize": {
|
||||
"description": "step size acording to stepVariable",
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"outputDetail": {
|
||||
"description": "Selecting the detail of the result",
|
||||
"type": "string",
|
||||
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ]
|
||||
},
|
||||
"outputFormat": {
|
||||
"description": "Output format",
|
||||
"type": "string",
|
||||
"enum": [ "julia_dict", "csv" ]
|
||||
},
|
||||
"outputDir": {
|
||||
"description": "Path for the CSV export",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}""")
|
||||
|
||||
settings = YAML.load(open(file))["settings"]
|
||||
|
||||
## validate the loaded file
|
||||
try
|
||||
validate(schema, settings)
|
||||
catch err
|
||||
println("Could not load settings file $file.\n Format is not recognized - using default as fall back.")
|
||||
settings = Dict()
|
||||
end
|
||||
|
||||
## set the variables if they exist in "settings"
|
||||
haskey(settings, "massModel") ? massModel = Symbol(settings["massModel"]) : nothing
|
||||
haskey(settings, "stepVariable") ? stepVariable = Symbol(settings["stepVariable"]) : nothing
|
||||
haskey(settings, "stepSize") ? stepSize = settings["stepSize"] : nothing
|
||||
haskey(settings, "approxLevel") ? approxLevel = settings["approxLevel"] : nothing
|
||||
haskey(settings, "outputDetail") ? outputDetail = Symbol(settings["outputDetail"]) : nothing
|
||||
haskey(settings, "outputFormat") ? outputFormat = Symbol(settings["outputFormat"]) : nothing
|
||||
haskey(settings, "outputDir") ? outputDir = settings["outputDir"] : nothing
|
||||
end
|
||||
|
||||
new(massModel, stepVariable, stepSize, approxLevel, outputDetail, outputFormat, outputDir)
|
||||
|
||||
end #function Settings() # constructor
|
||||
|
||||
end #struct Settings
|
||||
|
||||
"""
|
||||
Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them.
|
||||
"""
|
||||
function checkAndSetInput!(train::Dict, path::Dict, settings::Settings)
|
||||
checkAndSetTrain!(train)
|
||||
checkAndSetPath!(path)
|
||||
|
||||
if settings.outputDetail == :points_of_interest && !haskey(path, :pointsOfInterest)
|
||||
throw(DomainError(settings.outputDetail, "INFO at checking the input for settings and path:\n
|
||||
settings[:outputDetail] is 'points of interest' but the path does not for pointsOfInterest."))
|
||||
end
|
||||
return (train, path)
|
||||
end #function checkAndSetInput!
|
||||
|
||||
"""
|
||||
Read the train information from a YAML file, save it in a train Dict and return it.
|
||||
"""
|
||||
function checkAndSetTrain!(train::Dict)
|
||||
# check train information from input dictionary
|
||||
|
||||
checkAndSetString!(train, "train", :name, "") # train's name
|
||||
# add train's identifier if not existing
|
||||
if !(haskey(train, :id) && train[:id]!=nothing)
|
||||
merge!(train, Dict(:id =>1))
|
||||
end
|
||||
checkAndSetString!(train, "train", :type, "passenger", ["passenger", "freight"]) # train type "passenger" or "freight"
|
||||
|
||||
checkAndSetPositiveNumberWithDifferentNames!(train, "train", :length, :l_train, "m", 20.0) # total length (in m)
|
||||
# TODO: or just use: checkAndSetPositiveNumber!(train, "train", :length, "m", 20.0)
|
||||
|
||||
checkAndSetSpeedLimit!(train) # train's speed limit (in m/s)
|
||||
checkAndSetBrakingAcceleration!(train) # a_braking
|
||||
|
||||
checkAndSetPositiveNumber!(train, "train", :m_td, "kg", 80000) # mass on the traction unit's driving axles (in kg)
|
||||
checkAndSetPositiveNumber!(train, "train", :m_tc, "kg", 0.0) # mass on the traction unit's carrying axles (in kg)
|
||||
checkAndSetSum!(train, "train", :m_t, :m_td, :m_tc) # mass of the traction unit (in kg)
|
||||
|
||||
checkAndSetPositiveNumber!(train, "train", :m_w, "kg", 0.0) # mass of the set of wagons (consist) (in kg)
|
||||
checkAndSetSum!(train, "train", :m_train, :m_t, :m_w) # total mass (in kg)
|
||||
if train[:m_train] <= 0.0
|
||||
error("ERROR at checking the input for the train: The train's mass has to be higher than 0.0 kg.")
|
||||
end
|
||||
|
||||
checkAndSetRotationMassFactors!(train)
|
||||
checkAndSetTractiveEffortVelocityPairs!(train) # pairs of velocity and tractive effort
|
||||
|
||||
# coefficients for the vehicle resistance of the traction unit
|
||||
checkAndSetRealNumber!(train, "train", :Δv_t, "m/s", 15.0/3.6) # coefficient for velocitiy difference between traction unit and outdoor air (in m/s)
|
||||
checkAndSetPositiveNumber!(train, "train", :f_Rtd0, "‰", 0.0) # coefficient for basic resistance due to the traction units driving axles (in ‰)
|
||||
checkAndSetPositiveNumber!(train, "train", :f_Rtc0, "‰", 0.0) # coefficient for basic resistance due to the traction units carring axles (in ‰)
|
||||
checkAndSetPositiveNumber!(train, "train", :F_Rt2, "N", 0.0) # coefficient for air resistance of the traction units (in N)
|
||||
|
||||
# coefficients for the vehicle resistance of the set of wagons (consist)
|
||||
checkAndSetRealNumber!(train, "train", :Δv_w, "m/s", getDefault_Δv_w(train[:type])) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
|
||||
checkAndSetPositiveNumber!(train, "train", :f_Rw0, "‰", 0.0) # coefficient for basic resistance of the set of wagons (consist) (in ‰)
|
||||
checkAndSetPositiveNumber!(train, "train", :f_Rw1, "‰", 0.0) # coefficient for the consists resistance to rolling (in ‰)
|
||||
checkAndSetPositiveNumber!(train, "train", :f_Rw2, "‰", 0.0) # coefficient fo the consistsr air resistance (in ‰)
|
||||
|
||||
# inform the user about keys of the input dictionary that are not used in this tool
|
||||
usedKeys = [:name, :id, :type,
|
||||
:length, :l_train, :v_limit, :v_limit_kmh, :a_braking,
|
||||
:m_train, :m_t, :m_td, :m_tc, :m_w,
|
||||
:ξ_train, :ξ_t, :ξ_w, :rotationMassFactor_train, :rotationMassFactor_t, :rotationMassFactor_w,
|
||||
:tractiveEffortVelocityPairs, :F_T_pairs, :F_T_pairs_kmh,
|
||||
:f_Rtd0, :f_Rtc0, :F_Rt2, :Δv_t,
|
||||
:f_Rw0, :f_Rw1, :f_Rw2, :Δv_w]
|
||||
informAboutUnusedKeys(collect(keys(train)), usedKeys::Vector{Symbol}, "train")
|
||||
|
||||
return train
|
||||
end #function checkAndSetTrain!
|
||||
|
||||
function checkAndSetPath!(path::Dict)
|
||||
# check path information from input dictionary
|
||||
|
||||
checkAndSetString!(path, "path", :name, "")
|
||||
# TODO checkId ? path[:id] # path identifier
|
||||
checkAndSetSections!(path)
|
||||
checkAndSetPOIs!(path)
|
||||
|
||||
# inform the user about keys of the input dictionary that are not used in this tool
|
||||
usedKeys = [:name,
|
||||
:sections, :sectionStarts, :sectionStarts_kmh,
|
||||
:pointsOfInterest]
|
||||
informAboutUnusedKeys(collect(keys(path)), usedKeys::Vector{Symbol}, "path")
|
||||
|
||||
return path
|
||||
end # function checkAndSetPath!
|
||||
|
||||
function checkAndSetBool!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::Bool)
|
||||
if haskey(dictionary,key) && dictionary[key]!=nothing
|
||||
if typeof(dictionary[key]) != Bool
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of the key ",String(key)," is not correct. The value has to be of type Bool.")
|
||||
end
|
||||
else
|
||||
merge!(dictionary, Dict(key => defaultValue))
|
||||
defaultValue && println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," or its value is missing. Therefore ",String(key),"=",dictionary[key]," is assumed and used.")
|
||||
end
|
||||
return dictionary
|
||||
end #function checkAndSetBool!
|
||||
|
||||
function checkAndSetPositiveNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real)
|
||||
if haskey(dictionary,key) && dictionary[key]!=nothing
|
||||
if typeof(dictionary[key]) <: Real && dictionary[key] >= 0.0
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.")
|
||||
end
|
||||
else
|
||||
merge!(dictionary, Dict(key => default))
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default," ",unit," will be assumed and used." )
|
||||
end
|
||||
|
||||
return dictionary
|
||||
end #function checkAndSetPositiveNumber!
|
||||
|
||||
# first method without a default value
|
||||
function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictionaryType::String, mainKey::Symbol, alternativeKey::Symbol, unit::String)
|
||||
mainKey_temp = -1.0
|
||||
alternativeKey_temp = -1.0
|
||||
|
||||
if haskey(dictionary, mainKey) && dictionary[mainKey]!=nothing
|
||||
if typeof(dictionary[mainKey]) <: Real && dictionary[mainKey] >= 0.0
|
||||
mainKey_temp = dictionary[mainKey]
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",mainKey," is no real floating point number >=0.0.")
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(dictionary, alternativeKey) && dictionary[alternativeKey]!=nothing
|
||||
if typeof(dictionary[alternativeKey]) <: Real && dictionary[alternativeKey] >= 0.0
|
||||
alternativeKey_temp = dictionary[alternativeKey]
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",alternativeKey," is no real floating point number >=0.0.")
|
||||
end
|
||||
else
|
||||
delete!(dictionary, alternativeKey)
|
||||
end
|
||||
|
||||
if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0
|
||||
difference = abs(mainKey_temp - alternativeKey_temp)
|
||||
if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
|
||||
delete!(dictionary, alternativeKey)
|
||||
println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference," ",unit,". The value ",String(mainKey),"=",default," ",unit," is used." )
|
||||
end
|
||||
elseif mainKey_temp >= 0.0
|
||||
# do nothing
|
||||
elseif alternativeKey_temp >= 0.0
|
||||
merge!(dictionary, Dict(mainKey => alternativeKey_temp))
|
||||
else
|
||||
# do nothing
|
||||
end
|
||||
|
||||
return dictionary
|
||||
end #function checkAndSetPositiveNumberWithDifferentNames!
|
||||
|
||||
# second method with a default value
|
||||
function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictionaryType::String, mainKey::Symbol, alternativeKey::Symbol, unit::String, default::Real)
|
||||
mainKey_temp = -1.0
|
||||
alternativeKey_temp = -1.0
|
||||
|
||||
if haskey(dictionary, mainKey) && dictionary[mainKey]!=nothing
|
||||
if typeof(dictionary[mainKey]) <: Real && dictionary[mainKey] >= 0.0
|
||||
mainKey_temp = dictionary[mainKey]
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",mainKey," is no real floating point number >=0.0.")
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(dictionary, alternativeKey) && dictionary[alternativeKey]!=nothing
|
||||
if typeof(dictionary[alternativeKey]) <: Real && dictionary[alternativeKey] >= 0.0
|
||||
alternativeKey_temp = dictionary[alternativeKey]
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",alternativeKey," is no real floating point number >=0.0.")
|
||||
end
|
||||
else
|
||||
delete!(dictionary, alternativeKey)
|
||||
end
|
||||
|
||||
if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0
|
||||
difference = abs(mainKey_temp - alternativeKey_temp)
|
||||
if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
|
||||
delete!(dictionary, alternativeKey)
|
||||
println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference," ",unit,". The value ",String(mainKey),"=",default," ",unit," is used." )
|
||||
end
|
||||
elseif mainKey_temp >= 0.0
|
||||
# do nothing
|
||||
elseif alternativeKey_temp >= 0.0
|
||||
merge!(dictionary, Dict(mainKey => alternativeKey_temp))
|
||||
else
|
||||
# set a default value
|
||||
merge!(dictionary, Dict(mainKey, default))
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",mainKey," or its value is missing. Therefore the value ",String(mainKey),"=",default," ",unit," is used." )
|
||||
end
|
||||
|
||||
return dictionary
|
||||
end #function checkAndSetPositiveNumberWithDifferentNames!
|
||||
|
||||
function checkAndSetRealNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real)
|
||||
if haskey(dictionary,key) && dictionary[key]!=nothing
|
||||
if typeof(dictionary[key]) <: Real
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real number.")
|
||||
end
|
||||
else
|
||||
merge!(dictionary, Dict(key => default))
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default," ",unit," will be assumed and used." )
|
||||
end
|
||||
|
||||
return dictionary
|
||||
end #function checkAndSetRealNumber!
|
||||
|
||||
function checkAndSetSum!(dictionary::Dict, dictionaryType::String, sum::Symbol, summand1::Symbol, summand2::Symbol)
|
||||
if haskey(dictionary,sum) && dictionary[sum]!=nothing
|
||||
if typeof(dictionary[sum]) <: Real && dictionary[sum] >= 0.0
|
||||
difference = abs(dictionary[sum] - (dictionary[summand1]+dictionary[summand2]))
|
||||
if difference > 1/(10^approxLevel)
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is not exactly the sum of ",String(summand1)," and ",String(summand2),". It differs by ",difference,".")
|
||||
end
|
||||
else
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is no real floating point number >=0.0.")
|
||||
end
|
||||
else
|
||||
merge!(dictionary, Dict(sum => dictionary[summand1]+dictionary[summand2]))
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",String(sum)," is missing. Therefore ",String(sum)," = ",String(summand1)," + ",String(summand2)," = ",dictionary[sum]," was calculated and will be used." )
|
||||
end
|
||||
|
||||
return dictionary
|
||||
end #function checkAndSetSum!
|
||||
|
||||
function checkAndSetString!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::String, validValues::Vector{String})
|
||||
# TODO change checkAndAddString! to checkAndAddSymbol! ?
|
||||
if haskey(dictionary,key) && dictionary[key]!=nothing
|
||||
value = dictionary[key]
|
||||
if typeof(value) == String
|
||||
for validValue in validValues
|
||||
if value == validValue
|
||||
return dictionary
|
||||
end
|
||||
end
|
||||
end
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be one of the following String values: ", validValues)
|
||||
else
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. It has to be one of the following String values: ", validValues,". For this calculation the default value '",defaultValue,"' will be used.")
|
||||
merge!(dictionary, Dict(key => defaultValue))
|
||||
end
|
||||
return dictionary
|
||||
end #function checkAndSetString!
|
||||
# second method of function checkAndSetString! without validValues
|
||||
function checkAndSetString!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::String)
|
||||
if haskey(dictionary,key) && dictionary[key]!=nothing
|
||||
value = dictionary[key]
|
||||
if typeof(value) == String
|
||||
return dictionary
|
||||
end
|
||||
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be of type String.")
|
||||
else
|
||||
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. For this calculation the default value '",defaultValue,"' will be used.")
|
||||
merge!(dictionary, Dict(key => defaultValue))
|
||||
end
|
||||
return dictionary
|
||||
end #function checkAndSetString!
|
||||
|
||||
function checkAndSetSpeedLimit!(train::Dict)
|
||||
v_limit_temp = 0.0
|
||||
v_limit_kmh_temp = 0.0
|
||||
|
||||
if haskey(train, :v_limit) && train[:v_limit]!=nothing
|
||||
if typeof(train[:v_limit]) <: Real && train[:v_limit] >= 0.0
|
||||
v_limit_temp = train[:v_limit]
|
||||
else
|
||||
error("ERROR at checking the input for the train: The value of v_limit is no real floating point number >=0.0.")
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(train, :v_limit_kmh) && train[:v_limit_kmh]!=nothing
|
||||
if typeof(train[:v_limit_kmh]) <: Real && train[:v_limit_kmh] >= 0.0
|
||||
v_limit_kmh_temp = train[:v_limit_kmh]
|
||||
else
|
||||
error("ERROR at checking the input for the train: The value of v_limit_kmh is no real floating point number >=0.0.")
|
||||
end
|
||||
else
|
||||
delete!(train, :v_limit_kmh)
|
||||
end
|
||||
|
||||
if v_limit_temp > 0.0 && v_limit_kmh_temp > 0.0
|
||||
difference = abs(v_limit_temp - v_limit_kmh_temp/3.6)
|
||||
if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
|
||||
delete!(train, :v_limit_kmh)
|
||||
println("WARNING at checking the input for the train: The values of v_limit and v_limit_kmh differ by ",difference," m/s. The value v_limit=",v_limit_temp," m/s is used." )
|
||||
end
|
||||
elseif v_limit_temp > 0.0
|
||||
# do nothing
|
||||
elseif v_limit_kmh_temp > 0.0
|
||||
merge!(train, Dict(:v_limit => v_limit_kmh_temp/3.6))
|
||||
else
|
||||
# set a default value
|
||||
merge!(train, Dict(:v_limit, 1000.0/3.6)) # set speed limit to 1000 km/h
|
||||
println("INFO at checking the input for the train: There is no value for the trains speed limit (v_limit or v_limit_kmh). The value v_limit=1000 km/h =",train[:v_limit]," m/s is used." )
|
||||
end
|
||||
|
||||
return train
|
||||
end #function checkAndSetSpeedLimit!
|
||||
|
||||
function checkAndSetBrakingAcceleration!(train::Dict)
|
||||
if haskey(train, :a_braking) && train[:a_braking]!=nothing
|
||||
if typeof(train[:a_braking]) <: Real
|
||||
if train[:a_braking] > 0.0
|
||||
train[:a_braking] =-train[:a_braking]
|
||||
println("INFO at checking the input for the train: The value for a_braking is >0.0. The braking acceleration has to be <0.0. Therefore a_braking=",train[:a_braking]," m/s^2 is used." )
|
||||
elseif train[:a_braking] == 0.0
|
||||
error("ERROR at checking the input for the train: The value for a_braking is 0.0. The braking acceleration has to be <0.0.")
|
||||
end
|
||||
else
|
||||
error("ERROR at checking the input for the train: The value for a_braking is no real floating point number <0.0.")
|
||||
end
|
||||
else
|
||||
# set a default value depending on the train type
|
||||
if train[:type] == "freight"
|
||||
a_braking = -0.225
|
||||
elseif train[:type] == "passenger"
|
||||
a_braking = -0.375
|
||||
#elseif train[:type] == "passengerSuburban"
|
||||
# a_braking = -0.525
|
||||
# TODO: add suburban trains to train type?
|
||||
end
|
||||
|
||||
merge!(train, Dict(:a_braking => a_braking))
|
||||
println("INFO at checking the input for the train: The key for a_braking is missing. Because of the train type ",train[:type]," a_braking=",a_braking," m/s^2 will be assumed and used." )
|
||||
end
|
||||
|
||||
return train
|
||||
end #function checkAndSetBrakingAcceleration!
|
||||
|
||||
function checkAndSetRotationMassFactors!(train::Dict)
|
||||
checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_train, :rotationMassFactor_train, "")
|
||||
checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_t, :rotationMassFactor_t, "")
|
||||
checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_w, :rotationMassFactor_w, "")
|
||||
if haskey(train, :ξ_train) && train[:ξ_train]!=nothing
|
||||
if train[:ξ_train]>0.0
|
||||
if haskey(train, :ξ_t) && train[:ξ_t]!=nothing && train[:ξ_t]>0.0 && (train[:m_w]==0.0 || (haskey(train, :ξ_w) && train[:ξ_w]!=nothing))
|
||||
# TODO: is && train[:ξ_t]>0.0 necessary here?
|
||||
difference = abs(train[:ξ_train] - (train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train])
|
||||
if difference > 1/(10^approxLevel)
|
||||
error("ERROR at checking the input for the train: The value of ξ_train is not exactly ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train. It differs by ",difference,".")
|
||||
end
|
||||
end
|
||||
else
|
||||
error("ERROR at checking the input for the train: The value of :ξ_train is no real floating point number >0.0.")
|
||||
end
|
||||
else
|
||||
checkAndSetPositiveNumber!(train, "train", :ξ_t, "", 1.09)
|
||||
|
||||
if train[:m_w]>0.0
|
||||
default_ξ_w = 1.06
|
||||
else
|
||||
default_ξ_w = 0.0
|
||||
end
|
||||
checkAndSetPositiveNumber!(train, "train", :ξ_w, "", default_ξ_w)
|
||||
|
||||
|
||||
ξ_train=(train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train] # rotation mass factor of the whole train (without unit)
|
||||
if ξ_train <= 0.0
|
||||
error("ERROR at checking the input for the train: The train's rotations mass factor has to be higher than 0.0 kg.")
|
||||
end
|
||||
merge!(train, Dict(:ξ_train => ξ_train))
|
||||
end
|
||||
|
||||
return train
|
||||
end #function checkAndSetRotationMassFactors!
|
||||
|
||||
function checkAndSetTractiveEffortVelocityPairs!(train::Dict) # pairs of velocity and tractive effort
|
||||
if haskey(train,:tractiveEffortVelocityPairs) && train[:tractiveEffortVelocityPairs]!=nothing
|
||||
pairs = train[:tractiveEffortVelocityPairs]
|
||||
velocityMultiplier = 1.0
|
||||
|
||||
if (haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing) && (haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing)
|
||||
println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs, F_T_pairs and F_T_pairs_kmh. The values for tractiveEffortVelocityPairs are used." )
|
||||
|
||||
elseif haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing
|
||||
println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs. The values for tractiveEffortVelocityPairs are used." )
|
||||
|
||||
elseif haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing
|
||||
println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs_kmh. The values for tractiveEffortVelocityPairs are used." )
|
||||
end
|
||||
|
||||
elseif haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing
|
||||
pairs = train[:F_T_pairs]
|
||||
velocityMultiplier = 1.0
|
||||
|
||||
if haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing
|
||||
println("WARNING at checking the input for the train: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." )
|
||||
end
|
||||
|
||||
elseif haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing
|
||||
velocityMultiplier = 1000/3600
|
||||
pairs=[]
|
||||
for row in 1:length(train[:F_T_pairs_kmh])
|
||||
push!(pairs, [train[:F_T_pairs_kmh][row][1]*velocityMultiplier, train[:F_T_pairs_kmh][row][2]])
|
||||
end # for
|
||||
|
||||
else
|
||||
error("ERROR at checking the input for the train: There has to be the key tractiveEffortVelocityPairs filled with a list of pairs of velocity and tractive effort.")
|
||||
end # if
|
||||
|
||||
# check if the elements of the array have the correct type
|
||||
errorDetected=false
|
||||
|
||||
for row in 1:length(pairs)
|
||||
if typeof(pairs[row][1]) <: Real && pairs[row][1]>=0.0
|
||||
else
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the train: The speed value of train[:tractiveEffortVelocityPairs] in row ", row ," is no real floating point number >=0.0.")
|
||||
end
|
||||
if typeof(pairs[row][2]) <: Real && pairs[row][2]>=0.0
|
||||
else
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the train: The tractive effort value of train[:tractiveEffortVelocityPairs] in row ", row ," is no real floating point number >=0.0.")
|
||||
end
|
||||
|
||||
if row>=2 && pairs[row][1] <= pairs[row-1][1]
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the train: The speed value of train[:tractiveEffortVelocityPairs] in row ", row ," (v=",pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",pairs[row-1][1]," m/s).")
|
||||
end
|
||||
end # for
|
||||
if errorDetected
|
||||
error("ERROR at checking the input for the train: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.")
|
||||
end
|
||||
|
||||
# create tractiveEffortVelocityPairs
|
||||
if pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used
|
||||
newPairs=[]
|
||||
push!(newPairs, [0.0, pairs[1][2]])
|
||||
println("INFO at checking the input for the train: The tractive effort for v=0.0 m/s is missing. Therefore the first given value F_T(v=",pairs[1][1]," m/s)=",pairs[1][2]," N will be used." )
|
||||
for row in 1:length(pairs)
|
||||
push!(newPairs, [pairs[row][1], pairs[row][2]])
|
||||
end # for
|
||||
merge!(train, Dict(:tractiveEffortVelocityPairs => newPairs))
|
||||
else
|
||||
merge!(train, Dict(:tractiveEffortVelocityPairs => pairs))
|
||||
end
|
||||
|
||||
if length(pairs[1])>2
|
||||
println("INFO according the train dictionary: Only the first two columns of train[:tractiveEffortVelocityPairs] are used in this tool.")
|
||||
end
|
||||
|
||||
return train
|
||||
end #function checkAndSetTractiveEffortVelocityPairs!
|
||||
|
||||
function getDefault_Δv_w(type::String) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
|
||||
if type == "passenger"
|
||||
# TODO if different passenger or freight trains are posiible, use: if startswith(type, "passenger"). exanples: passengerLocomotivehauled and passengerMotorCoachTrain
|
||||
Δv_w=15.0/3.6
|
||||
elseif type == "freight"
|
||||
Δv_w=0.0
|
||||
end # if
|
||||
|
||||
return Δv_w
|
||||
end #function getDefault_Δv_w!
|
||||
|
||||
function checkAndSetSections!(path::Dict)
|
||||
# check the section information
|
||||
if haskey(path,:sections) && path[:sections]!=nothing
|
||||
# TODO: check typeof(path[:sections]) == Dict
|
||||
if (haskey(path, :sectionStarts) && path[:sectionStarts]!=nothing) && (haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing)
|
||||
println("WARNING at checking the input for the path: There are values for sections, sectionStarts and sectionStarts_kmh. The dictionary sections is used." )
|
||||
|
||||
elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing
|
||||
println("WARNING at checking the input for the path: There are values for sections and sectionStarts. The dictionary sections is used." )
|
||||
|
||||
elseif haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing
|
||||
println("WARNING at checking the input for the path: There are values for sections and sectionStarts_kmh. The dictionary sections is used." )
|
||||
end
|
||||
elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing
|
||||
# TODO: check typeof(path[:sections]) == Array
|
||||
createSections!(path, :sectionStarts)
|
||||
|
||||
if haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing
|
||||
println("WARNING at checking the input for the path: There are values for sectionStarts and sectionStarts_kmh. The array sectionStarts is used." )
|
||||
end
|
||||
elseif haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing
|
||||
# TODO: check typeof(path[:sections]) == Array
|
||||
createSections!(path, :sectionStarts_kmh)
|
||||
else
|
||||
error("ERROR at checking the input for the path: The Symbol :sections is missing. It has to be added with a list of sections. Each has to be a dictionary with the keys :s_tart, :s_end, :v_limit and :f_Rp.")
|
||||
section = Dict(:s_start => 0.0,
|
||||
:s_end => 15.0,
|
||||
:v_limit => 1000.0/3.6,
|
||||
:f_Rp => 0.0)
|
||||
merge!(path, Dict(:sections => [section]))
|
||||
return path
|
||||
end
|
||||
|
||||
sections = path[:sections]
|
||||
|
||||
checkedSections = []
|
||||
increasing = false
|
||||
decreasing = false
|
||||
|
||||
#TODO: throw error for each issue or collect the issues and use the Bool errorDetected like in createSections?
|
||||
|
||||
# check values for section==1
|
||||
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_start, "m", 0.0) # first point of the section (in m)
|
||||
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_end, "m", 0.0) # first point of the next section (in m)
|
||||
checkAndSetPositiveNumber!(sections[1], "path[:sections][1]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s)
|
||||
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :f_Rp, "‰", 0.0) # specific path resistance of the section (in ‰)
|
||||
|
||||
push!(checkedSections, sections[1])
|
||||
|
||||
if sections[1][:s_start] < sections[1][:s_end]
|
||||
increasing = true
|
||||
elseif sections[1][:s_start] > sections[1][:s_end]
|
||||
decreasing = true
|
||||
else
|
||||
pop!(checkedSections)
|
||||
println("WARNING at checking the input for the path: The first section of :sections has the same position for starting and end point. The section will be deleted and not used in the tool.")
|
||||
end
|
||||
|
||||
|
||||
for sectionNr in 2:length(sections)
|
||||
checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :s_start, "m", sections[sectionNr-1][:s_end]) # first point of the section (in m)
|
||||
# TODO how to define default values? which has to be checked and defined fist? s_end-1 and s_start need each other as default values
|
||||
#if sectionNr < length(sections) && haskey(sections[sectionNr], :s_start) && sections[sectionNr][:s_start]!=nothing && typeof(sections[sectionNr][:s_start]) <: Real
|
||||
# defaultEnd = sections[sectionNr+1][:s_start]
|
||||
#end
|
||||
defaultEnd = sections[sectionNr][:s_start] # so the default value for s_end creates a sections of lenght=0.0 #TODO should be changed!
|
||||
checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :s_end, "m", defaultEnd) # first point of the next section (in m)
|
||||
checkAndSetPositiveNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s)
|
||||
checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :f_Rp, "‰", 0.0) # specific path resistance of the section (in ‰)
|
||||
|
||||
push!(checkedSections, sections[sectionNr])
|
||||
|
||||
# compare the section's start and end position
|
||||
if sections[sectionNr][:s_start] < sections[sectionNr][:s_end]
|
||||
increasing = true
|
||||
elseif sections[sectionNr][:s_start] > sections[sectionNr][:s_end]
|
||||
decreasing = true
|
||||
else
|
||||
pop!(checkedSections)
|
||||
println("INFO at checking the input for the path: The ",sectionNr,". section of :sections has the same position for starting and end point. The section will be deleted and not used in the tool.")
|
||||
end
|
||||
if increasing && decreasing
|
||||
error("ERROR at checking the input for the path: The positions of the :sections are not increasing/decreasing consistently. The direction in the ",sectionNr,". section differs from the previous.")
|
||||
end
|
||||
|
||||
|
||||
if length(checkedSections)>1 && sections[sectionNr][:s_start] != checkedSections[end-1][:s_end]
|
||||
error("ERROR at checking the input for the path[:sections]: The starting position of the ",section,". section (s=",sections[sectionNr][:s_start]," m) does not euqal the last position of the previous section(s=",checkedSections[end-1][:s_end]," m). The sections have to be sequential.")
|
||||
# TODO: maybe if there is a gab create a new section and only if there a jumps in the wrong direction throw an error?
|
||||
end
|
||||
end #for
|
||||
|
||||
return path
|
||||
end #function checkAndSetSections!
|
||||
|
||||
function createSections!(path::Dict, key::Symbol)
|
||||
# read the section starting positions and corresponding information
|
||||
if key == :sectionStarts
|
||||
sectionStartsArray = path[:sectionStarts]
|
||||
conversionFactor = 1.0 # conversion factor between the units m/s and m/s
|
||||
|
||||
if haskey(path,:sectionStarts) && path[:sectionStarts_kmh]!=nothing
|
||||
println("WARNING at checking the input for the path: There are values for sectionStarts and sectionStarts_kmh. The values for sectionStarts are used." )
|
||||
end
|
||||
elseif key == :sectionStarts_kmh
|
||||
sectionStartsArray = path[:sectionStarts_kmh]
|
||||
conversionFactor = 1/3.6 # conversion factor between the units km/h and m/s
|
||||
else
|
||||
error("ERROR at checking the input for the path: The keyword sectionStarts or sectionStarts_kmh is missing. The sections can not be created without them.")
|
||||
end # if
|
||||
|
||||
# check if the array is correct and if elements of the array have the correct type and valid values
|
||||
errorDetected = false
|
||||
if length(sectionStartsArray)<2
|
||||
error("ERROR at checking the input for the path: The keyword ",key," needs at least two rows for two points each with the three columns [s, v_limit, f_Rp].")
|
||||
end
|
||||
|
||||
for row in 1:length(sectionStartsArray)
|
||||
if length(sectionStartsArray[row])>=3
|
||||
if length(sectionStartsArray[row])>3
|
||||
println("INFO at checking the input for the path: Only the first three columns of sectionStartsArray are used in this tool.")
|
||||
end
|
||||
else
|
||||
error("ERROR at checking the input for the path: The keyword ",key," needs to be filled with the three columns [s, v_limit, f_Rp].")
|
||||
end
|
||||
|
||||
if !(typeof(sectionStartsArray[row][1]) <: Real)
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the path: The position value (column 1) of ",key," in row ", row ," is no real floating point number.")
|
||||
end
|
||||
if !(typeof(sectionStartsArray[row][2]) <: Real && sectionStartsArray[row][2] >= 0.0)
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the path: The speed limit (column 2) of ",key," in row ", row ," is no real floating point number >=0.0.")
|
||||
end
|
||||
if !(typeof(sectionStartsArray[row][3]) <: Real)
|
||||
errorDetected=true
|
||||
println("ERROR at checking the input for the path: The tractive effort value (column 3) of ",key," in row ", row ," is no real floating point number.")
|
||||
end
|
||||
end # for
|
||||
if errorDetected
|
||||
error("ERROR at checking the input for the path: The values of ",key," have to be corrected.")
|
||||
end
|
||||
|
||||
|
||||
sections = []
|
||||
for row in 2:length(sectionStartsArray)
|
||||
s_start = sectionStartsArray[row-1][1] # first point of the section (in m)
|
||||
s_end = sectionStartsArray[row][1] # first point of the next section (in m)
|
||||
v_limit = sectionStartsArray[row-1][2]*conversionFactor # paths speed limt (in m/s)
|
||||
f_Rp = sectionStartsArray[row-1][3] # specific path resistance of the section (in ‰)
|
||||
|
||||
section = Dict(:s_start => s_start,
|
||||
:s_end => s_end,
|
||||
:v_limit => v_limit,
|
||||
:f_Rp => f_Rp)
|
||||
push!(sections, section)
|
||||
end # for
|
||||
# s_start in first entry defines the path's beginning
|
||||
# s_end in last entry defines the path's ending
|
||||
|
||||
merge!(path, Dict(:sections => sections))
|
||||
return path
|
||||
end #function createSections!
|
||||
|
||||
function checkAndSetPOIs!(path::Dict)
|
||||
# read the section starting positions and corresponding information
|
||||
if haskey(path, :pointsOfInterest)
|
||||
if path[:pointsOfInterest] != nothing
|
||||
pointsOfInterest = path[:pointsOfInterest]
|
||||
|
||||
sortingNeeded = false
|
||||
errorDetected = false
|
||||
for element in 1:length(pointsOfInterest)
|
||||
if typeof(pointsOfInterest[element]) <: Real
|
||||
if element > 1
|
||||
if pointsOfInterest[element] < pointsOfInterest[element-1]
|
||||
sortingNeeded = true
|
||||
println("INFO at checking the input for the path: The point of interest in element ", element ," (",pointsOfInterest[element]," m) has to be higher than the value of the previous element (",pointsOfInterest[element-1]," m). The points of interest will be sorted.")
|
||||
end
|
||||
end
|
||||
else
|
||||
errorDetected = true
|
||||
println("ERROR at checking the input for the path: The point of interest in element ", element ," is no real floating point number.")
|
||||
end
|
||||
end # for
|
||||
|
||||
if errorDetected
|
||||
error("ERROR at checking the input for the path: The values of pointsOfInterest have to be corrected.")
|
||||
end
|
||||
if sortingNeeded == true
|
||||
sort!(pointsOfInterest)
|
||||
end
|
||||
|
||||
copiedPOIs = []
|
||||
for element in 1:length(pointsOfInterest)
|
||||
if element == 1
|
||||
push!(copiedPOIs, pointsOfInterest[element])
|
||||
elseif element > 1 && pointsOfInterest[element] > pointsOfInterest[element-1]
|
||||
push!(copiedPOIs, pointsOfInterest[element])
|
||||
end
|
||||
end # for
|
||||
path[:pointsOfInterest] = copiedPOIs
|
||||
|
||||
else
|
||||
println("INFO at checking the input for the path: The key pointsOfInterest exists but without values.")
|
||||
delete!(path, :pointsOfInterest)
|
||||
end
|
||||
end
|
||||
|
||||
return path
|
||||
end #function checkAndSetPOIs!
|
||||
|
||||
#function informAboutUnusedKeys(dictionary::Dict, dictionaryType::String) # inform the user which Symbols of the input dictionary are not used in this tool
|
||||
function informAboutUnusedKeys(allKeys::AbstractVector, usedKeys::Vector{Symbol}, dictionaryType::String) # inform the user which Symbols of the input dictionary are not used in this tool
|
||||
unusedKeys = []
|
||||
# find unused keys in allKeys
|
||||
for key in allKeys
|
||||
used = false
|
||||
for usedKey in usedKeys
|
||||
if key == usedKey
|
||||
used = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if !used
|
||||
push!(unusedKeys, key)
|
||||
end
|
||||
end
|
||||
|
||||
if length(unusedKeys)>0
|
||||
println("INFO at checking the input for the ",dictionaryType,": The following Keywords are not used in this tool:")
|
||||
for key in unusedKeys
|
||||
println(" - ",key)
|
||||
end
|
||||
end
|
||||
end #function informAboutUnusedKeys
|
Loading…
Reference in New Issue