new type Settings as struct

development
Martin Scheidt 2022-04-28 17:02:40 +02:00
parent 25959f7302
commit e2842157da
42 changed files with 485 additions and 1836 deletions

View File

@ -9,6 +9,24 @@ Categories: Added, Changed, Deprecated, Removed, Fixed, and Security.
## [Unreleased] ## [Unreleased]
### Added
* dependency JSONSchema
* validation of YAML input via JSON schema
### Changed
* replaced settings::Dict with type Settings as struct
* restructured examples/ and data/ in docs/ and test/
* modified test to work with Julia Testsets and with simplier naming of input files
* renamed Validate.jl into types.jl
* renamed TrainRunCalc.jl into calc.jl
* changed capital letter of include files to lower letter
* changed seperation of submodules into a single module with file include
### Removed
* dependency Plots
* AdditionalOutput.jl
* EnergySaving.jl
* test/testEnums.jl
## Version [0.8] 2022-01-20 ## Version [0.8] 2022-01-20

View File

@ -5,6 +5,15 @@ email, or any other method with the owners of this repository before making a ch
Please note we have a code of conduct, please follow it in all your interactions with the project. Please note we have a code of conduct, please follow it in all your interactions with the project.
# Julia Development Environment
```
$ ln -s ~/path/to/TrainRun.jl ~/.julia/dev/TrainRun
```
and use `Revise.jl`
# Pull Request Process # Pull Request Process
* add your changes to the CHANGELOG.md under [Unreleased] * add your changes to the CHANGELOG.md under [Unreleased]

View File

