Refactor input and import and set default values

development
Max Kannenberg 2022-04-08 17:30:34 +02:00
parent 5c9541775d
commit 9343e1cc74
8 changed files with 570 additions and 827 deletions

View File

@ -7,6 +7,6 @@ settings:
stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s) stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s)
operationModeMinimumRunningTime: true # operation mode "minimum running time" operationModeMinimumRunningTime: true # operation mode "minimum running time"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "CSV" # output as "julia dictionary" or as "CSV" typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
detailOfOutput: "everything" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"?
csvDirectory: "~/Desktop/TrainRun" csvDirectory: "~/Desktop/TrainRun"

View File

@ -2,7 +2,7 @@
--- ---
train: train:
name: "V 90 with 10 ore wagons of type Facs 124" # (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 and https://dybas.de/dybas/gw/gw_f_1/g124.html) name: "V 90 with 10 ore wagons of type Facs 124" # (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 and https://dybas.de/dybas/gw/gw_f_1/g124.html)
l_train: 205.3 # in m (source: FBS: DB 290 with 10x Facs124) length: 205.3 # in m (source: FBS: DB 290 with 10x Facs124)
m_td: 80000 # mass on driving axles of the traction unit in kg (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) m_td: 80000 # mass on driving axles of the traction unit in kg (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90)
m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90)
m_w: 850000 # mass of the consist (set of wagons) in kg (source: FBS: 10x Facs124) m_w: 850000 # mass of the consist (set of wagons) in kg (source: FBS: 10x Facs124)
@ -10,7 +10,7 @@ train:
rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit)
rotationMassFactor_w: 1.03 # (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Güterwagenzug beladen" -> 1.03 to 1.04) rotationMassFactor_w: 1.03 # (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Güterwagenzug beladen" -> 1.03 to 1.04)
powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90)
trainType: freight # "freight" or "passenger" or "motorCoachTrain" (source: https://dybas.de/dybas/gw/gw_f_1/g124.html) type: freight # "freight" or "passenger" (source: https://dybas.de/dybas/gw/gw_f_1/g124.html)
v_limit: # in m/s v_limit: # in m/s
v_limit_kmh: 80 # in km/h (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) v_limit_kmh: 80 # in km/h (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90)
a_braking: -0.4124 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 290 with with 10x Facs124) a_braking: -0.4124 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 290 with with 10x Facs124)

View File

@ -2,7 +2,7 @@
--- ---
train: train:
name: "Intercity 2 (Traxx P160 AC2 + double deck coaches)" # (source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario#Intercity_2 and https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) name: "Intercity 2 (Traxx P160 AC2 + double deck coaches)" # (source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario#Intercity_2 and https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn))
l_train: 152 # in m (source: FBS: DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) length: 152 # in m (source: FBS: DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2)
m_td: 84000 # mass on driving axles of the traction unit in kg (source: FBS: DB146.5) m_td: 84000 # mass on driving axles of the traction unit in kg (source: FBS: DB146.5)
m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: FBS: DB146.5) m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: FBS: DB146.5)
m_w: 309000 # mass of the consist (set of wagons) in kg (source: FBS: 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) m_w: 309000 # mass of the consist (set of wagons) in kg (source: FBS: 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2)
@ -10,7 +10,7 @@ train:
rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit)
rotationMassFactor_w: 1.06 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons) rotationMassFactor_w: 1.06 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons)
powerType: electric # diesel or electric (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) powerType: electric # diesel or electric (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale)
trainType: passenger # "freight" or "passenger" or "motorCoachTrain" (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) type: passenger # "freight" or "passenger" (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn))
v_limit: # in m/s v_limit: # in m/s
v_limit_kmh: 160 # in km/h (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) v_limit_kmh: 160 # in km/h (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale)
a_braking: -0.3507 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) a_braking: -0.3507 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2)

View File

@ -2,7 +2,7 @@
--- ---
train: train:
name: "Siemens Desiro Classic" # (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) name: "Siemens Desiro Classic" # (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
l_train: 41.7 # in m (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) length: 41.7 # in m (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
m_td: 52800 # mass on driving axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) m_td: 52800 # mass on driving axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
m_tc: 35200 # mass on carrying axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) m_tc: 35200 # mass on carrying axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
m_w: 0 # mass of the consist (set of wagons) in kg (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons) m_w: 0 # mass of the consist (set of wagons) in kg (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons)
@ -10,7 +10,7 @@ train:
rotationMassFactor_t: rotationMassFactor_t:
rotationMassFactor_w: rotationMassFactor_w:
powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
trainType: motorCoachTrain # "freight" or "passenger" or "motorCoachTrain" (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) type: passenger # "freight" or "passenger" (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
v_limit: # in m/s v_limit: # in m/s
v_limit_kmh: 120 # in km/h (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) v_limit_kmh: 120 # in km/h (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic)
a_braking: -0.4253 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 642) a_braking: -0.4253 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 642)

View File

@ -14,7 +14,7 @@
# TODO from 2022/01/22: use always copyCharacteristicSection and don't do it manually like "csModified=Dict(:id => csOriginal[:id], ..." three times # TODO from 2022/01/22: use always copyCharacteristicSection and don't do it manually like "csModified=Dict(:id => csOriginal[:id], ..." three times
# TODO from 2022/03/18: stateFlags need to be added to functions that add behavior sections # TODO from 2022/03/18: stateFlags need to be added to functions that add behavior sections
# TODO from 2022/03/21: consider previous speed limits during the coasting section in case F_R < 0.0 and the train is getting faster # TODO from 2022/03/21: consider previous speed limits during the coasting section in case F_R < 0.0 and the train is getting faster
# TODO from 2002/04/07: the train type is only devided in passenger and freight and not motorCoachTrain anymore because this is only used for EnergySaving. If EnergySaving will be reactivated it the train type also has to change from enum to String or Symbol
module EnergySaving module EnergySaving
# include modules of TrainRunCalc # include modules of TrainRunCalc

View File

