checkAndSetString!(train,"train",:name,"")# train's name
# add train's identifier if not existing
if!(haskey(train,:id)&&train[:id]!=nothing)
merge!(train,Dict(:id=>1))
end
checkAndSetString!(train,"train",:type,"passenger",["passenger","freight"])# train type "passenger" or "freight"
checkAndSetPositiveNumberWithDifferentNames!(train,"train",:length,:l_train,"m",20.0)# total length (in m)
# TODO: or just use: checkAndSetPositiveNumber!(train, "train", :length, "m", 20.0)
checkAndSetSpeedLimit!(train)# train's speed limit (in m/s)
checkAndSetBrakingAcceleration!(train)# a_braking
checkAndSetPositiveNumber!(train,"train",:m_td,"kg",80000)# mass on the traction unit's driving axles (in kg)
checkAndSetPositiveNumber!(train,"train",:m_tc,"kg",0.0)# mass on the traction unit's carrying axles (in kg)
checkAndSetSum!(train,"train",:m_t,:m_td,:m_tc)# mass of the traction unit (in kg)
checkAndSetPositiveNumber!(train,"train",:m_w,"kg",0.0)# mass of the set of wagons (consist) (in kg)
checkAndSetSum!(train,"train",:m_train,:m_t,:m_w)# total mass (in kg)
iftrain[:m_train]<=0.0
error("ERROR at checking the input for the train: The train's mass has to be higher than 0.0 kg.")
end
checkAndSetRotationMassFactors!(train)
checkAndSetTractiveEffortVelocityPairs!(train)# pairs of velocity and tractive effort
# coefficients for the vehicle resistance of the traction unit
checkAndSetRealNumber!(train,"train",:Δv_t,"m/s",15.0/3.6)# coefficient for velocitiy difference between traction unit and outdoor air (in m/s)
checkAndSetPositiveNumber!(train,"train",:f_Rtd0,"‰",0.0)# coefficient for basic resistance due to the traction units driving axles (in ‰)
checkAndSetPositiveNumber!(train,"train",:f_Rtc0,"‰",0.0)# coefficient for basic resistance due to the traction units carring axles (in ‰)
checkAndSetPositiveNumber!(train,"train",:F_Rt2,"N",0.0)# coefficient for air resistance of the traction units (in N)
# coefficients for the vehicle resistance of the set of wagons (consist)
checkAndSetRealNumber!(train,"train",:Δv_w,"m/s",getDefault_Δv_w(train[:type]))# coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
checkAndSetPositiveNumber!(train,"train",:f_Rw0,"‰",0.0)# coefficient for basic resistance of the set of wagons (consist) (in ‰)
checkAndSetPositiveNumber!(train,"train",:f_Rw1,"‰",0.0)# coefficient for the consists resistance to rolling (in ‰)
checkAndSetPositiveNumber!(train,"train",:f_Rw2,"‰",0.0)# coefficient fo the consistsr air resistance (in ‰)
# inform the user about keys of the input dictionary that are not used in this tool
error("ERROR at checking the input for the ",dictionaryType,": The value of the key ",String(key)," is not correct. The value has to be of type Bool.")
end
else
merge!(dictionary,Dict(key=>defaultValue))
defaultValue&&println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," or its value is missing. Therefore ",String(key),"=",dictionary[key]," is assumed and used.")
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.")
end
else
merge!(dictionary,Dict(key=>default))
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default,"",unit," will be assumed and used.")
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
ifmainKey_temp>=0.0&&alternativeKey_temp>=0.0
difference=abs(mainKey_temp-alternativeKey_temp)
ifdifference>1/(10^approxLevel)# TODO or use difference > 0.0 ?
delete!(dictionary,alternativeKey)
println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference,"",unit,". The value ",String(mainKey),"=",default,"",unit," is used.")
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
ifmainKey_temp>=0.0&&alternativeKey_temp>=0.0
difference=abs(mainKey_temp-alternativeKey_temp)
ifdifference>1/(10^approxLevel)# TODO or use difference > 0.0 ?
delete!(dictionary,alternativeKey)
println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference,"",unit,". The value ",String(mainKey),"=",default,"",unit," is used.")
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.")
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real number.")
end
else
merge!(dictionary,Dict(key=>default))
println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default,"",unit," will be assumed and used.")
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is not exactly the sum of ",String(summand1)," and ",String(summand2),". It differs by ",difference,".")
end
else
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is no real floating point number >=0.0.")
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.")
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
returndictionary
end#function checkAndSetString!
# second method of function checkAndSetString! without validValues
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.")
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
ifv_limit_temp>0.0&&v_limit_kmh_temp>0.0
difference=abs(v_limit_temp-v_limit_kmh_temp/3.6)
ifdifference>1/(10^approxLevel)# TODO or use difference > 0.0 ?
delete!(train,:v_limit_kmh)
println("WARNING at checking the input for the train: The values of v_limit and v_limit_kmh differ by ",difference," m/s. The value v_limit=",v_limit_temp," m/s is used.")
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.")
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.")
elseiftrain[: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
iftrain[:type]=="freight"
a_braking=-0.225
elseiftrain[: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.")
error("ERROR at checking the input for the train: The value of ξ_train is not exactly ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train. It differs by ",difference,".")
end
end
else
error("ERROR at checking the input for the train: The value of :ξ_train is no real floating point number >0.0.")
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.")
println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs. The values for tractiveEffortVelocityPairs are used.")
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.")
error("ERROR at checking the input for the train: There has to be the key tractiveEffortVelocityPairs filled with a list of pairs of velocity and tractive effort.")
end# if
# check if the elements of the array have the correct type
errorDetected=false
forrowin1:length(pairs)
iftypeof(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
iftypeof(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
ifrow>=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
iferrorDetected
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
ifpairs[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.")
functiongetDefault_Δv_w(type::String)# coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s)
iftype=="passenger"
# TODO if different passenger or freight trains are posiible, use: if startswith(type, "passenger"). exanples: passengerLocomotivehauled and passengerMotorCoachTrain
# if haskey(path,:sections) && path.sections!=nothing
# # TODO: check typeof(path.sections) == Dict
# if (haskey(path, :sectionStarts) && path[:sectionStarts]!=nothing) && (haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing)
# println("WARNING at checking the input for the path: There are values for sections, sectionStarts and sectionStarts_kmh. The dictionary sections is used." )
# error("ERROR at checking the input for the path: The Symbol :sections is missing. It has to be added with a list of sections. Each has to be a dictionary with the keys :s_tart, :s_end, :v_limit and :f_Rp.")
# section = Dict(:s_start => 0.0,
# :s_end => 15.0,
# :v_limit => 1000.0/3.6,
# :f_Rp => 0.0)
# merge!(path, Dict(:sections => [section]))
# return path
# end
# sections = path.sections
# checkedSections = []
# increasing = false
# decreasing = false
# #TODO: throw error for each issue or collect the issues and use the Bool errorDetected like in createSections?
# # check values for section==1
# checkAndSetRealNumber!(sections[1], "path.sections[1]", :s_start, "m", 0.0) # first point of the section (in m)
# checkAndSetRealNumber!(sections[1], "path.sections[1]", :s_end, "m", 0.0) # first point of the next section (in m)
# 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
# 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)
# 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]
# println("INFO at checking the input for the path: The ",sectionNr,". section of :sections has the same position for starting and end point. The section will be deleted and not used in the tool.")
# end
# if increasing && decreasing
# error("ERROR at checking the input for the path: The positions of the :sections are not increasing/decreasing consistently. The direction in the ",sectionNr,". section differs from the previous.")
# end
# if length(checkedSections)>1 && sections[sectionNr][:s_start] != checkedSections[end-1][:s_end]
# error("ERROR at checking the input for the path.sections: The starting position of the ",section,". section (s=",sections[sectionNr][:s_start]," m) does not euqal the last position of the previous section(s=",checkedSections[end-1][:s_end]," m). The sections have to be sequential.")
# # TODO: maybe if there is a gab create a new section and only if there a jumps in the wrong direction throw an error?
# end
# end #for
# return path
# end #function checkAndSetSections!
# function createSections!(path::Path, 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
# 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::Path)
# # read the section starting positions and corresponding information
# if haskey(path, :pointsOfInterest)
# # if path.poi != nothing
# pointsOfInterest = path[:points_of_interest]
# sortingNeeded = false
# errorDetected = false
# for element in 1:length(pointsOfInterest)
# if typeof(pointsOfInterest[element]) <: Real
# if element > 1
# if pointsOfInterest[element] < pointsOfInterest[element-1]
# sortingNeeded = true
# println("INFO at checking the input for the path: The point of interest in element ", element ," (",pointsOfInterest[element]," m) has to be higher than the value of the previous element (",pointsOfInterest[element-1]," m). The points of interest will be sorted.")
# end
# end
# else
# errorDetected = true
# println("ERROR at checking the input for the path: The point of interest in element ", element ," is no real floating point number.")
# end
# end # for
# if errorDetected
# error("ERROR at checking the input for the path: The values of pointsOfInterest have to be corrected.")
# end
# if sortingNeeded == true
# sort!(pointsOfInterest)
# end
# copiedPOIs = []
# for element in 1:length(pointsOfInterest)
# if element == 1
# push!(copiedPOIs, pointsOfInterest[element])
# elseif element > 1 && pointsOfInterest[element] > pointsOfInterest[element-1]
# push!(copiedPOIs, pointsOfInterest[element])
# end
# end # for
# path[:points_of_interest ] = copiedPOIs
# # else
# # println("INFO at checking the input for the path: The key pointsOfInterest exists but without values.")
#function informAboutUnusedKeys(dictionary::Dict, dictionaryType::String) # inform the user which Symbols of the input dictionary are not used in this tool
functioninformAboutUnusedKeys(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
forkeyinallKeys
used=false
forusedKeyinusedKeys
ifkey==usedKey
used=true
break
end
end
if!used
push!(unusedKeys,key)
end
end
iflength(unusedKeys)>0
println("INFO at checking the input for the ",dictionaryType,": The following Keywords are not used in this tool:")