@ -1,12 +1,20 @@
name = "TrainRun" name = "TrainRun"
uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92" uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92"
authors = ["Max Kannenberg"] authors = ["Max Kannenberg, Martin Scheidt, and contributors"]
version = "0.8.0" version = "0.8.0"
[deps] [deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
[compat]
julia = "1.7"
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[targets]
test = ["Test"]

View File

@ -1,6 +1,7 @@
# TrainRun # TrainRun
[![License: ISC](https://img.shields.io/badge/license-ISC-green.svg)](https://opensource.org/licenses/ISC) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6448563.svg)](https://doi.org/10.5281/zenodo.6448563) [![License: ISC](https://img.shields.io/badge/license-ISC-green.svg)](https://opensource.org/licenses/ISC) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6448563.svg)](https://doi.org/10.5281/zenodo.6448563)
[![Build Status](https://github.com/railtoolkit/TrainRun.jl/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/railtoolkit/TrainRun.jl/actions/workflows/CI.yml?query=branch%3Amaster)
------------ ------------

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "homogeneous strip" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "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"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
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"

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "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"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
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"

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "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"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "CSV" # output as "julia dictionary" or as "CSV"
detailOfOutput: "running time" # 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"

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "homogeneous strip" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "t in s" # step variable of the step method "s in m", "t in s" or "v in m/s"
stepSize: 3.0 # step size (unit depends on stepVariable s in m, t in s and v in m/s)
operationModeMinimumRunningTime: true # operation mode "minimum running time"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
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"

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "t in s" # step variable of the step method "s in m", "t in s" or "v in m/s"
stepSize: 3.0 # step size (unit depends on stepVariable s in m, t in s and v in m/s)
operationModeMinimumRunningTime: true # operation mode "minimum running time"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
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"

View File

@ -1,12 +0,0 @@
%YAML 1.2
---
settings:
# settings for the simulation
massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip"
stepVariable: "v in m/s" # step variable of the step method "s in m", "t in s" or "v in m/s"
stepSize: 0.1 # step size (unit depends on stepVariable s in m, t in s and v in m/s)
operationModeMinimumRunningTime: true # operation mode "minimum running time"
operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption"
typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV"
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"

11
docs/DEFAULT.yaml Normal file
View File

@ -0,0 +1,11 @@
%YAML 1.2
---
settings:
# default settings for the calculation
massModel: "mass_point" # type of train model used: "mass_point" or "homogeneous_strip"
stepVariable: "distance" # variable of the linear multistep method: "distance", "time" or "velocity"
stepSize: 20 # step size, unit depends on stepVariable - distance in meter, time in seconds and velocity in meter/second.
approxLevel: 3 # value for approximation; used when rounding or interating
outputDetail: "running_time" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"
outputFormat: "julia_dict" # output as "julia_dict" or as "csv"
outputDir: "." # used if other outputFormat than "julia dict"

View File

@ -0,0 +1,32 @@
#!/usr/bin/env julia
import TrainRun
paths=[]
push!(paths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml"))
push!(paths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml"))
settings=[]
push!(settings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml"))
trains=[]
push!(trains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml"))
push!(trains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml"))
push!(trains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml"))
for path in paths
# println(" - - - - - - - - -")
# println("path: ", path[:name])
for train in trains
# println("train: ", train[:name])
for settings in settings
resultsDict = trainRun(train, path, settings)
if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV"
exportToCsv(resultsDict, settings)
sleep(2)
end
end
end
end

View File

@ -0,0 +1,10 @@
#!/usr/bin/env julia
import TrainRun
train = Train("data/trains/train_freight_V90withOreConsist.yaml")
path = Path("data/paths/path_1_10km_nConst_vConst.yaml")
runtime = trainRun(train, path)
println("The train needs $runtime seconds for the running path.")

View File

@ -1,44 +0,0 @@
#!/usr/bin/env julia
# -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.0
# __author__ = "Max Kannenberg"
# __copyright__ = "2021"
# __license__ = "ISC"
include("../src/TrainRun.jl")
using .TrainRun
allPaths=[]
push!(allPaths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml"))
push!(allPaths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml"))
push!(allPaths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml"))
push!(allPaths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml"))
allSettings=[]
push!(allSettings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml"))
allTrains=[]
push!(allTrains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml"))
push!(allTrains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml"))
push!(allTrains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml"))
for path in allPaths
# println(" - - - - - - - - -")
# println("path: ", path[:name])
for train in allTrains
# println("train: ", train[:name])
for settings in allSettings
resultsDict = trainRun(train, path, settings)
if haskey(settings, :typeOfOutput) && settings[:typeOfOutput] == "CSV"
exportToCsv(resultsDict, settings)
sleep(2)
end
# println("")
end
end
# println("")
end
# println("")
# println("________________________")
# println("")

View File

@ -1,19 +0,0 @@
#!/usr/bin/env julia
# -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.0
# __author__ = "Max Kannenberg"
# __copyright__ = "2021"
# __license__ = "ISC"
include("../src/TrainRun.jl")
using .TrainRun
train_directory = "data/trains/train_freight_V90withOreConsist.yaml"
running_path_directory = "data/paths/path_1_10km_nConst_vConst.yaml"
setting_directory = "data/settings/settings_distanceStep_massPoint_runningTime.yaml"
(train, running_path, settings) = importYamlFiles(train_directory, running_path_directory, setting_directory)
runtime = trainRun(train, running_path, settings)
exportToCsv(runtime, settings)
println("The V 90 with 10 ore wagons needs $runtime seconds for 10 km with no gradient.")

View File

@ -1,210 +0,0 @@
#!/usr/bin/env julia
# -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.2
# __author__ = "Max Kannenberg"
# __copyright__ = "2020-2022"
# __license__ = "ISC"
# INFO: AdditionalOutput should not be used because it is not completed yet. It was used to show first results during development.
# TODO: It has to be optimized so that the created plots and printed information is clear and understandable.
module AdditionalOutput
using Plots
export plotResults, plotDrivingCourse, printImportantValues, printSectionInformation
function plotResults(output::Dict)
opModeMinTime = output[:settings][:operationModeMinimumRunningTime]
opModeMinEnergy = output[:settings][:operationModeMinimumEnergyConsumption]
if opModeMinTime == true && opModeMinEnergy == true
plotDrivingCourse(output[:drivingCourseMinimumRunningTime], output[:drivingCourseMinimumEnergyConsumption])
elseif opModeMinTime == true
plotDrivingCourse(output[:drivingCourseMinimumRunningTime])
elseif opModeMinEnergy == true
plotDrivingCourse(output[:drivingCourseMinimumEnergyConsumption])
else
output[:settings][:detailOfOutput] == "everything" && println("No Output was demanded. So no plot is created.")
end
return true
end #function plotResults
function plotResults(drivingCourse::Vector{Dict})
plotDrivingCourse(drivingCourse)
return true
end #function plotResults
function plotResults(singleValue::AbstractFloat)
println("Not able to plot the single value ",singleValue)
return false
end #function plotResults
function plotDrivingCourse(drivingCourse::Vector{Dict})
a=[]
E=[]
s=[]
t=[]
v=[]
for i in 1:length(drivingCourse)
push!(a, drivingCourse[i][:a])
push!(E, drivingCourse[i][:E])
push!(s, drivingCourse[i][:s])
push!(t, drivingCourse[i][:t])
push!(v, drivingCourse[i][:v])
end #for
# p1=plot([s], [v], title = "v in m/s", label = ["v"], xlabel = "s in m")
p1=plot([s/1000], [v*3.6], title = "v in km/h", label = ["v"], xlabel = "s in km")
# p2=plot([t], [v], title = "v in m/s", label = ["v"], xlabel = "t in s")
p2=plot([t/60], [v*3.6], title = "v in km/h", label = ["v"], xlabel = "t in min")
# p3=plot([s], [t], title = "t in s", label = ["t"], xlabel = "s in m")
# p4=plot([t], [s], title = "s in m", label = ["s"], xlabel = "t in s")
#p5=plot([s], [E], title = "E in Ws", label = ["E"], xlabel = "s in m")
p5=plot([s/1000], [E], title = "E in Ws", label = ["E"], xlabel = "s in km")
#p6=plot([t], [E], title = "E in Ws", label = ["E"], xlabel = "t in s")
p6=plot([t/60], [E], title = "E in Ws", label = ["E"], xlabel = "t in min")
all=plot(p1, p2, p5, p6, layout = (2, 2), legend = false)
#=
# p5=plot([s], [E], title = "E in Ws", label = ["E"], xlabel = "s in m")
# p6=plot([t], [E], title = "E in Ws", label = ["E"], xlabel = "t in s")
all=plot(p1, p2, layout = (1, 2), legend = false)=#
# all=plot(p1, p2, p3, p4, p5, p6, layout = (3, 2), legend = false)
display(all)
println("Plots for different variables have been created.")
end #function plotDrivingCourse
function plotDrivingCourse(drivingCourseMinimumRunningTime::Vector{Dict},drivingCourseMinimumEnergyConsumption::Vector{Dict})
a_minTime=[]
E_minTime=[]
s_minTime=[]
t_minTime=[]
v_minTime=[]
for i in 1:length(drivingCourseMinimumRunningTime)
push!(a_minTime, drivingCourseMinimumRunningTime[i][:a])
push!(E_minTime, drivingCourseMinimumRunningTime[i][:E])
push!(s_minTime, drivingCourseMinimumRunningTime[i][:s])
push!(t_minTime, drivingCourseMinimumRunningTime[i][:t])
push!(v_minTime, drivingCourseMinimumRunningTime[i][:v])
end #for
a_minEnergy=[]
E_minEnergy=[]
s_minEnergy=[]
t_minEnergy=[]
v_minEnergy=[]
for i in 1:length(drivingCourseMinimumEnergyConsumption)
push!(a_minEnergy, drivingCourseMinimumEnergyConsumption[i][:a])
push!(E_minEnergy, drivingCourseMinimumEnergyConsumption[i][:E])
push!(s_minEnergy, drivingCourseMinimumEnergyConsumption[i][:s])
push!(t_minEnergy, drivingCourseMinimumEnergyConsumption[i][:t])
push!(v_minEnergy, drivingCourseMinimumEnergyConsumption[i][:v])
end #for
p1=plot([s_minTime,s_minEnergy],
[v_minTime,v_minEnergy],
title = "v in m/s",
label = ["v for t_min" "v for E_min"],
xlabel = "s in m")# lw = 3)
p2=plot([t_minTime,t_minEnergy],
[v_minTime,v_minEnergy],
title = "v in m/s",
label = ["v for t_min" "v for E_min"],
xlabel = "t in s")
# p3=plot([s_minTime,s_minEnergy],
# [t_minTime,t_minEnergy],
# title = "t in s",
# label = ["t for t_min" "t for E_min"],
# xlabel = "s in m")
# p4=plot([t_minTime,t_minEnergy],
# [s_minTime,s_minEnergy],
# title = "s in m",
# label = ["s for t_min" "s for E_min"],
# xlabel = "t in s")
p5=plot([s_minTime,s_minEnergy],
[E_minTime,E_minEnergy],
title = "E in Ws",
label = ["E for t_min" "E for E_min"],
xlabel = "s in m")
p6=plot([t_minTime,t_minEnergy],
[E_minTime,E_minEnergy],
title = "E in Ws",
label = ["E for t_min" "E for E_min"],
xlabel = "t in s")
# all=plot(p1, p2, p3, p4, p5, p6, layout = (3, 2), legend = false)
all=plot(p1, p2, p5, p6, layout = (2, 2), legend = false)
display(all)
println("Plots for different variables have been created.")
end #function plotDrivingCourse
function printImportantValues(dataPoints::Vector{Dict})
println("i behavior s in m v in km/h t in min a in m/s^2 F_R in k N F_T in k N E in k Wh")
for i in 1:length(dataPoints)
println(dataPoints[i][:i],". ",dataPoints[i][:behavior]," ",dataPoints[i][:s]," ",dataPoints[i][:v]*3.6," ",dataPoints[i][:t]/60," ",dataPoints[i][:a]," ",dataPoints[i][:F_R]/1000," ",dataPoints[i][:F_T]/1000," ",dataPoints[i][:E]/3600/1000)
end #for
println("i behavior s in m v in km/h t in min a in m/s^2 F_R in k N F_T in k N E in k Wh")
end #function printImportantValues
function printSectionInformation(movingSection::Dict)
CSs::Vector{Dict} = movingSection[:characteristicSections]
println("MS with length=", movingSection[:length]," with t=", movingSection[:t])
#allBSs=[:breakFree, :clearing, :accelerating, :clearing2, :accelerating2, :clearing3, :accelerating3, :cruising, :downhillBraking, :diminishing, :coasting, :braking, :standstill]
for csId in 1:length(CSs)
println("CS ",csId," with length=", CSs[csId][:length]," with t=", CSs[csId][:t])
# for bs in 1: length(allBSs)
# if haskey(CSs[csId][:behaviorSections], allBSs[bs])
# println("BS ",allBSs[bs], " with s_entry=", CSs[csId][:behaviorSections][allBSs[bs]][:s_entry], " and length=",CSs[csId][:behaviorSections][allBSs[bs]][:length]) # and t=", CSs[csId][:behaviorSections][allBSs[bs]][:t])
# # for point in 1:length(CSs[csId][:behaviorSections][allBSs[bs]][:dataPoints])
# # println(CSs[csId][:behaviorSections][allBSs[bs]][:dataPoints][point])
# # end
# end #if
# end #for
tempBSs = collect(keys(CSs[csId][:behaviorSections]))
while length(tempBSs) > 0
currentBS = :default
for bs in 1: length(tempBSs)
if currentBS == :default
currentBS = tempBSs[bs]
else
if CSs[csId][:behaviorSections][currentBS][:s_entry] > CSs[csId][:behaviorSections][tempBSs[bs]][:s_entry]
currentBS = tempBSs[bs]
end
end
end #for
println("BS ",currentBS, " with s_entry=", CSs[csId][:behaviorSections][currentBS][:s_entry], " and length=",CSs[csId][:behaviorSections][currentBS][:length]) # and t=", CSs[csId][:behaviorSections][currentBS][:t])
# for point in 1:length(CSs[csId][:behaviorSections][currentBS][:dataPoints])
# println(CSs[csId][:behaviorSections][currentBS][:dataPoints][point])
# end
newTempBSs = []
for bs in 1: length(tempBSs)
if currentBS != tempBSs[bs]
push!(newTempBSs, tempBSs[bs])
end #if
end #for
tempBSs = newTempBSs
end #while
end #for
end #function printSectionInformation
end # module AdditionalOutput

View File

@ -5,22 +5,6 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module Behavior
include("./Formulary.jl")
using .Formulary
export addBreakFreeSection!, addClearingSection!, addAcceleratingSection!, addCruisingSection!, addDiminishingSection!, addCoastingSection!, addBrakingSection!, addStandstill!,
# addBrakingSectionInOneStep! is not used in the current version of the tool
calculateForces!, createDataPoint,
# export functions from Formulary
calcBrakingDistance, calcBrakingStartVelocity, calc_Δs_with_Δt
approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s)
# TODO: define it in TrainRun and give it to each function?
## functions for calculating tractive effort and resisting forces ## functions for calculating tractive effort and resisting forces
""" """
calculateTractiveEffort(v, tractiveEffortVelocityPairs) calculateTractiveEffort(v, tractiveEffortVelocityPairs)
@ -62,10 +46,11 @@ end #function calculateTractiveEffort
""" """
calculate and return the path resistance dependend on the trains position and mass model calculate and return the path resistance dependend on the trains position and mass model
""" """
function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel::String, train::Dict) function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Dict)
if massModel == "mass point"
if massModel == :mass_point
pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train[:m_train]) pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train[:m_train])
elseif massModel == "homogeneous strip" elseif massModel == :homogeneous_strip
pathResistance = 0.0 pathResistance = 0.0
s_rear = s - train[:length] # position of the rear of the train s_rear = s - train[:length] # position of the rear of the train
while csId > 0 && s_rear < CSs[csId][:s_exit] while csId > 0 && s_rear < CSs[csId][:s_exit]
@ -84,7 +69,7 @@ end #function calculatePathResistance
""" """
calculate and return tractive and resisting forces for a data point calculate and return tractive and resisting forces for a data point
""" """
function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Dict, massModel::String) function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Dict, massModel)
# calculate resisting forces # calculate resisting forces
dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train)
dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train)
@ -108,7 +93,7 @@ end #function calculateForces!
""" """
TODO TODO
""" """
function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, csId::Integer) function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer)
# stepSize is the currentStepSize depending on the accessing function # stepSize is the currentStepSize depending on the accessing function
# TODO: csId is only for error messages. Should it be removed? # TODO: csId is only for error messages. Should it be removed?
#= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =#
@ -118,7 +103,7 @@ function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, cs
newPoint[:i] = previousPoint[:i]+1 # identifier newPoint[:i] = previousPoint[:i]+1 # identifier
# calculate s, t, v, E # calculate s, t, v, E
if stepVariable == "s in m" # distance step method if stepVariable == :distance # distance step method
newPoint[:Δs] = stepSize # step size (in m) newPoint[:Δs] = stepSize # step size (in m)
if previousPoint[:a] == 0.0 if previousPoint[:a] == 0.0
if previousPoint[:v] == 0.0 if previousPoint[:v] == 0.0
@ -138,12 +123,12 @@ function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, cs
newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s)
end end
elseif stepVariable == "t in s" # time step method elseif stepVariable == :time # time step method
newPoint[:Δt] = stepSize # step size (in s) newPoint[:Δt] = stepSize # step size (in s)
newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m)
newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s)
elseif stepVariable == "v in m/s" # velocity step method elseif stepVariable == :velocity # velocity step method
if previousPoint[:a] == 0.0 if previousPoint[:a] == 0.0
if previousPoint[:v] == 0.0 if previousPoint[:v] == 0.0
error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".")
@ -203,7 +188,7 @@ end #function getNextPointOfInterest
## This function calculates the data points of the breakFree section. ## This function calculates the data points of the breakFree section.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for breakFree if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for breakFree if needed.
# Info: currently the values of the breakFree section will be calculated like in the accelerating section # Info: currently the values of the breakFree section will be calculated like in the accelerating section
function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
# conditions for the break free section # conditions for the break free section
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
trainIsHalting = drivingCourse[end][:v] == 0.0 trainIsHalting = drivingCourse[end][:v] == 0.0
@ -213,7 +198,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) # currently the tractive effort is calculated like in the accelerating section calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel) # currently the tractive effort is calculated like in the accelerating section
# calculate the breakFree section with calculating the accelerating section and just using the first step and removing the rest # calculate the breakFree section with calculating the accelerating section and just using the first step and removing the rest
try (CS, drivingCourse, stateFlags) = addAcceleratingSection!(CS, drivingCourse, stateFlags, settings, train, CSs) try (CS, drivingCourse, stateFlags) = addAcceleratingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
@ -272,7 +257,7 @@ end #function addBreakFreeSection!
## This function calculates the data points of the clearing section. ## This function calculates the data points of the clearing section.
# Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the clearing section. # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the clearing section.
function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
if stateFlags[:previousSpeedLimitReached] if stateFlags[:previousSpeedLimitReached]
currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length])
@ -287,7 +272,7 @@ function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s]) s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s])
if s_clearing > 0.0 if s_clearing > 0.0
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_clearing, settings, train, CSs, "clearing") (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_clearing, settings, train, CSs, "clearing")
calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel)
# stateFlags[:brakingStartReached] = brakingStartReached # stateFlags[:brakingStartReached] = brakingStartReached
# stateFlags[:endOfCSReached] = stateFlags[:endOfCSReached] || drivingCourse[end][:s] == CS[:s_exit] # stateFlags[:endOfCSReached] = stateFlags[:endOfCSReached] || drivingCourse[end][:s] == CS[:s_exit]
else else
@ -305,14 +290,14 @@ end #function addClearingSection
## This function calculates the data points of the accelerating section. ## This function calculates the data points of the accelerating section.
# Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the accelerating section # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the accelerating section
function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
#function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}, ignoreBraking::Bool) #function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Dict, CSs::Vector{Dict}, ignoreBraking::Bool)
#=if drivingCourse would also be part of movingSectiong: function addAcceleratingSection!(movingSection::Dict, stateFlags::Dict, csId::Integer, settings::Dict, train::Dict) #=if drivingCourse would also be part of movingSectiong: function addAcceleratingSection!(movingSection::Dict, stateFlags::Dict, csId::Integer, settings::Settings, train::Dict)
CSs = movingSection[:characteristicSections] CSs = movingSection[:characteristicSections]
CS = CSs[csId] CS = CSs[csId]
drivingCourse = movingSection[:drivingCourse]=# drivingCourse = movingSection[:drivingCourse]=#
calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel)
if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics]
ignoreBraking = true ignoreBraking = true
@ -340,11 +325,11 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
#speedLimitReached = drivingCourse[end][:v] > currentSpeedLimit[:v] #speedLimitReached = drivingCourse[end][:v] > currentSpeedLimit[:v]
#targetSpeedReached = speedLimitReached #targetSpeedReached = speedLimitReached
while !targetSpeedReached && !endOfCSReached && tractionSurplus && !brakingStartReached && !previousSpeedLimitReached while !targetSpeedReached && !endOfCSReached && tractionSurplus && !brakingStartReached && !previousSpeedLimitReached
currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections currentStepSize = settings.stepSize # initialize the step size that can be reduced near intersections
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
if !ignoreBraking if !ignoreBraking
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking])
end end
@ -360,11 +345,11 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train])
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
# conditions for the next while cycle # conditions for the next while cycle
if !ignoreBraking if !ignoreBraking
@ -386,41 +371,41 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
end end
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] if drivingCourse[end][:F_T] <= drivingCourse[end][:F_R]
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," <= F_R=",drivingCourse[end][:F_R]) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," <= F_R=",drivingCourse[end][:F_R]) # for testing
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit] elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit]
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end][:s] > nextPointOfInterest elseif drivingCourse[end][:s] > nextPointOfInterest
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] > CS[:v_peak] elseif drivingCourse[end][:v] > CS[:v_peak]
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=",CS[:v_peak]) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=",CS[:v_peak]) # for testing
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == :speed
currentStepSize = CS[:v_peak]-drivingCourse[end-1][:v] currentStepSize = CS[:v_peak]-drivingCourse[end-1][:v]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] > currentSpeedLimit[:v] elseif drivingCourse[end][:v] > currentSpeedLimit[:v]
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_limitCurrent=",currentSpeedLimit[:v]) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_limitCurrent=",currentSpeedLimit[:v]) # for testing
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == :velocity
currentStepSize = currentSpeedLimit[:v]-drivingCourse[end-1][:v] currentStepSize = currentSpeedLimit[:v]-drivingCourse[end-1][:v]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] +s_braking == CS[:s_exit] elseif drivingCourse[end][:s] + s_braking == CS[:s_exit]
testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing
if s_braking == 0.0 if s_braking == 0.0
endOfCSReached = true endOfCSReached = true
@ -447,7 +432,7 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla
println("s=" ,drivingCourse[end][:s]," s_exit=", CS[:s_exit], " s+s_braking=", drivingCourse[end][:s] +s_braking," nextPOI=",nextPointOfInterest) println("s=" ,drivingCourse[end][:s]," s_exit=", CS[:s_exit], " s+s_braking=", drivingCourse[end][:s] +s_braking," nextPOI=",nextPointOfInterest)
println("F_T=",drivingCourse[end][:F_T] ," F_R=", drivingCourse[end][:F_R]) println("F_T=",drivingCourse[end][:F_T] ," F_R=", drivingCourse[end][:F_R])
error("ERROR at accelerating section: With the step variable ",settings[:stepVariable]," the while loop will be left although v<v_peak and s<s_exit in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") error("ERROR at accelerating section: With the step variable ",settings.stepVariable," the while loop will be left although v<v_peak and s<s_exit in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s")
end end
# delete last data point for recalculating the last step with reduced step size # delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse) pop!(drivingCourse)
@ -551,15 +536,15 @@ end #function addAcceleratingSection!
## This function calculates the data points of the cruising section. ## This function calculates the data points of the cruising section.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed.
function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, s_cruising::Real, settings::Dict, train::Dict, CSs::Vector{Dict}, cruisingType::String) function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, s_cruising::Real, settings::Settings, train::Dict, CSs::Vector{Dict}, cruisingType::String)
trainIsClearing = cruisingType == "clearing" trainIsClearing = cruisingType == "clearing"
trainIsBrakingDownhill = cruisingType == "downhillBraking" trainIsBrakingDownhill = cruisingType == "downhillBraking"
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
if !trainIsBrakingDownhill # TODO: or just give BS[:type] instead of "cruising"/"braking"? if !trainIsBrakingDownhill # TODO: or just give BS[:type] instead of "cruising"/"braking"?
calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
else else
calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel)
end end
if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics]
@ -587,14 +572,14 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry]) s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry])
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
#03/25 calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) #03/25 calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
if !trainIsBrakingDownhill if !trainIsBrakingDownhill
calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
else else
calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel)
end end
if settings[:massModel]=="homogeneous strip" && CS[:id] > 1 if settings.massModel == :homogeneous_strip && CS[:id] > 1
# conditions for cruising section # conditions for cruising section
trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train[:length] trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train[:length]
targetPositionReached = drivingCourse[end][:s] >= BS[:s_entry] +s_cruising targetPositionReached = drivingCourse[end][:s] >= BS[:s_entry] +s_cruising
@ -604,11 +589,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
#&& targetSpeedReached #&& targetSpeedReached
# use the conditions for the cruising section # use the conditions for the cruising section
while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
currentStepSize = settings[:stepSize] currentStepSize = settings.stepSize
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
while trainInPreviousCS && !targetPositionReached && !pointOfInterestReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used while trainInPreviousCS && !targetPositionReached && !pointOfInterestReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used
# 03/09 old: while drivingCourse[end][:s] < CS[:s_entry] + train[:length] && drivingCourse[end][:s] < BS[:s_entry] +s_cruising && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:F_T]>=drivingCourse[end][:F_R] # 03/09 old: while drivingCourse[end][:s] < CS[:s_entry] + train[:length] && drivingCourse[end][:s] < BS[:s_entry] +s_cruising && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:F_T]>=drivingCourse[end][:F_R]
# the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_peak OR the mass model homogeneous strip is used and parts of the train are still in former CS # the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_peak OR the mass model homogeneous strip is used and parts of the train are still in former CS
@ -626,21 +611,21 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
drivingCourse[end][:a] = 0.0 drivingCourse[end][:a] = 0.0
# create the next data point # create the next data point
if settings[:stepVariable] =="s in m" || settings[:stepVariable] =="t in s" if settings.stepVariable == :distance || settings.stepVariable == time
push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
else else
push!(drivingCourse, moveAStep(drivingCourse[end], "s in m", train[:length]/(10.0^cycle), CS[:id])) # TODO which step size should be used? push!(drivingCourse, moveAStep(drivingCourse[end], position, train[:length]/(10.0^cycle), CS[:id])) # TODO which step size should be used?
end end
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel)
# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
#if !trainIsBrakingDownhill #if !trainIsBrakingDownhill
# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
#else #else
# calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel)
#end #end
# conditions for the next while cycle # conditions for the next while cycle
@ -652,28 +637,28 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
end #while end #while
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:F_T] < drivingCourse[end][:F_R] if drivingCourse[end][:F_T] < drivingCourse[end][:F_R]
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif !trainIsBrakingDownhill && resistingForceNegative elseif !trainIsBrakingDownhill && resistingForceNegative
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif trainIsBrakingDownhill && !resistingForceNegative elseif trainIsBrakingDownhill && !resistingForceNegative
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end][:s] > nextPointOfInterest elseif drivingCourse[end][:s] > nextPointOfInterest
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] > BS[:s_entry] + s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train[:length])) elseif drivingCourse[end][:s] > BS[:s_entry] + s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train[:length]))
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize=BS[:s_entry] + s_cruising-drivingCourse[end-1][:s] currentStepSize=BS[:s_entry] + s_cruising-drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] == BS[:s_entry] + s_cruising # || drivingCourse[end][:s]==CS[:s_exit] elseif drivingCourse[end][:s] == BS[:s_entry] + s_cruising # || drivingCourse[end][:s]==CS[:s_exit]
@ -689,7 +674,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
break break
else else
error("ERROR at cruising section: With the step variable ",settings[:stepVariable]," the while loop will be left although the if cases don't apply in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") error("ERROR at cruising section: With the step variable ",settings.stepVariable," the while loop will be left although the if cases don't apply in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s")
end end
# delete last data point for recalculating the last step with reduced step size # delete last data point for recalculating the last step with reduced step size
@ -757,16 +742,16 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
s_cruisingRemaining = min(nextPointOfInterest -drivingCourse[end][:s], BS[:s_entry] +s_cruising -drivingCourse[end][:s]) s_cruisingRemaining = min(nextPointOfInterest -drivingCourse[end][:s], BS[:s_entry] +s_cruising -drivingCourse[end][:s])
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], "s in m", s_cruisingRemaining, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel)
# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
#if !trainIsBrakingDownhill #if !trainIsBrakingDownhill
# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel)
#else #else
# calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel)
#end #end
# conditions for the next while cycle # conditions for the next while cycle
@ -808,8 +793,8 @@ end #function addCruisingSection!
## This function calculates the data points for diminishing run when using maximum tractive effort and still getting slower ## This function calculates the data points for diminishing run when using maximum tractive effort and still getting slower
function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
calculateForces!(drivingCourse[end], CSs, CS[:id], "diminishing", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "diminishing", train, settings.massModel)
if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics]
ignoreBraking = true ignoreBraking = true
@ -832,22 +817,22 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached
currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
while tractionDeficit && !brakingStartReached && !pointOfInterestReached && !targetSpeedReached while tractionDeficit && !brakingStartReached && !pointOfInterestReached && !targetSpeedReached
# 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end # 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train])
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
# conditions for the next while cycle # conditions for the next while cycle
if !ignoreBraking if !ignoreBraking
@ -867,27 +852,27 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
end end
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:v] < 0.0 if drivingCourse[end][:v] < 0.0
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == velocity
currentStepSize = drivingCourse[end-1][:v] currentStepSize = drivingCourse[end-1][:v]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R]
testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit] elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit]
testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end][:s] > nextPointOfInterest elseif drivingCourse[end][:s] > nextPointOfInterest
testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] elseif drivingCourse[end][:s] + s_braking == CS[:s_exit]
@ -908,7 +893,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag
" F_T=",drivingCourse[end-1][:F_T]," N R_traction=",drivingCourse[end-1][:R_traction]," N R_wagons=",drivingCourse[end-1][:R_wagons]," N R_path=",drivingCourse[end-1][:R_path]," N.") " F_T=",drivingCourse[end-1][:F_T]," N R_traction=",drivingCourse[end-1][:R_traction]," N R_wagons=",drivingCourse[end-1][:R_wagons]," N R_path=",drivingCourse[end-1][:R_path]," N.")
else else
error("ERROR during diminishing run: With the step variable ",settings[:stepVariable]," the while loop will be left although s+s_braking<s_exit && v>0.0 in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") error("ERROR during diminishing run: With the step variable ",settings.stepVariable," the while loop will be left although s+s_braking<s_exit && v>0.0 in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s")
end end
# delete last data point for recalculating the last step with reduced step size # delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse) pop!(drivingCourse)
@ -995,7 +980,7 @@ end #function addDiminishingSection!
## This function calculates the data points of the coasting section. ## This function calculates the data points of the coasting section.
# Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the coasting section # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the coasting section
function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
# TODO: if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept # TODO: if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept
# with getCurrentSpeedLimit # with getCurrentSpeedLimit
@ -1012,21 +997,21 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
while !targetSpeedReached && !endOfCSReached && !brakingStartReached while !targetSpeedReached && !endOfCSReached && !brakingStartReached
currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
while !targetSpeedReached && !brakingStartReached && !pointOfInterestReached while !targetSpeedReached && !brakingStartReached && !pointOfInterestReached
# 03/09 old : while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:v] <= CS[:v_peak] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest # 03/09 old : while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:v] <= CS[:v_peak] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest
# traction effort and resisting forces (in N): # traction effort and resisting forces (in N):
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train])
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
@ -1040,33 +1025,33 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
testFlag = false testFlag = false
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
if cycle < approximationLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:s] + s_braking > CS[:s_exit] if drivingCourse[end][:s] + s_braking > CS[:s_exit]
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
elseif drivingCourse[end][:s] > nextPointOfInterest elseif drivingCourse[end][:s] > nextPointOfInterest
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == velocity
currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] > CS[:v_peak] elseif drivingCourse[end][:v] > CS[:v_peak]
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == velocity
currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v] currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] elseif drivingCourse[end][:s] + s_braking == CS[:s_exit]
testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing
@ -1082,7 +1067,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::
else else
# TODO: not needed. just for testing # TODO: not needed. just for testing
error("ERROR at coasting until braking section: With the step variable ",settings[:stepVariable]," the while loop will be left although v<v_peak and s+s_braking<s_exit in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") error("ERROR at coasting until braking section: With the step variable ",settings.stepVariable," the while loop will be left although v<v_peak and s+s_braking<s_exit in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s")
end end
# delete last data point for recalculating the last step with reduced step size # delete last data point for recalculating the last step with reduced step size
pop!(drivingCourse) pop!(drivingCourse)
@ -1158,7 +1143,7 @@ end #function addCoastingSection!
## This function calculates the data points of the braking section. ## This function calculates the data points of the braking section.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed.
function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Dict, CSs::Vector{Dict})
# conditions for braking section # conditions for braking section
targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit]
endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached]
@ -1169,21 +1154,21 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
while !targetSpeedReached && !endOfCSReached while !targetSpeedReached && !endOfCSReached
currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections currentStepSize = settings.stepSize # initialize the step size that can be reduced near intersections
nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])
pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest
for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation
while !targetSpeedReached && !endOfCSReached && !pointOfInterestReached while !targetSpeedReached && !endOfCSReached && !pointOfInterestReached
# 03/09 old: while drivingCourse[end][:v] > CS[:v_exit] && !targetSpeedReached && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:s] < nextPointOfInterest # 03/09 old: while drivingCourse[end][:v] > CS[:v_exit] && !targetSpeedReached && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:s] < nextPointOfInterest
# traction effort and resisting forces (in N): # traction effort and resisting forces (in N):
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
# acceleration (in m/s^2): # acceleration (in m/s^2):
drivingCourse[end][:a] = train[:a_braking] drivingCourse[end][:a] = train[:a_braking]
# TODO or: drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s]) # TODO or: drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s])
if settings[:stepVariable] == "s in m" && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 if settings.stepVariable == :distance && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0
# create empty data point and set it for the values of s_exit and v_exit # create empty data point and set it for the values of s_exit and v_exit
push!(drivingCourse, createDataPoint()) push!(drivingCourse, createDataPoint())
drivingCourse[end][:i] = drivingCourse[end-1][:i]+1 drivingCourse[end][:i] = drivingCourse[end-1][:i]+1
@ -1192,7 +1177,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
recalculateLastBrakingPoint!(drivingCourse, CS[:s_exit], CS[:v_exit]) recalculateLastBrakingPoint!(drivingCourse, CS[:s_exit], CS[:v_exit])
else else
# create the next data point # create the next data point
push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id]))
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
push!(BS[:dataPoints], drivingCourse[end][:i]) push!(BS[:dataPoints], drivingCourse[end][:i])
end end
@ -1206,18 +1191,18 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
# check which limit was reached and adjust the currentStepSize for the next cycle # check which limit was reached and adjust the currentStepSize for the next cycle
# TODO: is there a better way than rounding like in the following? # TODO: is there a better way than rounding like in the following?
if cycle < approximationLevel+1 if cycle < settings.approxLevel+1
if drivingCourse[end][:v] < CS[:v_exit] if drivingCourse[end][:v] < CS[:v_exit]
if settings[:stepVariable] == "v in m/s" if settings.stepVariable == velocity
currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:s] > nextPointOfInterest elseif drivingCourse[end][:s] > nextPointOfInterest
if settings[:stepVariable] == "s in m" if settings.stepVariable == :distance
currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s]
else else
currentStepSize = settings[:stepSize] / 10.0^cycle currentStepSize = settings.stepSize / 10.0^cycle
end end
elseif drivingCourse[end][:v] == CS[:v_exit] && drivingCourse[end][:s] == CS[:s_exit] elseif drivingCourse[end][:v] == CS[:v_exit] && drivingCourse[end][:s] == CS[:s_exit]
break break
@ -1306,7 +1291,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D
stateFlags[:speedLimitReached] = drivingCourse[end][:v] >= CS[:v_exit] stateFlags[:speedLimitReached] = drivingCourse[end][:v] >= CS[:v_exit]
stateFlags[:endOfCSReached] = endOfCSReached stateFlags[:endOfCSReached] = endOfCSReached
stateFlags[:error] = !(endOfCSReached) stateFlags[:error] = !(endOfCSReached)
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel)
stateFlags[:resistingForceNegative] = drivingCourse[end][:F_R] < 0 stateFlags[:resistingForceNegative] = drivingCourse[end][:F_R] < 0
return (CS, drivingCourse, stateFlags) return (CS, drivingCourse, stateFlags)
@ -1315,7 +1300,7 @@ end #function addBrakingSection!
## This function calculates the data point of the standstill. ## This function calculates the data point of the standstill.
# Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed.
function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Dict, CSs::Vector{Dict})
if drivingCourse[end][:v] == 0.0 if drivingCourse[end][:v] == 0.0
BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i])
merge!(BS, Dict(:length => 0.0, # total length (in m) merge!(BS, Dict(:length => 0.0, # total length (in m)
@ -1326,7 +1311,7 @@ function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, t
drivingCourse[end][:behavior] = BS[:type] drivingCourse[end][:behavior] = BS[:type]
# traction effort and resisting forces (in N) # traction effort and resisting forces (in N)
calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel)
merge!(CS[:behaviorSections], Dict(:standstill => BS)) merge!(CS[:behaviorSections], Dict(:standstill => BS))
end # else: return the characteristic section without a standstillSection section end # else: return the characteristic section without a standstillSection section
@ -1411,5 +1396,3 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target)
currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws) currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws)
currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws) currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws)
end #function recalculateLastBrakingPoint end #function recalculateLastBrakingPoint
end #module Behavior