@ -9,584 +9,36 @@ module Import
import YAML import YAML
export importYamlFiles, importYamlFile export importYamlFiles, importFromYaml
@enum trainType passenger=1 freight=2 motorCoachTrain=3
""" """
Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them. 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, settingsDirectory::String) function importYamlFiles(trainDirectory::String, pathDirectory::String, settingsDirectory::String)
train = importTrainFromYaml(trainDirectory) train = importFromYaml(:train, trainDirectory)
path = importPathFromYaml(pathDirectory) path = importFromYaml(:path, pathDirectory)
settings = importSettingsFromYaml(settingsDirectory) settings = importFromYaml(:settings, settingsDirectory)
return (train, path, settings) return (train, path, settings)
end #function importYamlFiles end #function importYamlFiles
""" """
Read the input information from one of the YAML files for train, path or settings, save it in a Dictionary and return it. Read the train information from a YAML file, save it in a Dict and return it.
""" """
function importYamlFile(dataType::Symbol, directory::String) function importFromYaml(dataType::Symbol, directory::String)
if dataType == :train dataSet = String(dataType)
return importTrainFromYaml(directory) data = YAML.load(open(directory))
elseif dataType == :path if collect(keys(data))[1] != dataSet
return importPathFromYaml(directory) error("ERROR at reading the ", dataSet, " yaml file: The data set is called ", collect(keys(data))[1]," and not ", dataSet, ".")
elseif dataType == :settings
return importSettingsFromYaml(directory)
else
error("Wrong dataType in function importYamlFile")
end end
end #function importYamlFile dataKeys = collect(keys(data[dataSet]))
dataKeys = collect(keys(data[dataSet]))
""" dataValues = collect(values(data[dataSet]))
Read the train information from a YAML file, save it in a train Dict and return it. dictionary = Dict()
""" for number in 1:length(dataKeys)
function importTrainFromYaml(trainDirectory::String) merge!(dictionary, Dict(Symbol(dataKeys[number]) => dataValues[number]))
data = YAML.load(open(trainDirectory))
name = getString!(data, "train", "name") # train's name
id=1 # train's identifier
type = getTrainType!(data) # "passenger" or "freight" or "motorCoachTrain"
trainLength = getPositiveNumber!(data, "train", "l_train", "m", true) # total length (in m)
v_limit = getSpeedLimit!(data) # train's speed limit (in m/s)
a_braking = get_a_braking!(data) # a_braking
m_td = getPositiveNumber!(data, "train", "m_td", "kg", true) # mass on the traction unit's driving axles (in kg)
m_tc = getPositiveNumber!(data, "train", "m_tc", "kg", false) # mass on the traction unit's carrying axles (in kg)
m_t=m_td+m_tc # mass of the traction unit (in kg)
m_w = getPositiveNumber!(data, "train", "m_w", "kg", false) # mass of the set of wagons (consist) (in kg)
m_train=m_t+m_w # total mass (in kg)
(ξ_train, ξ_t, ξ_w) = getRotationMassFactors!(data, m_train, m_t, m_w)
tractiveEffortVelocityPairs = getTractiveEffortVelocityPairs!(data) # pairs of velocity and tractive effort
# coefficients for the vehicle resistance of the traction unit
Δv_t=15.0/3.6 # coefficient for velocitiy difference between traction unit and outdoor air (in m/s)
f_Rtd0 = getPositiveNumber!(data, "train", "f_Rtd0", "", false) # coefficient for basic resistance due to the traction units driving axles (in ‰)
f_Rtc0 = getPositiveNumber!(data, "train", "f_Rtc0", "", false) # coefficient for basic resistance due to the traction units carring axles (in ‰)
F_Rt2 = getPositiveNumber!(data, "train", "F_Rt2", "N", false) # coefficient for air resistance of the traction units (in N)
# coefficients for the vehicle resistance of the set of wagons (consist)
Δv_w = get_Δv_w!(type) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
f_Rw0 = getPositiveNumber!(data, "train", "f_Rw0", "", false) # coefficient for basic resistance of the set of wagons (consist) (in ‰)
f_Rw1 = getPositiveNumber!(data, "train", "f_Rw1", "", false) # coefficient for the consists resistance to rolling (in ‰)
f_Rw2 = getPositiveNumber!(data, "train", "f_Rw2", "", false) # coefficient fo the consistsr air resistance (in ‰)
informAboutUnusedKeys(data, "train") # inform the user, which keywords of the imported data are not used in this tool
# create the train Dictionary
train= Dict(:name => name, # train's name
:id => id, # train's identifier
:type => type, # type of train "passenger" or "freight" or "motorCoachTrain"
#= 01/05 old without enum :type => type, # type of train "passenger" or "freight" or "motor coach train" =#
:length => trainLength, # total length (in m)
:v_limit => v_limit, # trains speed limit (in m/s)
:a_braking => a_braking, # braking acceleration (in m/s^2)
:m_train => m_train, # total mass (in kg)
:ξ_train => ξ_train, # rotation mass factor of the whole train (without unit)
# if not available use ξ_t and ξ_w
# traction unit
:m_t => m_t, # mass of the traction unit (in kg)
:m_td => m_td, # mass on the traction units driving axles (in kg)
:m_tc => m_tc, # mass on the traction units carrying axles (in kg)
:ξ_t => ξ_t, # rotation mass factor of the traction unit (without unit)
# in case ξ_train is not available
:tractiveEffortVelocityPairs => tractiveEffortVelocityPairs, # list of velocities and their corresponding tractive effort (in [m/s , N])
:f_Rtd0 => f_Rtd0, # coefficient for basic resistance due to the traction units driving axles (in ‰)
:f_Rtc0 => f_Rtc0, # coefficient for basic resistance due to the traction units carring axles (in ‰)
:F_Rt2 => F_Rt2, # coefficient for air resistance of the traction units (in N)
:Δv_t => Δv_t, # coefficient for velocitiy difference between traction unit and outdoor air (in m/s)
# set of wagons
:m_w => m_w, # mass of the set of wagons (in kg)
:ξ_w => ξ_w, # rotation mass factor of the set of wagons (without unit)
# in case ξ_train is not available
:f_Rw0 => f_Rw0, # coefficient for basic resistance of the set of wagons (in ‰)
:f_Rw1 => f_Rw1, # coefficient for resistance to rolling of the set of wagons (in ‰)
:f_Rw2 => f_Rw2, # coefficient for air resistance of the set of wagons (in ‰)
:Δv_w => Δv_w) # coefficient for velocitiy difference between set of wagons and outdoor air (in m/s)
return train
end #function importTrainFromYaml
function importPathFromYaml(pathDirectory::String)
# read path information from a YAML file, save it in a path Dict and return it
data = YAML.load(open(pathDirectory))
name = getString!(data, "path", "name")
id=1 # path identifier
sections = getSections!(data)
# save values in the path Dict
path = Dict(:name => name,
:id => id,
:sections => sections)
addPointsOfInterest!(path, data)
informAboutUnusedKeys(data, "path") # inform the user, which keywords of the imported data are not used in this tool
return path
end # function importPathFromYaml
## settings for the calculation
function importSettingsFromYaml(settingsDirectory::String)
# read setting information from a YAML file, save it in a settings Dict and return it
data = YAML.load(open(settingsDirectory))
# initialize the settings Dictionary
settings = Dict(:massModel => "", # model type of the train's mass "mass point" or "homogeneous strip"
:stepVariable => "", # step variable of the step method "s in m", "t in s" or "v in m/s"
:stepSize => 0.0, # step size (unit depends on stepVariable s in m, t in s and v in m/s)
:operationModeMinimumRunningTime => false, # operation mode "minimum running time"
:operationModeMinimumEnergyConsumption => false, # operation mode "minimum energy consumption"
:typeOfOutput => "", # output as "julia dictionary" or as "CSV"
:csvDirectory => "", # path of the folder in which the CSV files willl be saved
:detailOfOutput => "") # detail of output "minimal" or "everything"
settings[:massModel] = getString!(data, "settings", "massModel", ["mass point", "homogeneous strip"]) # model type of the train's mass "mass point" or "homogeneous strip"
settings[:stepVariable] = getString!(data, "settings", "stepVariable", ["s in m", "t in s", "v in m/s"]) # step variable of the step method "s in m", "t in s" or "v in m/s"
settings[:stepSize] = getPositiveNumber!(data, "settings", "stepSize", "("*settings[:stepVariable]*")", true) # step size (unit depends on stepVariable: s in m, t in s and v in m/s)
settings[:operationModeMinimumRunningTime] = getBool!(data, "settings", "operationModeMinimumRunningTime") # operation mode "minimum running time"
settings[:operationModeMinimumEnergyConsumption] = getBool!(data, "settings", "operationModeMinimumEnergyConsumption") # operation mode "minimum energy consumption"
settings[:typeOfOutput] = getString!(data, "settings", "typeOfOutput", ["julia dictionary", "CSV"]) # output as "julia dictionary" or as "CSV"
if settings[:typeOfOutput] == "CSV"
settings[:csvDirectory] = getString!(data, "settings", "csvDirectory")
# TODO: it could be checked if the path is existing on the pc
end # if
settings[:detailOfOutput] = getString!(data, "settings", "detailOfOutput", ["running time", "points of interest", "driving course", "everything"]) # should the output be only the value of the "running time", or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"?
# 30/31 old: settings[:detailOfOutput] = getString!(data, "settings", "detailOfOutput", ["minimal", "points of interest", "driving course"]) # should the output be "minimal" or are "points of interest" or the complete "driving course" required?
informAboutUnusedKeys(data, "settings") # inform the user, which keywords of the imported data are not used in this tool
return settings
end # function importSettingsFromYaml
function getBool!(data::Dict, dataSet::String, key::String)
if haskey(data[dataSet],key) && data[dataSet][key]!=nothing
if typeof(data[dataSet][key])==Bool
value = data[dataSet][key]
else
error("ERROR at reading the ",dataSet," yaml file: The value of the keyword ",key," is not correct. The value has to be of type Bool.")
end
else
value=false
println("WARNING at reading the ",dataSet," yaml file: The keyword ",key," or its value is missing. Therefore ",key,"=",value," is assumed and used.")
end end
delete!(data[dataSet], key) return dictionary
return value end # function importFromYaml
end #function getBool!
function getPositiveNumber!(data::Dict, dataSet::String, key::String, unit::String, required::Bool)
if haskey(data[dataSet],key) && data[dataSet][key]!=nothing
if typeof(data[dataSet][key]) <: Real && data[dataSet][key] >= 0.0
value = data[dataSet][key]
else
error("ERROR at reading the ",dataSet," yaml file: The value of ",key," is no real floating point number >=0.0.")
end
elseif required
error("ERROR at reading the ",dataSet," yaml file: The keyword ",key," is missing. It has to be added with a value of type real floating point number >0.0.")
else
value=0.0
println("WARNING at reading the ",dataSet," yaml file: The keyword ",key," is missing. Therefore ",key,"=0.0 ",unit," will be assumed and used." )
end
delete!(data[dataSet], key)
return value
end #function getPositiveNumber!
function getString!(data::Dict, dataSet::String, key::String, validValues::Vector{String})
# TODO change getString! to getSymbol! or to getEnum! ?
if haskey(data[dataSet],key) && data[dataSet][key]!=nothing
value = data[dataSet][key]
if typeof(value)==String
for validValue in validValues
if value == validValue
delete!(data[dataSet], key)
return value
end
end
end
error("ERROR at reading the ",dataSet," yaml file: The value of ",key," is wrong. It has to be one of the following String values: ", validValues)
else
error("ERROR at reading the ",dataSet," yaml file: The keyword ",key," is missing. It has to be added with one of the following String values: ", validValues)
end
end #function getString!
# second method of function getString! without validValues
function getString!(data::Dict, dataSet::String, key::String)
if haskey(data[dataSet],key) && data[dataSet][key]!=nothing
value = data[dataSet][key]
if typeof(value)==String
delete!(data[dataSet], key)
return value
end
error("ERROR at reading the ",dataSet," yaml file: The value of ",key," is wrong. It has to be of type String.")
else
error("ERROR at reading the ",dataSet," yaml file: The keyword ",key," is missing. It has to be added.")
end
end #function getString!
function getTrainType!(data::Dict)
if haskey(data["train"],"trainType") && data["train"]["trainType"]!=nothing
if typeof(data["train"]["trainType"])==String && (data["train"]["trainType"]=="freight" || data["train"]["trainType"]=="motorCoachTrain" || data["train"]["trainType"]=="passenger")
# 01/05 old without enum: trainType=data["train"]["trainType"] # "passenger" or "freight" or "motorCoachTrain"
type = getEnum(data["train"]["trainType"], trainType) # "passenger" or "freight" or "motorCoachTrain"
delete!(data["train"], "trainType")
else
error("ERROR at reading the train yaml file: The value of trainType is wrong. It has to be freight, motorCoachTrain or passenger.")
end
else
error("ERROR at reading the train yaml file: The keyword trainType is missing. It has to be added with the value freight, motorCoachTrain or passenger.")
end
return type
end # function getTrainType!
function getSpeedLimit!(data::Dict) # train's speed limit (in m/s)
v_limit_temp=0.0
v_limit_kmh_temp=0.0
if haskey(data["train"],"v_limit") && data["train"]["v_limit"]!=nothing
if typeof(data["train"]["v_limit"]) <: Real && data["train"]["v_limit"]>0.0
v_limit_temp=data["train"]["v_limit"] # trains speed limit (in m/s)
delete!(data["train"], "v_limit")
else
error("ERROR at reading the train yaml file: The value of v_limit is no real floating point number >0.0.")
end
end
if haskey(data["train"],"v_limit_kmh") && data["train"]["v_limit_kmh"]!=nothing
if typeof(data["train"]["v_limit_kmh"]) <: Real && data["train"]["v_limit_kmh"]>0.0
v_limit_kmh_temp=data["train"]["v_limit_kmh"] # trains speed limit (in km/h)
delete!(data["train"], "v_limit_kmh")
else
error("ERROR at reading the train yaml file: The value of v_limit is no real floating point number >0.0.")
end
end
if v_limit_temp > 0.0 && v_limit_kmh_temp > 0.0
v_limit=v_limit_temp
difference=abs(v_limit_temp-v_limit_kmh_temp/3.6)
if difference >0.0
println("WARNING at reading the train yaml file: The values of v_limit and v_limit_kmh differ by ",difference," m/s. The value v_limit=",v_limit," m/s is used." )
end
elseif v_limit_temp > 0.0
v_limit=v_limit_temp
elseif v_limit_kmh_temp > 0.0
v_limit=v_limit_kmh_temp/3.6
else
v_limit=1000.0/3.6
println("WARNING at reading the train yaml file: There is no value for the trains speed limit (v_limit or v_limit_kmh). The value v_limit=1000 km/h =",v_limit," m/s is used." )
end
return v_limit
end #function getSpeedLimit!
function get_a_braking!(data)
if haskey(data["train"],"a_braking") && data["train"]["a_braking"]!=nothing
if typeof(data["train"]["a_braking"]) <: Real
a_braking=data["train"]["a_braking"]
else
error("ERROR at reading the train yaml file: The value of the a_braking is no real floating point number <0.0.")
end
delete!(data["train"], "a_braking")
if a_braking > 0.0
a_braking =-a_braking
println("WARNING at reading the train yaml file: The value for a_braking is >0.0. The braking acceleration has to be <0.0. Therefore a_braking =",a_braking," m/s^2 is used." )
elseif a_braking == 0.0
error("ERROR at reading the train yaml file: The value for a_braking is 0.0. The braking acceleration has to be <0.0.")
end
else
error("ERROR at reading the train yaml file: The keyword a_braking is missing. It has to be added with a value of type real floating point number <0.0.")
end
return a_braking
end #function get_a_braking!
function getRotationMassFactors!(data::Dict, m_train::Real, m_t::Real, m_w::Real)
if haskey(data["train"],"rotationMassFactor_train") && data["train"]["rotationMassFactor_train"]!=nothing && typeof(data["train"]["rotationMassFactor_train"]) <: Real
if data["train"]["rotationMassFactor_train"]>0.0
ξ_train=data["train"]["rotationMassFactor_train"]
ξ_t=0.0
ξ_w=0.0
else
error("ERROR at reading the train yaml file: The value of rotationMassFactor_train is no real floating point number >0.0.")
end
elseif haskey(data["train"],"rotationMassFactor_t") && data["train"]["rotationMassFactor_t"]!=nothing && typeof(data["train"]["rotationMassFactor_t"]) <: Real && (m_w==0.0 || (haskey(data["train"],"rotationMassFactor_w") && data["train"]["rotationMassFactor_w"]!=nothing && typeof(data["train"]["rotationMassFactor_w"]) <: Real))
if data["train"]["rotationMassFactor_t"]>0.0
ξ_t=data["train"]["rotationMassFactor_t"]
else
error("ERROR at reading the train yaml file: The value of rotationMassFactor_t is no real floating point number >0.0.")
end
if m_w>0.0
if data["train"]["rotationMassFactor_w"]>=0.0
ξ_w=data["train"]["rotationMassFactor_w"]
else
error("ERROR at reading the train yaml file: The value of rotationMassFactor_w is no real floating point number >=0.0.")
end
else
ξ_w=0.0
end
ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train # rotation mass factor of the whole train (without unit)
else
error("ERROR at reading the train yaml file: The keywords rotationMassFactor_train or rotationMassFactor_t and rotationMassFactor_w are missing. They has to be added with a value of type real floating point number.")
end
delete!(data["train"], "rotationMassFactor_train")
delete!(data["train"], "rotationMassFactor_t")
delete!(data["train"], "rotationMassFactor_w")
return (ξ_train, ξ_t, ξ_w)
end #function getRotationMassFactors!
function getTractiveEffortVelocityPairs!(data::Dict) # pairs of velocity and tractive effort
if haskey(data["train"],"F_T_pairs") && data["train"]["F_T_pairs"]!=nothing
F_T_pairs=data["train"]["F_T_pairs"]
tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs, 1.0)
if haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing
println("WARNING at reading the train yaml file: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." )
end
elseif haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing
F_T_pairs_kmh=data["train"]["F_T_pairs_kmh"]
tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs_kmh, 1000/3600)
else
error("ERROR at reading the train yaml file: There has to be one of the keywords F_T_pairs or F_T_pairs_kmh filled with a list of pairs of velocity and tractive effort.")
end # if
delete!(data["train"], "F_T_pairs")
delete!(data["train"], "F_T_pairs_kmh")
return tractiveEffortVelocityPairs
end #function getTractiveEffortVelocityPairs!
function checkAndDefineTractiveEffortInput(F_T_pairs, velocityMultiplier::AbstractFloat)
# TODO: check if its numbers are real ? function checkAndDefineTractiveEffortInput(F_T_pairs::Array{Array{Real,1},1}, velocityMultiplier::AbstractFloat)
# check if the elements of the array have the correct type
errorDetected=false
for row in 1:length(F_T_pairs)
if typeof(F_T_pairs[row][1]) <: Real && F_T_pairs[row][1]>=0.0
else
errorDetected=true
println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," is no real floating point number >=0.0.")
end
if typeof(F_T_pairs[row][2]) <: Real && F_T_pairs[row][2]>=0.0
else
errorDetected=true
println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.")
end
if row>=2 && F_T_pairs[row][1] <= F_T_pairs[row-1][1]
errorDetected=true
println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," (v=",F_T_pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",F_T_pairs[row-1][1]," m/s).")
end
end # for
if errorDetected
error("ERROR at reading the train yaml file: 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
tractiveEffortVelocityPairs=[]
if F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used
push!(tractiveEffortVelocityPairs, [0.0, F_T_pairs[1][2]])
println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." )
end
for row in 1:length(F_T_pairs)
push!(tractiveEffortVelocityPairs, [F_T_pairs[row][1]*velocityMultiplier, F_T_pairs[row][2]])
end # for
if length(F_T_pairs[1])>2
println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.")
end
return tractiveEffortVelocityPairs
end #function checkAndDefineTractiveEffortInput
function get_Δv_w!(type::trainType) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
if type == passenger::trainType || type == motorCoachTrain::trainType
Δv_w=15.0/3.6
elseif type == freight::trainType
Δv_w=0.0
end # if
#= 01/05 old without enum
if type=="passenger" || type=="motor coach train"
Δv_w=15.0/3.6
elseif type== "freight"
Δv_w=0.0
end # if =#
return Δv_w
end #function get_Δv_w!
function getSections!(data::Dict)
# read the section starting positions and corresponding information
if haskey(data["path"],"sectionStarts") && data["path"]["sectionStarts"]!=nothing
sectionStartsArray=data["path"]["sectionStarts"]
conversionFactor=1.0 # conversion factor between the units m/s and m/s
valueKey="sectionStarts" # necessary for error messages
if haskey(data["path"],"sectionStarts") && data["path"]["sectionStarts_kmh"]!=nothing
println("WARNING at reading the path yaml file: There are values for sectionStarts and sectionStarts_kmh. The values for sectionStarts are used." )
end
elseif haskey(data["path"],"sectionStarts_kmh") && data["path"]["sectionStarts_kmh"]!=nothing
sectionStartsArray=data["path"]["sectionStarts_kmh"]
conversionFactor=1/3.6 # conversion factor between the units km/h and m/s
valueKey="sectionStarts_kmh" # necessary for error messages
else
error("ERROR at reading the path yaml file: The keyword sectionStarts or sectionStarts_kmh is missing. It has to be added.")
end # if
delete!(data["path"], "sectionStarts")
delete!(data["path"], "sectionStarts_kmh")
# 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 reading the path yaml file: The keyword ",valueKey," needs at least two rows for two points each with the three columns [s, v_limit, gradient].")
end
for row in 1:length(sectionStartsArray)
if length(sectionStartsArray[row])>=3
if length(sectionStartsArray[row])>3
println("INFO at reading the path yaml file: Only the first three columns of sectionStartsArray are used in this tool.")
end
else
error("ERROR at reading the path yaml file: The keyword ",valueKey," needs to be filled with the three columns [s, v_limit, gradient].")
end
if typeof(sectionStartsArray[row][1]) <: Real
if row > 1
if sectionStartsArray[row][1]>sectionStartsArray[row-1][1]
else
errorDetected=true
println("ERROR at reading the path yaml file: The postion value of ",valueKey," in row ", row ," (",sectionStartsArray[row][1]," m) has to be higher than the value in the row above (",sectionStartsArray[row-1][1]," m).")
end
end
else
errorDetected=true
println("ERROR at reading the path yaml file: The position value (column 1) of ",valueKey," in row ", row ," is no real floating point number.")
end
if typeof(sectionStartsArray[row][2]) <: Real && sectionStartsArray[row][2]>=0.0
else
errorDetected=true
println("ERROR at reading the path yaml file: The speed limit (column 2) of ",valueKey," in row ", row ," is no real floating point number >=0.0.")
end
if typeof(sectionStartsArray[row][3]) <: Real
else
errorDetected=true
println("ERROR at reading the path yaml file: The tractive effort value (column 3) of ",valueKey," in row ", row ," is no real floating point number.")
end
end # for
if errorDetected
error("ERROR at reading the path yaml file: The values of ",valueKey," 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
return sections
end #function getSections!
function addPointsOfInterest!(path::Dict, data::Dict)
# read the section starting positions and corresponding information
if haskey(data["path"],"pointsOfInterest") && data["path"]["pointsOfInterest"]!=nothing
pointsOfInterest = data["path"]["pointsOfInterest"]
delete!(data["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 reading the path yaml file: 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 reading the path yaml file: The point of interest in element ", element ," is no real floating point number.")
end
end # for
if errorDetected
error("ERROR at reading the path yaml file: The values of the point of interest 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
merge!(path, Dict(:pointsOfInterest => copiedPOIs))
end
return (path, data)
end #function addPointsOfInterest!
function informAboutUnusedKeys(data::Dict, dataSet::String) # inform the user which keywords of the imported data are not used in this tool
if length(data[dataSet])>0
println("INFO at reading the ",dataSet," yaml file: The following Keywords are not used in this tool:")
for key in keys(data[dataSet])
println(" - ",key)
end
end
end #function informAboutUnusedKeys
"""
getEnum(string, enum_type)
Converts a string to an enumerated type.
But only if the string matches an enumerated value.
# Example
```jldoctest
julia> @enum trainType passenger freight
julia> myTrain = "passenger"
"passenger"
julia> myTrainType = getEnum(myTrain, trainType)
passenger::trainType = 0
```
"""
function getEnum(string::String, enum_type::DataType)
inst = instances(enum_type) # get all instances of enumerated type
syms = Symbol.(inst) # convert all instances to Symbols
lookup = Dict(zip(syms, inst)) # combine instances and Symbols in a lookup table
#
n_str = Symbol(string) # normalize String via a Symbol
return lookup[n_str] # return matched enumerated type
end # function getEnum
end # module Input end # module Input

View File

@ -5,14 +5,11 @@
# __copyright__ = "2022" # __copyright__ = "2022"
# __license__ = "ISC" # __license__ = "ISC"
# TODO: >>if train[:type] == freight::trainType<< does not work only in checkTrainType(train::Dict). because ::Main.TrainRun.Import.trainType != ::Main.TrainRun.Input.trainType -> why? checkTrainType ist therefore deactivated. # TODO: 2022-04-07: if EnergySaving should be used. The train type has do be defined and checked
# TODO: adapt function informAboutUnusedKeys for Input.jl
module Input module Input
export checkAndSetInput! export checkAndSetInput!
@enum trainType passenger=1 freight=2 motorCoachTrain=3
approximationLevel = 6 # value for approximation to intersections TODO further explanation approximationLevel = 6 # value for approximation to intersections TODO further explanation
@ -37,38 +34,53 @@ Read the train information from a YAML file, save it in a train Dict and return
function checkAndSetTrain!(train::Dict) function checkAndSetTrain!(train::Dict)
# check train information from input dictionary # check train information from input dictionary
checkString(train, "train", :name) # train's name checkAndSetString!(train, "train", :name, "") # train's name
# TODO checkId ? train[:id] # train's identifier # add train's identifier if not existing
checkTrainType(train) # passenger or freight or motorCoachTrain 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"
checkPositiveNumber(train, "train", :length, "m") # total length (in m) checkAndSetPositiveNumberWithDifferentNames!(train, "train", :length, :l_train, "m", 20.0) # total length (in m)
# TODO: or just use: checkAndSetPositiveNumber!(train, "train", :length, "m", 20.0)
checkAndSetPositiveNumber!(train, "train", :v_limit, "m/s", 1000.0/3.6) # train's speed limit (in m/s) checkAndSetSpeedLimit!(train) # train's speed limit (in m/s)
checkAndSet_a_braking!(train) # a_braking checkAndSetBrakingAcceleration!(train) # a_braking
checkPositiveNumber(train, "train", :m_td, "kg") # mass on the traction unit's driving axles (in kg) 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) 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) 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) 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) 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) checkAndSetRotationMassFactors!(train)
checkAndSetTractiveEffortVelocityPairs!(train) # pairs of velocity and tractive effort checkAndSetTractiveEffortVelocityPairs!(train) # pairs of velocity and tractive effort
# coefficients for the vehicle resistance of the traction unit # coefficients for the vehicle resistance of the traction unit
checkAndSetRealNumber!(train, "train", :Δv_t, "m/s") # coefficient for velocitiy difference between traction unit and outdoor air (in m/s) 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_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_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) 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) # coefficients for the vehicle resistance of the set of wagons (consist)
checkAndSetRealNumber!(train, "train", :Δv_w, "m/s") # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) 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_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_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 ‰) checkAndSetPositiveNumber!(train, "train", :f_Rw2, "", 0.0) # coefficient fo the consistsr air resistance (in ‰)
# TODO: informAboutUnusedKeys(train, "train") # inform the user, which Symbols of the input dictionary are not used in this tool # 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 return train
end #function checkAndSetTrain! end #function checkAndSetTrain!
@ -76,12 +88,16 @@ end #function checkAndSetTrain!
function checkAndSetPath!(path::Dict) function checkAndSetPath!(path::Dict)
# check path information from input dictionary # check path information from input dictionary
checkString(path, "path", :name) checkAndSetString!(path, "path", :name, "")
# TODO checkId ? path[:id] # path identifier # TODO checkId ? path[:id] # path identifier
checkAndSetSections!(path) checkAndSetSections!(path)
checkAndSetPOIs!(path) checkAndSetPOIs!(path)
# TODO: informAboutUnusedKeys(path, "path") # inform the user, which Symbols of the input dictionary are not used in this tool # 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 return path
end # function checkAndSetPath! end # function checkAndSetPath!
@ -91,211 +107,310 @@ end # function checkAndSetPath!
function checkAndSetSettings!(settings::Dict) function checkAndSetSettings!(settings::Dict)
# check settings information from input dictionary # check settings information from input dictionary
checkString(settings, "settings", :massModel, ["mass point", "homogeneous strip"]) # model type of the train's mass "mass point" or "homogeneous strip" checkAndSetString!(settings, "settings", :massModel, "mass point", ["mass point", "homogeneous strip"]) # model type of the train's mass "mass point" or "homogeneous strip"
checkString(settings, "settings", :stepVariable, ["s in m", "t in s", "v in m/s"]) # step variable of the step method "s in m", "t in s" or "v in m/s" checkAndSetString!(settings, "settings", :stepVariable, "s in m", ["s in m", "t in s", "v in m/s"]) # step variable of the step method "s in m", "t in s" or "v in m/s"
checkPositiveNumber(settings, "settings", :stepSize, "("*settings[:stepVariable]*")") # step size (unit depends on stepVariable: s in m, t in s and v in m/s)
checkAndSetBool!(settings, "settings", :operationModeMinimumRunningTime) # operation mode "minimum running time" checkAndSetPositiveNumber!(settings, "settings", :stepSize, "("*settings[:stepVariable]*")", getDefaultStepSize(settings[:stepVariable])) # step size (unit depends on stepVariable: s in m, t in s and v in m/s)
checkAndSetBool!(settings, "settings", :operationModeMinimumEnergyConsumption) # operation mode "minimum energy consumption" checkAndSetBool!(settings, "settings", :operationModeMinimumRunningTime, true) # operation mode "minimum running time"
checkString(settings, "settings", :typeOfOutput, ["julia dictionary", "CSV"]) # output as "julia dictionary" or as "CSV" checkAndSetBool!(settings, "settings", :operationModeMinimumEnergyConsumption, false) # operation mode "minimum energy consumption"
checkAndSetString!(settings, "settings", :typeOfOutput, "julia dictionary", ["julia dictionary", "CSV"]) # output as "julia dictionary" or as "CSV"
if settings[:typeOfOutput] == "CSV" if settings[:typeOfOutput] == "CSV"
checkString(settings, "settings", :csvDirectory) checkAndSetString!(settings, "settings", :csvDirectory, "~/Desktop/TrainRun")
# TODO use correct default directory
# TODO: it could be checked if the path is existing on the pc # TODO: it could be checked if the path is existing on the pc
end # if end # if
checkString(settings, "settings", :detailOfOutput, ["running time", "points of interest", "driving course", "everything"]) # should the output be only the value of the "running time", or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? checkAndSetString!(settings, "settings", :detailOfOutput, "running time", ["running time", "points of interest", "driving course", "everything"]) # should the output be only the value of the "running time", or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"?
# 30/31 old: checkString(settings, "settings", :detailOfOutput, ["minimal", "points of interest", "driving course"]) # should the output be "minimal" or are "points of interest" or the complete "driving course" required or also all the information about the different sections?
# TODO: informAboutUnusedKeys(settings, "settings") # inform the user, which Symbols of the input dictionary are not used in this tool # inform the user about keys of the input dictionary that are not used in this tool
usedKeys = [:massModel, :stepVariable, :stepSize,
:operationModeMinimumRunningTime, :operationModeMinimumEnergyConsumption,
:typeOfOutput, :detailOfOutput]
if settings[:typeOfOutput] == "CSV"
push!(usedKeys, :csvDirectory)
end
informAboutUnusedKeys(collect(keys(settings)), usedKeys::Vector{Symbol}, "settings")
return settings return settings
end # function checkAndSetSettings! end # function checkAndSetSettings!
function checkAndSetBool!(dictionary::Dict, dictionaryType::String, key::Symbol) function checkAndSetBool!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::Bool)
if haskey(dictionary,key) && dictionary[key]!=nothing if haskey(dictionary,key) && dictionary[key]!=nothing
if typeof(dictionary[key])!=Bool if typeof(dictionary[key]) != Bool
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of the Symbol :",String(key)," is not correct. The value has to be of type 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 end
else else
merge!(dictionary, Dict(key => false)) merge!(dictionary, Dict(key => defaultValue))
println("WARNING at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," or its value is missing. Therefore ",String(key),"=",dictionary[key]," is assumed and used.") 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 end
return dictionary return dictionary
end #function checkAndSetBool! end #function checkAndSetBool!
function checkPositiveNumber(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String)
if haskey(dictionary,key) && dictionary[key]!=nothing
if typeof(dictionary[key]) <: Real && dictionary[key] >= 0.0
return true
else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.")
end
else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," is missing. It has to be added with a value of type real floating point number >0.0.")
end
return false
end #function checkPositiveNumber
function checkAndSetPositiveNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real) function checkAndSetPositiveNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real)
if haskey(dictionary,key) && dictionary[key]!=nothing if haskey(dictionary,key) && dictionary[key]!=nothing
if typeof(dictionary[key]) <: Real && dictionary[key] >= 0.0 if typeof(dictionary[key]) <: Real && dictionary[key] >= 0.0
else else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.") error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.")
end end
else else
merge!(dictionary, Dict(key => default)) merge!(dictionary, Dict(key => default))
println("WARNING at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," is missing. Therefore ",String(key),"=",default," ",unit," will be assumed and used." ) 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 end
return dictionary return dictionary
end #function checkAndSetPositiveNumber! end #function checkAndSetPositiveNumber!
function checkAndSetRealNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String) # 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^approximationLevel) # 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^approximationLevel) # 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 haskey(dictionary,key) && dictionary[key]!=nothing
if typeof(dictionary[key]) <: Real if typeof(dictionary[key]) <: Real
else else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(key)," is no real number.") error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real number.")
end end
else else
if key == :Δv_t merge!(dictionary, Dict(key => default))
value = 15.0/3.6 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." )
elseif key == :Δv_w
if dictionary[:type] == passenger::trainType || dictionary[:type] == motorCoachTrain::trainType
value = 15.0/3.6
elseif dictionary[:type] == freight::trainType
value = 0.0
end # if
else
value = 0.0
end
merge!(dictionary, Dict(key => value))
println("WARNING at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," is missing. Therefore ",String(key),"=",value," ",unit," will be assumed and used." )
end end
return dictionary return dictionary
end #function checkAndSetRealNumber! end #function checkAndSetRealNumber!
function checkString(dictionary::Dict, dictionaryType::String, key::Symbol, validValues::Vector{String})
# TODO change getString! to getSymbol! or to getEnum! ?
if haskey(dictionary,key) && dictionary[key]!=nothing
value = dictionary[key]
if typeof(value)==String
for validValue in validValues
if value == validValue
return true
end
end
end
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be one of the following String values: ", validValues)
else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," is missing. It has to be added with one of the following String values: ", validValues)
end
return false
end #function checkString
# second method of function checkString without validValues
function checkString(dictionary::Dict, dictionaryType::String, key::Symbol)
if haskey(dictionary,key) && dictionary[key]!=nothing
value = dictionary[key]
if typeof(value)==String
return true
end
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be of type String.")
else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(key)," is missing. It has to be added.")
end
return false
end #function checkString
function checkTrainType(train::Dict)
if haskey(train,:type) && train[:type]!=nothing
#= # println("train[:type]=",train[:type]," typeof(train[:type])=", typeof(train[:type]))
if train[:type] == passenger::trainType || train[:type] == freight::trainType || train[:type] == motorCoachTrain::trainType
return true
else
error("ERROR at checking the input dictionary for the train: The value of train[:type] is wrong. It has to be passenger, freight or motorCoachTrain of enum type trainType.")
end =#
else
error("ERROR at checking the input dictionary for the train: The Symbol :type is missing. It has to be added with the value passenger, freight or motorCoachTrain of enum type trainType.")
end
return false
end # function checkTrainType
function checkAndSet_a_braking!(train::Dict)
if haskey(train, :a_braking) && train[:a_braking]!=nothing
if typeof(train[:a_braking]) <: Real
return train
else
error("ERROR at checking the input dictionary for the train: The value of the a_braking is no real floating point number <0.0.")
end
if train[:a_braking] > 0.0
train[:a_braking] =-train[:a_braking]
println("WARNING at checking the input dictionary 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 dictionary 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 dictionary for the train: The Symbol :a_braking is missing. It has to be added with a value of type real floating point number <0.0.")
end
return train
end #function checkAndSet_a_braking!
function checkAndSetSum!(dictionary::Dict, dictionaryType::String, sum::Symbol, summand1::Symbol, summand2::Symbol) function checkAndSetSum!(dictionary::Dict, dictionaryType::String, sum::Symbol, summand1::Symbol, summand2::Symbol)
if haskey(dictionary,sum) && dictionary[sum]!=nothing if haskey(dictionary,sum) && dictionary[sum]!=nothing
if typeof(dictionary[sum]) <: Real && dictionary[sum] >= 0.0 if typeof(dictionary[sum]) <: Real && dictionary[sum] >= 0.0
difference = abs(dictionary[sum] - (dictionary[summand1]+dictionary[summand2])) difference = abs(dictionary[sum] - (dictionary[summand1]+dictionary[summand2]))
if difference > 1/(10^approximationLevel) if difference > 1/(10^approximationLevel)
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(sum)," is not exactly the sum of ",String(summand1)," and ",String(summand2),". It differs by ",difference,".") 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 end
else else
error("ERROR at checking the input dictionary for the ",dictionaryType,": The value of ",String(sum)," is no real floating point number >=0.0.") error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is no real floating point number >=0.0.")
end end
else else
merge!(dictionary, Dict(sum => dictionary[summand1]+dictionary[summand2])) merge!(dictionary, Dict(sum => dictionary[summand1]+dictionary[summand2]))
println("WARNING at checking the input dictionary for the ",dictionaryType,": The Symbol :",String(sum)," is missing. Therefore ",String(sum)," = ",String(summand1)," + ",String(summand2)," = ",dictionary[sum]," was calculated and will be used." ) 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 end
return dictionary return dictionary
end #function checkAndSetSum! end #function checkAndSetSum!
function checkAndSetRotationMassFactors!(train::Dict) function checkAndSetString!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::String, validValues::Vector{String})
if haskey(train, :ξ_train) && train[:ξ_train]!=nothing && typeof(train[:ξ_train]) <: Real # TODO change checkAndAddString! to checkAndAddSymbol! ?
if train[:ξ_train]>0.0 if haskey(dictionary,key) && dictionary[key]!=nothing
if haskey(train, :ξ_t) && train[:ξ_t]!=nothing && train[:ξ_t]>0.0 && typeof(train[:ξ_t]) <: Real && (train[:m_w]==0.0 || (haskey(train, :ξ_w) && train[:ξ_w]!=nothing && typeof(train[:ξ_w]) <: Real)) value = dictionary[key]
## println("train[:ξ_train]=",train[:ξ_train]," Rest=",(train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train]) if typeof(value) == String
# println("train[:ξ_t]=",train[:ξ_t]," train[:m_t]=",train[:m_t]," train[:ξ_w]=",train[:ξ_w]," train[:m_w]=",train[:m_w]," train[:m_train]=",train[:m_train]) 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!
# println("absDiff=", abs(train[:ξ_train] - (train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train])) 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^approximationLevel) # 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]) difference = abs(train[:ξ_train] - (train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train])
if difference > 1/(10^approximationLevel) if difference > 1/(10^approximationLevel)
error("ERROR at checking the input dictionary for the train: The value of ξ_train is not exactly ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train. It differs by ",difference,".") 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
end end
else else
error("ERROR at checking the input dictionary for the train: The value of :ξ_train is no real floating point number >0.0.") error("ERROR at checking the input for the train: The value of :ξ_train is no real floating point number >0.0.")
end end
elseif haskey(train, :ξ_t) && train[:ξ_t]!=nothing && typeof(train[:ξ_t]) <: Real && (train[:m_w]==0.0 || (haskey(train, :ξ_w) && train[:ξ_w]!=nothing && typeof(train[:ξ_w]) <: Real))
if train[:ξ_t]>0.0
ξ_t=train[:ξ_t]
else
error("ERROR at checking the input dictionary for the train: The value of :ξ_t is no real floating point number >0.0.")
end
if train[:m_w]>0.0
if train[:ξ_w]>=0.0
ξ_w=train[:ξ_w]
else
error("ERROR at checking the input dictionary for the train: The value of :ξ_w is no real floating point number >=0.0.")
end
else
ξ_w=0.0
end
ξ_train=(ξ_t*train[:m_t] + ξ_w*train[:m_w])/train[:m_train] # rotation mass factor of the whole train (without unit)
merge!(train, Dict(:ξ_train => ξ_train))
else else
error("ERROR at checking the input dictionary for the train: The Symbols :ξ_train or :ξ_t and :ξ_w are missing. They has to be added with a value of type real floating point number.") 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 end
return train return train
@ -304,118 +419,259 @@ end #function checkAndSetRotationMassFactors!
function checkAndSetTractiveEffortVelocityPairs!(train::Dict) # pairs of velocity and tractive effort function checkAndSetTractiveEffortVelocityPairs!(train::Dict) # pairs of velocity and tractive effort
if haskey(train,:tractiveEffortVelocityPairs) && train[:tractiveEffortVelocityPairs]!=nothing if haskey(train,:tractiveEffortVelocityPairs) && train[:tractiveEffortVelocityPairs]!=nothing
pairs = train[:tractiveEffortVelocityPairs] pairs = train[:tractiveEffortVelocityPairs]
velocityMultiplier = 1.0
# check if the elements of the array have the correct type if (haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing) && (haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing)
errorDetected=false 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." )
for row in 1:length(pairs) elseif haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing
if typeof(pairs[row][1]) <: Real && pairs[row][1]>=0.0 println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs. The values for tractiveEffortVelocityPairs are used." )
else
errorDetected=true
println("ERROR at checking the input dictionary 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 dictionary 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] elseif haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing
errorDetected=true 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." )
println("ERROR at checking the input dictionary 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
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 end # for
if errorDetected
error("ERROR at checking the input dictionary 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("WARNING at checking the input dictionary 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))
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
else else
error("ERROR at checking the input dictionary for the train: There has to be the Symbol :tractiveEffortVelocityPairs filled with a list of pairs of velocity and tractive effort.") 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 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 return train
end #function checkAndSetTractiveEffortVelocityPairs! 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) function checkAndSetSections!(path::Dict)
# check the section information # check the section information
if haskey(path,:sections) && path[:sections]!=nothing if haskey(path,:sections) && path[:sections]!=nothing
sections = path[:sections] # 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." )
checkedSections = [] elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing
increasing = false println("WARNING at checking the input for the path: There are values for sections and sectionStarts. The dictionary sections is used." )
decreasing = false
#TODO: throw error for each issue or collect the issues and use the Bool errorDetected like in checkTractiveEffortVelocityPairs!? elseif haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing
# check values for section==1 println("WARNING at checking the input for the path: There are values for sections and sectionStarts_kmh. The dictionary sections is used." )
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_start, "m") # first point of the section (in m) end
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_end, "m") # first point of the next section (in m) elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing
checkAndSetPositiveNumber!(sections[1], "path[:sections][1]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s) # TODO: check typeof(path[:sections]) == Array
checkAndSetRealNumber!(sections[1], "path[:sections][1]", :f_Rp, "") # specific path resistance of the section (in ‰) createSections!(path, :sectionStarts)
push!(checkedSections, sections[1]) 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
if sections[1][:s_start] < sections[1][:s_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 increasing = true
elseif sections[1][:s_start] > sections[1][:s_end] elseif sections[sectionNr][:s_start] > sections[sectionNr][:s_end]
decreasing = true decreasing = true
else else
pop!(checkedSections) pop!(checkedSections)
println("WARNING at checking the input dictionary 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.") 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 end
for section in 2:length(sections) if length(checkedSections)>1 && sections[sectionNr][:s_start] != checkedSections[end-1][:s_end]
checkAndSetRealNumber!(sections[section], "path[:sections]["*string(section)*"]", :s_start, "m") # first point of the section (in m) 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.")
checkAndSetRealNumber!(sections[section], "path[:sections]["*string(section)*"]", :s_end, "m") # first point of the next section (in m) # TODO: maybe if there is a gab create a new section and only if there a jumps in the wrong direction throw an error?
checkAndSetPositiveNumber!(sections[section], "path[:sections]["*string(section)*"]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s) end
checkAndSetRealNumber!(sections[section], "path[:sections]["*string(section)*"]", :f_Rp, "") # specific path resistance of the section (in ‰) end #for
push!(checkedSections, sections[section])
# compare the section's start and end position
if sections[section][:s_start] < sections[section][:s_end]
increasing = true
elseif sections[section][:s_start] > sections[section][:s_end]
decreasing = true
else
pop!(checkedSections)
println("WARNING at checking the input dictionary for the path: The ",section,". 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 dictionary for the path: The positions of the :sections are not increasing/decreasing consistently. The direction in the ",section,". section differs from the previous.")
end
if length(checkedSections)>1 && sections[section][:s_start] != checkedSections[end-1][:s_end]
error("ERROR at checking the input dictionary for the path[:sections]: The starting position of the ",section,". section (s=",sections[section][: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
else
error("ERROR at checking the input dictionary 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.")
end
return path return path
end #function checkAndSetSections! 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) function checkAndSetPOIs!(path::Dict)
# read the section starting positions and corresponding information # read the section starting positions and corresponding information
if haskey(path,:pointsOfInterest) if haskey(path, :pointsOfInterest)
if path[:pointsOfInterest] != nothing if path[:pointsOfInterest] != nothing
pointsOfInterest = path[:pointsOfInterest] pointsOfInterest = path[:pointsOfInterest]
@ -426,17 +682,17 @@ function checkAndSetPOIs!(path::Dict)
if element > 1 if element > 1
if pointsOfInterest[element] < pointsOfInterest[element-1] if pointsOfInterest[element] < pointsOfInterest[element-1]
sortingNeeded = true sortingNeeded = true
println("INFO at checking the input dictionary 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.") 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
end end
else else
errorDetected = true errorDetected = true
println("ERROR at checking the input dictionary for the path: The point of interest in element ", element ," is no real floating point number.") println("ERROR at checking the input for the path: The point of interest in element ", element ," is no real floating point number.")
end end
end # for end # for
if errorDetected if errorDetected
error("ERROR at checking the input dictionary for the path: The values of pointsOfInterest have to be corrected.") error("ERROR at checking the input for the path: The values of pointsOfInterest have to be corrected.")
end end
if sortingNeeded == true if sortingNeeded == true
sort!(pointsOfInterest) sort!(pointsOfInterest)
@ -453,7 +709,7 @@ function checkAndSetPOIs!(path::Dict)
path[:pointsOfInterest] = copiedPOIs path[:pointsOfInterest] = copiedPOIs
else else
println("INFO at checking the input dictionary for the path: The key pointsOfInterest exists but without values.") println("INFO at checking the input for the path: The key pointsOfInterest exists but without values.")
delete!(path, :pointsOfInterest) delete!(path, :pointsOfInterest)
end end
end end
@ -461,13 +717,41 @@ function checkAndSetPOIs!(path::Dict)
return path return path
end #function checkAndSetPOIs! 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 getDefaultStepSize(stepVariable::String)
#= if length(dictionary)>0 if stepVariable == "s in m"
println("INFO at checking the input dictionary for the ",dictionaryType,": The following Keywords are not used in this tool:") return 10.0
for key in keys(dictionary) elseif stepVariable == "t in s"
return 3.0
elseif stepVariable == "v in m/s"
return 0.1
#else
# error("ERROR at getting a default step size. The step variable ",stepVariable," can not be used.")
end
end #function getDefaultStepSize
#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) println(" - ",key)
end end
end =# end
end #function informAboutUnusedKeys end #function informAboutUnusedKeys
end # module Input end # module Input

View File

@ -1,3 +1,10 @@
#!/usr/bin/env julia
# -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.2
# __author__ = "Max Kannenberg"
# __copyright__ = "2020-2022"
# __license__ = "ISC"
module TrainRun module TrainRun
# include main module TrainRunCalc # include main module TrainRunCalc
@ -26,7 +33,7 @@ using .EnergySaving
export calculateDrivingDynamics, export calculateDrivingDynamics,
# import functions # import functions
importYamlFiles, importYamlFile, importYamlFiles, importFromYaml,
# functions for saving energy that are not recommended to use in this state # functions for saving energy that are not recommended to use in this state
addOperationModeEnergySaving!, addOperationModeEnergySaving!,