TrainRun.jl/src/Import.jl

541 lines
28 KiB
Julia
Raw Normal View History

module Import
import YAML
export importYamlFiles, importYamlFile
@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.
"""
function importYamlFiles(trainDirectory::String, pathDirectory::String, settingsDirectory::String)
train=importTrainFromYaml(trainDirectory)
path=importPathFromYaml(pathDirectory)
settings=importSettingsFromYaml(settingsDirectory)
return (train, path, settings)
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.
"""
function importYamlFile(dataType::Symbol, directory::String)
if dataType == :train
return importTrainFromYaml(directory)
elseif dataType == :path
return importPathFromYaml(directory)
elseif dataType == :settings
return importSettingsFromYaml(directory)
else
error("Wrong dataType in function importYamlFile")
end
end #function importYamlFile
"""
Read the train information from a YAML file, save it in a train Dict and return it.
"""
function importTrainFromYaml(trainDirectory::String)
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)
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", ["minimal", "driving course"]) # should the output be "minimal" or "driving course"
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
delete!(data[dataSet], key)
return value
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 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