View File

@ -5,83 +5,55 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module TrainRunCalc
# include modules of TrainRunCalc
include("./Validate.jl")
include("./Characteristics.jl")
include("./Behavior.jl")
include("./Output.jl")
# use modules of TrainRunCalc
using .Validate
using .Characteristics
using .Behavior
using .Output
# export main function
export trainRun
approximationLevel = 6 # value for approximation to intersections and precisely calculated digits
# TODO: define it here and give it to each function? (Behavior, ...)
# Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`. # Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`.
""" """
trainRun(train::Dict, path::Dict, settings::Dict) trainRun(train::Dict, path::Dict, settings::Settings)
Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding dictionaries `train`, `path`, `settings`. Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding dictionaries `train`, `path`, `settings`.
# Examples # Examples
```julia-repl ```julia-repl
julia> trainRun(trainDict, pathDict, settingsDict) julia> trainRun(trainDict, pathDict)
todo !!! todo !!!
``` ```
""" """
function trainRun(trainInput::Dict, pathInput::Dict, settingsInput::Dict) function trainRun(trainInput::Dict, pathInput::Dict, settings=Settings()::Settings)
# copy Input data for not changing them # copy Input data for not changing them
# TODO: or should they be changed? normally it would only make it "better" except for settings[:detailOfOutput] == "points of interest" && !haskey(path, :pointsOfInterest) # TODO: or should they be changed? normally it would only make it "better" except for settings.outputDetail == :points_of_interest && !haskey(path, :pointsOfInterest)
train = copy(trainInput) train = copy(trainInput)
path = copy(pathInput) path = copy(pathInput)
settings = copy(settingsInput)
# check the input data # check the input data
(train, path, settings) = checkAndSetInput!(train, path, settings) (train, path) = checkAndSetInput!(train, path, settings)
settings[:detailOfOutput] == "everything" && println("The input has been checked.") settings.outputDetail == :everything && println("The input has been checked.")
# prepare the input data # prepare the input data
movingSection = determineCharacteristics(path, train, settings) movingSection = determineCharacteristics(path, train, settings)
settings[:detailOfOutput] == "everything" && println("The moving section has been prepared.") settings.outputDetail == :everything && println("The moving section has been prepared.")
# calculate the train run for oparation mode "minimum running time" # calculate the train run for oparation mode "minimum running time"
if settings[:operationModeMinimumRunningTime] || settings[:operationModeMinimumEnergyConsumption] (movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train)
(movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train) settings.outputDetail == :everything && println("The driving course for the shortest running time has been calculated.")
settings[:detailOfOutput] == "everything" && println("The driving course for the shortest running time has been calculated.")
# accumulate data and create an output dictionary # accumulate data and create an output dictionary
output = createOutput(train, settings, path, movingSection, drivingCourse) output = createOutput(train, settings, path, movingSection, drivingCourse)
# 30/31 old: output = createOutputDict(train, settings, path, movingSection, drivingCourse)
else
output = nothing
# 30/31 old: output = Dict()
end #if
return output return output
end # function trainRun end # function trainRun
# calculate a train run focussing on using the minimum possible running time # calculate a train run focussing on using the minimum possible running time
function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train::Dict) function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, train::Dict)
CSs::Vector{Dict} = movingSection[:characteristicSections] CSs::Vector{Dict} = movingSection[:characteristicSections]
if settings[:massModel] == "homogeneous strip" && settings[:stepVariable] == "v in m/s" if settings.massModel == :homogeneous_strip && settings.stepVariable == speed
println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !")
end end
startingPoint=createDataPoint() startingPoint=createDataPoint()
startingPoint[:i]=1 startingPoint[:i]=1
startingPoint[:s]=CSs[1][:s_entry] startingPoint[:s]=CSs[1][:s_entry]
calculateForces!(startingPoint, CSs, 1, "default", train, settings[:massModel]) # traction effort and resisting forces (in N) calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N)
drivingCourse::Vector{Dict} = [startingPoint] # List of data points drivingCourse::Vector{Dict} = [startingPoint] # List of data points
for csId in 1:length(CSs) for csId in 1:length(CSs)
@ -96,7 +68,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train
# determine the different flags for switching between the states for creatinge moving phases # determine the different flags for switching between the states for creatinge moving phases
s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking])
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) # tractive effort and resisting forces (in N) calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N)
previousSpeedLimitReached = false previousSpeedLimitReached = false
stateFlags = Dict(:endOfCSReached => drivingCourse[end][:s] > CS[:s_exit], stateFlags = Dict(:endOfCSReached => drivingCourse[end][:s] > CS[:s_exit],
@ -122,11 +94,11 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached] elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
# cruise only one step # cruise only one step
if settings[:stepVariable] =="s in m" if settings.stepVariable == :distance
s_cruising = settings[:stepSize] s_cruising = settings.stepSize
elseif settings[:stepVariable] =="t in s" elseif settings.stepVariable == time
s_cruising = calc_Δs_with_Δt(settings[:stepSize], drivingCourse[end][:a], drivingCourse[end][:v]) s_cruising = calc_Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v])
elseif settings[:stepVariable] =="v in m/s" elseif settings.stepVariable == velocity
s_cruising = train[:length]/(10.0) # TODO which step size should be used? s_cruising = train[:length]/(10.0) # TODO which step size should be used?
end end
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
@ -186,5 +158,3 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train
return (movingSection, drivingCourse) return (movingSection, drivingCourse)
end #function calculateMinimumRunningTime end #function calculateMinimumRunningTime
end # module TrainRunCalc

View File

@ -5,15 +5,8 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module Characteristics
include("./Behavior.jl")
using .Behavior
export determineCharacteristics
## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior ## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior
function determineCharacteristics(path::Dict, train::Dict, settings::Dict) function determineCharacteristics(path::Dict, train::Dict, settings::Settings)
movingSection = createMovingSection(path, train[:v_limit]) movingSection = createMovingSection(path, train[:v_limit])
movingSection = secureBrakingBehavior!(movingSection, train[:a_braking]) movingSection = secureBrakingBehavior!(movingSection, train[:a_braking])
movingSection = secureAcceleratingBehavior!(movingSection, settings, train) movingSection = secureAcceleratingBehavior!(movingSection, settings, train)
@ -123,7 +116,7 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real)
end #function secureBrakingBehavior! end #function secureBrakingBehavior!
## define the intersection velocities between the characterisitc sections to secure accelerating behavior ## define the intersection velocities between the characterisitc sections to secure accelerating behavior
function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train::Dict) function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Dict)
# this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards # this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards
CSs = movingSection[:characteristicSections] CSs = movingSection[:characteristicSections]
@ -136,7 +129,7 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train:
CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) CS[:v_entry] = min(CS[:v_entry], previousCSv_exit)
startingPoint[:s] = CS[:s_entry] startingPoint[:s] = CS[:s_entry]
startingPoint[:v] = CS[:v_entry] startingPoint[:v] = CS[:v_entry]
calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings[:massModel]) # traction effort and resisting forces (in N) calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N)
acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points
if CS[:v_entry] < CS[:v_peak] if CS[:v_entry] < CS[:v_peak]
@ -160,7 +153,7 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train:
(CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit (CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit
end end
else else
if settings[:massModel] == "mass point" || acceleratingCourse[end][:s] > CS[:s_entry] + train[:length] if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train[:length]
break break
else else
(CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort (CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
@ -190,7 +183,7 @@ end #function secureAcceleratingBehavior!
#= #=
## define the intersection velocities between the characterisitc sections to secure cruising behavior ## define the intersection velocities between the characterisitc sections to secure cruising behavior
function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dict) function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Dict)
# limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak
CSs = movingSection[:characteristicSections] CSs = movingSection[:characteristicSections]
@ -225,7 +218,7 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic
(CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking") (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking")
end end
else else
if settings[:massModel] == "mass point" || cruisingCourse[end][:s] > CS[:s_entry] + train[:length] if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train[:length]
break break
else else
(CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort (CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort
@ -246,4 +239,3 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic
return movingSection return movingSection
end #function secureCruisingBehavior! end #function secureCruisingBehavior!
=# =#
end #module Characteristics

File diff suppressed because it is too large Load Diff

View File

@ -5,32 +5,26 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module Export function exportToCsv(runningTime::AbstractFloat, settings::Settings)
using CSV, DataFrames, Dates
export exportToCsv
function exportToCsv(runningTime::AbstractFloat, settings::Dict)
createCsvFile(runningTime, settings) createCsvFile(runningTime, settings)
return true return true
end end
function exportToCsv(dataPointsToExport::Vector{Dict}, settings::Dict) function exportToCsv(dataPointsToExport::Vector{Dict}, settings::Settings)
createCsvFile(dataPointsToExport, settings) createCsvFile(dataPointsToExport, settings)
return true return true
end end
function exportToCsv(output::Dict) function exportToCsv(output::Dict)
if output[:settings][:typeOfOutput] == "CSV" if output[:settings][:outputFormat] == "CSV"
pathName = output[:path][:name] pathName = output[:path][:name]
trainName = output[:train][:name] trainName = output[:train][:name]
if output[:settings][:operationModeMinimumRunningTime] == true if output[:settings][:operationModeMinimumRunningTime] == true
operationMode = "minimum running time" operationMode = "minimum running time"
if output[:settings][:detailOfOutput] == "points of interest" if output[:settings][:outputDetail] == "points of interest"
dataPointsToExport = output[:pointsOfInterestMinimumRunningTime] dataPointsToExport = output[:pointsOfInterestMinimumRunningTime]
else else
dataPointsToExport = output[:drivingCourseMinimumRunningTime] dataPointsToExport = output[:drivingCourseMinimumRunningTime]
@ -39,7 +33,7 @@ function exportToCsv(output::Dict)
end end
if output[:settings][:operationModeMinimumEnergyConsumption] == true if output[:settings][:operationModeMinimumEnergyConsumption] == true
operationMode = "minimum energy consumption" operationMode = "minimum energy consumption"
if output[:settings][:detailOfOutput] == "points of interest" if output[:settings][:outputDetail] == "points of interest"
dataPointsToExport = output[:pointsOfInterestMinimumEnergyConsumption] dataPointsToExport = output[:pointsOfInterestMinimumEnergyConsumption]
else else
dataPointsToExport = output[:drivingCourseMinimumEnergyConsumption] dataPointsToExport = output[:drivingCourseMinimumEnergyConsumption]
@ -51,15 +45,15 @@ function exportToCsv(output::Dict)
return false return false
end #function exportToCsv end #function exportToCsv
function createCsvFile(runningTime::AbstractFloat, settings::Dict) function createCsvFile(runningTime::AbstractFloat, settings::Settings)
# create DataFrame with running time information # create DataFrame with running time information
df = DataFrame(column1=["t (in s)", runningTime]) df = DataFrame(column1=["t (in s)", runningTime])
# save DataFrame as a CSV-file at csvDirectory # save DataFrame as a CSV-file at outputDir
date = Dates.now() date = Dates.now()
dateString = Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString = Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath = settings[:csvDirectory]*"/"*dateString*"_RunningTime.csv" csvFilePath = settings[:outputDir]*"/"*dateString*"_RunningTime.csv"
CSV.write(csvFilePath, df, header=false) CSV.write(csvFilePath, df, header=false)
println("The output CSV file has been created at ",csvFilePath) println("The output CSV file has been created at ",csvFilePath)
@ -68,8 +62,8 @@ function createCsvFile(runningTime::AbstractFloat, settings::Dict)
end #function createCsvFile end #function createCsvFile
function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Dict) function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Settings)
detailOfOutput = settings[:detailOfOutput] outputDetail = settings[:outputDetail]
header = ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"] header = ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]
columnSymbols = [:i, :behavior, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :ΔW, :W, :ΔE, :E, :a] columnSymbols = [:i, :behavior, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :ΔW, :W, :ΔE, :E, :a]
@ -85,8 +79,8 @@ function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Dict)
end # for end # for
# combine the columns in a data frame and saving it as a CSV-file at csvDirectory # combine the columns in a data frame and saving it as a CSV-file at outputDir
if detailOfOutput == "driving course" || detailOfOutput == "points of interest" if outputDetail == "driving course" || outputDetail == "points of interest"
df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
else else
@ -95,7 +89,7 @@ function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Dict)
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
csvFilePath=settings[:csvDirectory]*"/"*dateString*"_DataPoints.csv" csvFilePath=settings[:outputDir]*"/"*dateString*"_DataPoints.csv"
CSV.write(csvFilePath, df, header=false) CSV.write(csvFilePath, df, header=false)
println("The output CSV file has been created at ",csvFilePath) println("The output CSV file has been created at ",csvFilePath)
@ -103,12 +97,12 @@ function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Dict)
end #function createCsvFile end #function createCsvFile
function createCsvFile(dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Dict) function createCsvFile(dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Settings)
detailOfOutput = settings[:detailOfOutput] outputDetail = settings[:outputDetail]
massModel = settings[:massModel] massModel = settings.massModel
stepVariable = settings[:stepVariable] stepVariable = settings.stepVariable
stepSize = string(settings[:stepSize]) stepSize = string(settings.stepSize)
# create accumulated data block # create accumulated data block
accumulatedData = Array{Any, 1}[] accumulatedData = Array{Any, 1}[]
@ -135,15 +129,15 @@ function createCsvFile(dataPointsToExport::Vector{Dict}, operationMode::String,
end end
end # for end # for
# combine the columns in a data frame and saving it as a CSV-file at csvDirectory # combine the columns in a data frame and saving it as a CSV-file at outputDir
df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
if operationMode == "minimum running time" if operationMode == "minimum running time"
csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumRunningTime.csv" csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumRunningTime.csv"
elseif operationMode == "minimum energy consumption" elseif operationMode == "minimum energy consumption"
csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumEnergyConsumption.csv" csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumEnergyConsumption.csv"
else else
# should not be possible # should not be possible
end end
@ -156,20 +150,20 @@ end #function createCsvFile
#= #=
function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Dict) function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Settings)
detailOfOutput = settings[:detailOfOutput] outputDetail = settings[:outputDetail]
massModel = settings[:massModel] massModel = settings.massModel
stepVariable = settings[:stepVariable] stepVariable = settings.stepVariable
stepSize = string(settings[:stepSize]) stepSize = string(settings.stepSize)
# create accumulated data block # create accumulated data block
accumulatedData = Array{Any, 1}[] accumulatedData = Array{Any, 1}[]
if detailOfOutput == "minimal" if outputDetail == "minimal"
push!(accumulatedData, ["s (in m)", "t (in s)","E (in Ws)"]) # push header to accumulatedData push!(accumulatedData, ["s (in m)", "t (in s)","E (in Ws)"]) # push header to accumulatedData
row = [movingSection[:length], movingSection[:t], movingSection[:E]] row = [movingSection[:length], movingSection[:t], movingSection[:E]]
push!(accumulatedData, row) # push row to accumulatedData push!(accumulatedData, row) # push row to accumulatedData
elseif detailOfOutput == "driving course" || detailOfOutput == "points of interest" elseif outputDetail == "driving course" || outputDetail == "points of interest"
push!(accumulatedData, ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData push!(accumulatedData, ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData
for point in dataPointsToExport for point in dataPointsToExport
row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]] row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]]
@ -194,19 +188,19 @@ function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, op
end end
end # for end # for
# combine the columns in a data frame and saving it as a CSV-file at csvDirectory # combine the columns in a data frame and saving it as a CSV-file at outputDir
if detailOfOutput == "minimal" if outputDetail == "minimal"
df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3])
elseif detailOfOutput=="driving course" || detailOfOutput == "points of interest" elseif outputDetail=="driving course" || outputDetail == "points of interest"
df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19])
end end
date = Dates.now() date = Dates.now()
dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS")
if operationMode == "minimum running time" if operationMode == "minimum running time"
csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumRunningTime.csv" csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumRunningTime.csv"
elseif operationMode == "minimum energy consumption" elseif operationMode == "minimum energy consumption"
csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumEnergyConsumption.csv" csvFilePath=settings[:outputDir]*"/"*dateString*"_MinimumEnergyConsumption.csv"
else else
# should not be possible # should not be possible
end end
@ -216,5 +210,3 @@ function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, op
return true return true
end #function createCsvFile end #function createCsvFile
=# =#
end #module Export

View File

@ -5,8 +5,6 @@
# __copyright__ = "2022" # __copyright__ = "2022"
# __license__ = "ISC" # __license__ = "ISC"
module Formulary
######################### #########################
## literature the driving dynamics equations are based on: ## literature the driving dynamics equations are based on:
## ##
@ -21,17 +19,6 @@ module Formulary
## isbn = {978-3-777-10462-1}, ## isbn = {978-3-777-10462-1},
## publisher = {Eurailpress DVV Media Group}, ## publisher = {Eurailpress DVV Media Group},
## } ## }
## @article{Jaekel:2014,
## author = {Jaekel, Birgit and Albrecht, Thomas},
## year = {2014},
## title = {Comparative analysis of algorithms and models for train running simulation},
## journal = {Journal of Rail Transport Planning \& Management},
## doi = {10.1016/j.jrtpm.2014.06.002},
## volume = {4},
## number = {1-2},
## pages = {14--27},
## publisher = {Elsevier},
## }
## @Book{Wende:2003, ## @Book{Wende:2003,
## author = {Wende, Dietrich}, ## author = {Wende, Dietrich},
## date = {2003}, ## date = {2003},
@ -41,25 +28,10 @@ module Formulary
## } ## }
######################### #########################
# export resisting forces and acceleration approxLevel = 6
export calcTractionUnitResistance, calcWagonsResistance, calcForceFromCoefficient, calcAcceleration,
# export step sizes in different units
calc_Δs_with_Δt, calc_Δs_with_Δv,
calc_Δt_with_Δs, calc_Δt_with_Δv, calc_Δt_with_constant_v,
calc_Δv_with_Δs, calc_Δv_with_Δt,
calc_ΔW, calc_ΔE,
# export braking information
calcBrakingDistance, calcBrakingStartVelocity, calcBrakingAcceleration
v00 = 100/3.6 # velocity factor (in m/s) v00 = 100/3.6 # velocity factor (in m/s)
g = 9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2 g = 9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2
approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s)
# TODO: necessary here?
## calculate forces ## calculate forces
#TODO: replace the ? ? ? #TODO: replace the ? ? ?
@ -213,8 +185,8 @@ function calc_ΔW(F_T_prev::Real, Δs::Real)
end #function calc_ΔW end #function calc_ΔW
function calc_ΔE(ΔW::Real) function calc_ΔE(ΔW::Real)
# simplified equation is based on [Jaekel:2014, page 6] # simplified equation
# TODO!
# ΔW: mechanical work in this step (in Ws) # ΔW: mechanical work in this step (in Ws)
ΔE = ΔW # energy consumption in this step (in Ws) ΔE = ΔW # energy consumption in this step (in Ws)
return ΔE return ΔE
@ -228,8 +200,8 @@ function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real)
# a_braking: constant braking acceleration (in m/s^2) # a_braking: constant braking acceleration (in m/s^2)
s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m)
# TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start) # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start)
# return max(0.0, ceil(s_braking, digits=approximationLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors # return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
return max(0.0, ceil(s_braking, digits=approximationLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors return max(0.0, ceil(s_braking, digits=approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors
end #function calcBrakingDistance end #function calcBrakingDistance
function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real)
@ -239,8 +211,8 @@ function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real)
# a_braking: constant braking acceleration (in m/s^2) # a_braking: constant braking acceleration (in m/s^2)
# s_braking: braking distance (in Ws) # s_braking: braking distance (in Ws)
v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s)
# return floor(v_start, digits=approximationLevel) # return floor(v_start, digits=approxLevel)
return floor(v_start, digits=approximationLevel +1) return floor(v_start, digits=approxLevel +1)
end #function calcBrakingStartVelocity end #function calcBrakingStartVelocity
function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)
@ -252,5 +224,3 @@ function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real)
a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2) a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2)
return a_braking return a_braking
end #function calcBrakingAcceleration end #function calcBrakingAcceleration
end #module Formulary

View File

@ -5,21 +5,14 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module Import
import YAML
export importYamlFiles, importFromYaml
""" """
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)
train = importFromYaml(:train, trainDirectory) train = importFromYaml(:train, trainDirectory)
path = importFromYaml(:path, pathDirectory) path = importFromYaml(:path, pathDirectory)
settings = importFromYaml(:settings, settingsDirectory)
return (train, path, settings) return (train, path)
end #function importYamlFiles end #function importYamlFiles
""" """
@ -40,5 +33,3 @@ function importFromYaml(dataType::Symbol, directory::String)
end end
return dictionary return dictionary
end # function importFromYaml end # function importFromYaml
end # module Input

View File

@ -5,15 +5,11 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
module Output function createOutput(train::Dict, settings::Settings, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
if settings.outputDetail == :running_time
export createOutput
function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
if settings[:detailOfOutput] == "running time"
output = movingSection[:t] # TODO: or use drivingCourse[end][:t] output = movingSection[:t] # TODO: or use drivingCourse[end][:t]
elseif settings[:detailOfOutput] == "points of interest" elseif settings.outputDetail == :points_of_interest
# add points of interest # add points of interest
if haskey(path, :pointsOfInterest) if haskey(path, :pointsOfInterest)
output = Vector{Dict}() output = Vector{Dict}()
@ -28,10 +24,10 @@ function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Di
end end
end end
elseif settings[:detailOfOutput] == "driving course" elseif settings.outputDetail == :driving_course
output = drivingCourse output = drivingCourse
elseif settings[:detailOfOutput] == "everything" elseif settings.outputDetail == :everything
output = Dict{Symbol,Any}() output = Dict{Symbol,Any}()
merge!(output, Dict(:train => train, :path => path, :settings => settings)) merge!(output, Dict(:train => train, :path => path, :settings => settings))
@ -71,7 +67,7 @@ function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Di
end end
#= #=
function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict}) function createOutputDict(train::Dict, settings::Settings, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict})
outputDict = Dict{Symbol,Any}() outputDict = Dict{Symbol,Any}()
merge!(outputDict, Dict(:train => train, :path => path, :settings => settings)) merge!(outputDict, Dict(:train => train, :path => path, :settings => settings))
@ -108,5 +104,3 @@ function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection
return outputDict return outputDict
end # function createOutputDict end # function createOutputDict
=# =#
end # module Output

View File

@ -1,55 +1,30 @@
#!/usr/bin/env julia #!/usr/bin/env julia
# -*- coding: UTF-8 -*- # -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.2 # __julia-version__ = 1.7.2
# __author__ = "Max Kannenberg" # __author__ = "Max Kannenberg, Martin Scheidt"
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
__precompile__(true)
module TrainRun module TrainRun
# include main module TrainRunCalc ## loading external packages
include("./TrainRunCalc.jl") using YAML, JSONSchema, CSV, DataFrames, Dates
# include additional modules ## include package files
include("./Import.jl") include("types.jl")
include("./Export.jl") include("formulary.jl")
include("characteristics.jl")
include("behavior.jl")
include("output.jl")
include("import.jl")
include("export.jl")
include("calc.jl")
# include additional modules that are not recommended to use in this state export
include("./AdditionalOutput.jl") ## Interface
include("./EnergySaving.jl") trainRun, Settings, exportToCsv
# use main module TrainRunCalc
using .TrainRunCalc
# use additional modules
using .Import
using .Export
# use additional modules that are not recommended to use in this state
using .AdditionalOutput
using .EnergySaving
# main function
export trainRun,
# import functions
importYamlFiles, importFromYaml,
# functions for saving energy that are not recommended to use in this state
addOperationModeEnergySaving!,
# export functions
exportToCsv,
# functions for visualising results that are not recommended to use in this state
plotResults, plotDrivingCourse, printImportantValues, printSectionInformation
# approximationLevel = 6 # value for approximation to intersections
# TODO: define it here and give it to each function? (Behavior, EnergySaving, ..)
"""
TODO: Package description
"""
## main functions
end # module TrainRun end # module TrainRun

View File

@ -1,31 +1,120 @@
#!/usr/bin/env julia #!/usr/bin/env julia
# -*- coding: UTF-8 -*- # -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.2 # __julia-version__ = 1.7.2
# __author__ = "Max Kannenberg" # __author__ = "Max Kannenberg, Martin Scheidt"
# __copyright__ = "2022" # __copyright__ = "2022"
# __license__ = "ISC" # __license__ = "ISC"
# TODO: 2022-04-07: if EnergySaving should be used. The train type has do be defined and checked """
module Validate Settings(file)
export checkAndSetInput! Settings is a datastruture for calculation context.
The function Settings() will create a set of settings for the train run calculation.
`file` is optinal may be used to load settings in the YAML format.
# Example
```jldoctest
julia> my_settings = Settings() # will generate default settings
Settings(mass_point, :distance, 20, 3, running_time, julia_dict, ".")
```
"""
struct Settings
approximationLevel = 6 # value for approximation to intersections TODO further explanation massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip".
stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity".
stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second.
approxLevel::Int # value for approximation; used when rounding or interating.
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest",
# complete Array() ":driving_course", or Dict() ":everything".
outputFormat::Symbol # output as ":julia_dict" or as ":csv".
outputDir::String # if outputFormat is not ":julia_dict".
## constructor
function Settings(file="DEFAULT")
## default values
massModel = :mass_point
stepVariable = :distance
stepSize = 20
approxLevel = 3
outputDetail = :running_time
outputFormat = :julia_dict
outputDir = "."
if file != "DEFAULT"
## JSON schema for YAML-file validation
schema = Schema("""{
"properties": {
"massModel": {
"description": "type of train model",
"type": "string",
"enum": [ "mass_point", "homogeneous_strip" ]
},
"stepVariable": {
"description": "variable of the linear multistep method",
"type": "string",
"enum": [ "distance", "time", "velocity" ]
},
"stepSize": {
"description": "step size acording to stepVariable",
"type": "number",
"exclusiveMinimum": 0
},
"outputDetail": {
"description": "Selecting the detail of the result",
"type": "string",
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ]
},
"outputFormat": {
"description": "Output format",
"type": "string",
"enum": [ "julia_dict", "csv" ]
},
"outputDir": {
"description": "Path for the CSV export",
"type": "string"
}
}
}""")
settings = YAML.load(open(file))["settings"]
## validate the loaded file
try
validate(schema, settings)
catch err
println("Could not load settings file $file.\n Format is not recognized - using default as fall back.")
settings = Dict()
end
## set the variables if they exist in "settings"
haskey(settings, "massModel") ? massModel = Symbol(settings["massModel"]) : nothing
haskey(settings, "stepVariable") ? stepVariable = Symbol(settings["stepVariable"]) : nothing
haskey(settings, "stepSize") ? stepSize = settings["stepSize"] : nothing
haskey(settings, "approxLevel") ? approxLevel = settings["approxLevel"] : nothing
haskey(settings, "outputDetail") ? outputDetail = Symbol(settings["outputDetail"]) : nothing
haskey(settings, "outputFormat") ? outputFormat = Symbol(settings["outputFormat"]) : nothing
haskey(settings, "outputDir") ? outputDir = settings["outputDir"] : nothing
end
new(massModel, stepVariable, stepSize, approxLevel, outputDetail, outputFormat, outputDir)
end #function Settings() # constructor
end #struct Settings
""" """
Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them. Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them.
""" """
function checkAndSetInput!(train::Dict, path::Dict, settings::Dict) function checkAndSetInput!(train::Dict, path::Dict, settings::Settings)
checkAndSetTrain!(train) checkAndSetTrain!(train)
checkAndSetPath!(path) checkAndSetPath!(path)
checkAndSetSettings!(settings)
if settings[:detailOfOutput] == "points of interest" && !haskey(path, :pointsOfInterest) if settings.outputDetail == :points_of_interest && !haskey(path, :pointsOfInterest)
settings[:detailOfOutput] = "driving course" throw(DomainError(settings.outputDetail, "INFO at checking the input for settings and path:\n
println("INFO at checking the input for settings and path: settings[:detailOfOutput] is 'points of interest' but the path does not have a list for pointsOfInterest. Therefore the detailOfOut is changed to 'driving course'.") settings[:outputDetail] is 'points of interest' but the path does not for pointsOfInterest."))
end end
return (train, path, settings) return (train, path)
end #function checkAndSetInput! end #function checkAndSetInput!
""" """
@ -102,39 +191,6 @@ function checkAndSetPath!(path::Dict)
return path return path
end # function checkAndSetPath! end # function checkAndSetPath!
## settings for the calculation
function checkAndSetSettings!(settings::Dict)
# check settings information from input dictionary
checkAndSetString!(settings, "settings", :massModel, "mass point", ["mass point", "homogeneous strip"]) # model type of the train's mass "mass point" or "homogeneous strip"
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"
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", :operationModeMinimumRunningTime, true) # operation mode "minimum running time"
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"
checkAndSetString!(settings, "settings", :csvDirectory, "~/Desktop/TrainRun")
# TODO use correct default directory
# TODO: it could be checked if the path is existing on the pc
end # if
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"?
# 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
end # function checkAndSetSettings!
function checkAndSetBool!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::Bool) 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
@ -186,7 +242,7 @@ function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictiona
if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0 if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0
difference = abs(mainKey_temp - alternativeKey_temp) difference = abs(mainKey_temp - alternativeKey_temp)
if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
delete!(dictionary, alternativeKey) 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("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 end
@ -226,7 +282,7 @@ function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictiona
if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0 if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0
difference = abs(mainKey_temp - alternativeKey_temp) difference = abs(mainKey_temp - alternativeKey_temp)
if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
delete!(dictionary, alternativeKey) 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("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 end
@ -261,7 +317,7 @@ function checkAndSetSum!(dictionary::Dict, dictionaryType::String, sum::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^approxLevel)
error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is not exactly the sum of ",String(summand1)," and ",String(summand2),". It differs by ",difference,".") 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
@ -332,7 +388,7 @@ function checkAndSetSpeedLimit!(train::Dict)
if v_limit_temp > 0.0 && v_limit_kmh_temp > 0.0 if v_limit_temp > 0.0 && v_limit_kmh_temp > 0.0
difference = abs(v_limit_temp - v_limit_kmh_temp/3.6) difference = abs(v_limit_temp - v_limit_kmh_temp/3.6)
if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? if difference > 1/(10^approxLevel) # TODO or use difference > 0.0 ?
delete!(train, :v_limit_kmh) 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." ) 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 end
@ -388,7 +444,7 @@ function checkAndSetRotationMassFactors!(train::Dict)
if haskey(train, :ξ_t) && train[:ξ_t]!=nothing && train[:ξ_t]>0.0 && (train[:m_w]==0.0 || (haskey(train, :ξ_w) && train[:ξ_w]!=nothing)) 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? # 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^approxLevel)
error("ERROR at checking the input for the train: The value of ξ_train is not exactly ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train. It differs by ",difference,".") 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
@ -717,18 +773,6 @@ function checkAndSetPOIs!(path::Dict)
return path return path
end #function checkAndSetPOIs! end #function checkAndSetPOIs!
function getDefaultStepSize(stepVariable::String)
if stepVariable == "s in m"
return 10.0
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(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 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 = [] unusedKeys = []
@ -753,5 +797,3 @@ function informAboutUnusedKeys(allKeys::AbstractVector, usedKeys::Vector{Symbol}
end end
end end
end #function informAboutUnusedKeys end #function informAboutUnusedKeys
end # module Validate

View File

@ -0,0 +1,5 @@
%YAML 1.2
---
settings:
outputFormat: "csv" # output as "julia_dict" or as "csv"
outputDir: "." # used if other outputFormat than "julia dict"

View File

@ -0,0 +1,9 @@
%YAML 1.2
---
settings:
# default settings for the calculation
stepSize: 5 # step size, unit depends on stepVariable - distance in meter, time in seconds and velocity in meter/second.
approxLevel: 6 # value for approximation; used when rounding or interating
outputDetail: "running_time" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"
outputFormat: "julia_dict" # output as "julia_dict" or as "csv"
outputDir: "." # used if other outputFormat than "julia dict"

View File

@ -0,0 +1,4 @@
%YAML 1.2
---
settings:
outputDetail: "driving_course" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything"

View File

@ -0,0 +1,4 @@
%YAML 1.2
---
settings:
massModel: "homogeneous_strip" # type of train model used: "mass_point" or "homogeneous_strip"

View File

@ -0,0 +1,4 @@
%YAML 1.2
---
settings:
stepVariable: "time" # variable of the linear multistep method: "distance", "time" or "velocity"

View File

@ -0,0 +1,5 @@
%YAML 1.2
---
settings:
stepVariable: "time" # variable of the linear multistep method: "distance", "time" or "velocity"
massModel: "homogeneous_strip" # type of train model used: "mass_point" or "homogeneous_strip"

View File

@ -0,0 +1,5 @@
%YAML 1.2
---
settings:
stepVariable: "velocity" # variable of the linear multistep method: "distance", "time" or "velocity"
stepSize: 0.1 # step size, unit depends on stepVariable - position in meter, time in seconds and velocity in meter/second

View File

@ -1,40 +1,69 @@
#!/usr/bin/env julia #!/usr/bin/env julia
# -*- coding: UTF-8 -*- # -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.0 # __julia-version__ = 1.7.0
# __author__ = "Max Kannenberg" # __author__ = "Max Kannenberg, Martin Scheidt"
# __copyright__ = "2021" # __copyright__ = "2021"
# __license__ = "ISC" # __license__ = "ISC"
using TrainRun, Test using TrainRun, Test
allPaths=[] paths=Dict()
push!(allPaths, importYamlFile(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) push!(paths, "const" => TrainRun.importFromYaml(:path, "test/data/paths/const.yaml"))
push!(allPaths, importYamlFile(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) push!(paths, "slope" => TrainRun.importFromYaml(:path, "test/data/paths/slope.yaml"))
push!(allPaths, importYamlFile(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) push!(paths, "speed" => TrainRun.importFromYaml(:path, "test/data/paths/speed.yaml"))
push!(allPaths, importYamlFile(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) push!(paths, "realworld" => TrainRun.importFromYaml(:path, "test/data/paths/realworld.yaml"))
settings=Dict()
push!(settings, "default" => Settings())
push!(settings, "detail" => Settings("test/data/settings/detail.yaml"))
push!(settings, "driving_course" => Settings("test/data/settings/driving_course.yaml"))
push!(settings, "strip" => Settings("test/data/settings/strip.yaml"))
push!(settings, "time" => Settings("test/data/settings/time.yaml"))
push!(settings, "time_strip" => Settings("test/data/settings/time_strip.yaml"))
push!(settings, "velocity" => Settings("test/data/settings/velocity.yaml"))
push!(settings, "csv_export" => Settings("test/data/settings/csv_export.yaml"))
allSettings=[] trains=Dict()
push!(allSettings, importYamlFile(:settings, "data/settings.yaml")) push!(trains, TrainRun.importFromYaml(:train, "test/data/trains/freight.yaml"))
push!(trains, TrainRun.importFromYaml(:train, "test/data/trains/local.yaml"))
push!(trains, TrainRun.importFromYaml(:train, "test/data/trains/longdistance.yaml"))
allTrains=[] @testset "TrainRun.jl" begin
push!(allTrains, importYamlFile(:train, "data/trains/train_freight_V90withOreConsist.yaml"))
push!(allTrains, importYamlFile(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml"))
push!(allTrains, importYamlFile(:train, "data/trains/train_passenger_IC2.yaml"))
for path in allPaths @testset "Default settings" begin
for train in allTrains
for settings in allSettings @test typeof(Settings()) == Settings
testDict=trainRun(train, path, settings)
exportToCsv(testDict) @testset "const path" begin
sleep(2)
path = TrainRun.importFromYaml(:path, "test/data/paths/const.yaml")
@test typeof(path) == Dict{Any,Any}
@testset "freight train - const path" begin
train = TrainRun.importFromYaml(:train, "test/data/trains/freight.yaml")
data = trainRun(train, path)
expected = 727.796900196972
# compare result to test data set
@test isapprox(data, expected, atol=0.01)
end
@testset "local train - const path" begin
train = TrainRun.importFromYaml(:train, "test/data/trains/local.yaml")
data = trainRun(train, path)
expected = 392.723361763612
# compare result to test data set
@test isapprox(data, expected, atol=0.01)
end
@testset "long distance train - const path" begin
train = TrainRun.importFromYaml(:train, "test/data/trains/longdistance.yaml")
data = trainRun(train, path)
expected = 328.83487704779117
# compare result to test data set
@test isapprox(data, expected, atol=0.01)
end
# TODO:
# compare result to test data set
end end
end end
end
println("test finished") end
# TODO:
# print test results

View File

@ -1,24 +0,0 @@
#!/usr/bin/env julia
# -*- coding: UTF-8 -*-
# __julia-version__ = 1.7.0
# __author__ = "Martin Scheidt"
# __copyright__ = "2021"
# __license__ = "ISC"
include("../src/types.jl")
include("../src/Validate.jl")
using .Input
using YAML, Test
@enum trainType passenger=1 freight=2 motorCoachTrain=3
@test Input.getEnum("passenger", trainType) == passenger::trainType
@test Input.getEnum("freight", trainType) == freight::trainType
@test Input.getEnum("motorCoachTrain", trainType) == motorCoachTrain::trainType
data = YAML.load(open("data/trains/train_passenger_IC2.yaml"))
@test Input.getEnum(data["train"]["trainType"], trainType) == passenger::trainType
data = YAML.load(open("data/trains/train_freight_V90withOreConsist.yaml"))
@test Input.getEnum(data["train"]["trainType"], trainType) == freight::trainType