Merge pull request #23 from railtoolkit/development_max

cleanup of development max
master
Martin Scheidt 2022-08-29 14:27:13 +02:00 committed by GitHub
commit 31befe815d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 373 additions and 523 deletions

View File

@ -9,6 +9,22 @@ Categories: Added, Changed, Deprecated, Removed, Fixed, and Security.
## [Unreleased]
### Added
* output alternative with starting points of the driving modes
### Changed
* renamed data points into 'support points'
* reduced number of decimal places of output data
* replace v_peak by the existing v_limit
* changed type of a point of interest from Tuple to NamedTuple
### Removed
* dictionary MovingSection
* redundant keys from the dictionary CharacteristicSection
* dictionary BehaviorSection
* redundant keys from the dictionary SupportPoint
* function secureAcceleratingBehavior()
## Version [1.0.1] 2022-06-05
@ -208,4 +224,4 @@ Proof of concept and master thesis submission.
[0.4]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.3...v0.4
[0.3]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.2...v0.3
[0.2]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.1...v0.2
[0.1]: https://github.com/railtoolkit/TrainRuns.jl/releases/tag/v0.1
[0.1]: https://github.com/railtoolkit/TrainRuns.jl/releases/tag/v0.1

View File

@ -50,7 +50,7 @@ function trainrun(train::Train, path::Path, settings=Settings()::Settings)
# TODO settings.outputDetail == :verbose && println("The characteristics haven been determined.")
# calculate the train run with the minimum running time
(characteristicSections, drivingCourse) = calculateMinimumRunningTime!(characteristicSections, settings, train)
drivingCourse = calculateMinimumRunningTime(characteristicSections, settings, train)
# TODO settings.outputDetail == :verbose && println("The driving course for the shortest running time has been calculated.")
# accumulate data and create an output dictionary

File diff suppressed because it is too large Load Diff

View File

@ -7,109 +7,99 @@
# Calculate the running time 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 a train run focussing on using the minimum possible running time
function calculateMinimumRunningTime!(CSs::Vector{Dict}, settings::Settings, train::Train)
if settings.massModel == :homogeneous_strip && settings.stepVariable == speed
println("WARNING: ! ! ! TrainRuns.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 # TODO
function calculateMinimumRunningTime(CSs::Vector{Dict}, settings::Settings, train::Train)
startingPoint = SupportPoint()
startingPoint[:i] = 1
startingPoint[:s] = CSs[1][:s_entry]
calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N)
drivingCourse::Vector{Dict} = [startingPoint] # List of support points
for csId in 1:length(CSs)
CS = CSs[csId]
# for testing: # TODO
if drivingCourse[end][:s] != CS[:s_entry]
println("ERROR: In CS", csId," the train run starts at s=",drivingCourse[end][:s]," and not s_entry=",CS[:s_entry])
end
if drivingCourse[end][:v] > CS[:v_entry]
println("ERROR: In CS", csId," the train run ends with v=",drivingCourse[end][:v]," and not with v_entry=",CS[:v_entry])
end
# determine the different flags for switching between the states for creating moving phases
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N)
calculateForces!(drivingCourse[end], CSs, csId, "default", train, settings.massModel) # tractive effort and resisting forces (in N)
previousSpeedLimitReached = false
stateFlags = Dict(:endOfCSReached => drivingCourse[end][:s] > CS[:s_exit],
:brakingStartReached => drivingCourse[end][:s] + s_braking == CS[:s_exit],
:tractionDeficit => drivingCourse[end][:F_T] < drivingCourse[end][:F_R], # or add another flag for equal forces?
:resistingForceNegative => drivingCourse[end][:F_R] < 0.0,
:previousSpeedLimitReached => false, #speedLimitReached, # check already at this position?
:previousSpeedLimitReached => false,
:speedLimitReached => drivingCourse[end][:v] > CS[:v_limit],
:error => false)
# determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "halt")
while !stateFlags[:endOfCSReached] # s < s_exit
if !stateFlags[:brakingStartReached] # s+s_braking < s_exit
if !stateFlags[:tractionDeficit]
if drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && drivingCourse[end][:v] == 0.0
(CS, drivingCourse, stateFlags) = addBreakFreeSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
elseif stateFlags[:previousSpeedLimitReached]
(CS, drivingCourse, stateFlags) = addClearingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
(CS, drivingCourse, stateFlags) = addAcceleratingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
# cruise only one step
if settings.stepVariable == :distance
s_cruising = settings.stepSize
elseif settings.stepVariable == time
s_cruising = Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v])
elseif settings.stepVariable == velocity
s_cruising = train.length/(10.0) # TODO which step size should be used?
end
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached]
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 0.0
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking")
else
stateFlags[:brakingStartReached] = true
end
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached]
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 1/10^(settings.approxLevel) # TODO: define another minimum cruising length?
(CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising")
else
stateFlags[:brakingStartReached] = true
end
else
error()
end
elseif stateFlags[:tractionDeficit]
(CS, drivingCourse, stateFlags) = addDiminishingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
else
error()
# determine the behavior sections for this characteristic section. It has to be at least one of those BS: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "halt")
while !stateFlags[:endOfCSReached] # s < s_exit
if stateFlags[:error]
error("ERROR in calc in CS",csId,": BS=",drivingCourse[end][:behavior]," s=",drivingCourse[end][:s]," s_braking=",s_braking," v_limit=",CS[:v_limit]," v=",drivingCourse[end][:v]," v_exit=",CS[:v_exit]," with the flags: endOfCS: ",stateFlags[:endOfCSReached]," brakingStart: ",stateFlags[:brakingStartReached]," F_T<F_R: ",stateFlags[:tractionDeficit]," F_R<0: ",stateFlags[:resistingForceNegative]," v_previousLimit: ",stateFlags[:previousSpeedLimitReached]," v_limit: ",stateFlags[:speedLimitReached]," error: ",stateFlags[:error])
end
else#if !stateFlags[:endOfCSReached] # s < s_exit
(CS, drivingCourse, stateFlags) = addBrakingSection!(CS, drivingCourse, stateFlags, settings, train, CSs)
#else
# error()
end
if CS[:s_exit] - drivingCourse[end][:s] < 1/10^(settings.approxLevel)
drivingCourse[end][:s] = CS[:s_exit] # round s up to CS[:s_exit]
if !stateFlags[:brakingStartReached] # s+s_braking < s_exit
if !stateFlags[:tractionDeficit]
if drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && drivingCourse[end][:v] == 0.0
(drivingCourse, stateFlags) = addBreakFreeSection!(drivingCourse, stateFlags, CSs, csId, settings, train)
# set state flag
stateFlags[:endOfCSReached] = true
elseif stateFlags[:previousSpeedLimitReached]
(drivingCourse, stateFlags) = addClearingSection!(drivingCourse, stateFlags, CSs, csId, settings, train)
elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
(drivingCourse, stateFlags) = addAcceleratingSection!(drivingCourse, stateFlags, CSs, csId, settings, train)
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached]
# cruise only one step
if settings.stepVariable == :distance
s_cruising = settings.stepSize
elseif settings.stepVariable == time
s_cruising = Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v])
elseif settings.stepVariable == velocity
s_cruising = train.length/(10.0) # TODO which step size should be used?
end
(drivingCourse, stateFlags) = addCruisingSection!(drivingCourse, stateFlags, CSs, csId, settings, train, "cruising", s_cruising)
elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached]
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 0.0
(drivingCourse, stateFlags) = addCruisingSection!(drivingCourse, stateFlags, CSs, csId, settings, train, "downhillBraking", s_cruising)
else
stateFlags[:brakingStartReached] = true
end
elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached]
s_braking = brakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking, settings.approxLevel)
s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking
if s_cruising > 1/10^(settings.approxLevel) # TODO: define another minimum cruising length?
(drivingCourse, stateFlags) = addCruisingSection!(drivingCourse, stateFlags, CSs, csId, settings, train, "cruising", s_cruising)
else
stateFlags[:brakingStartReached] = true
end
else
error()
end
elseif stateFlags[:tractionDeficit]
(drivingCourse, stateFlags) = addDiminishingSection!(drivingCourse, stateFlags, CSs, csId, settings, train)
else
error()
end
else#if !stateFlags[:endOfCSReached] # s < s_exit
(drivingCourse, stateFlags) = addBrakingSection!(drivingCourse, stateFlags, CSs, csId, settings, train)
#else
# error()
end
if CS[:s_exit] - drivingCourse[end][:s] < 1/10^(settings.approxLevel)
drivingCourse[end][:s] = CS[:s_exit] # round s up to CS[:s_exit]
# set state flag
stateFlags[:endOfCSReached] = true
end
end
end
#if s == s_exit
# halt
#end
#if s == s_exit
# halt
#end
# for testing: # TODO
@ -121,9 +111,9 @@ function calculateMinimumRunningTime!(CSs::Vector{Dict}, settings::Settings, tra
end
end #for
(CSs[end], drivingCourse) = addHalt!(CSs[end], drivingCourse, settings, train, CSs)
drivingCourse = addHalt!(drivingCourse, CSs, length(CSs), settings, train)
return (CSs, drivingCourse)
return drivingCourse
end #function calculateMinimumRunningTime
@ -232,7 +222,6 @@ function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, cs
# create the next support point
newPoint = SupportPoint()
newPoint[:i] = previousPoint[:i]+1 # identifier
# calculate s, t, v, E
if stepVariable == :distance # distance step method
@ -287,7 +276,7 @@ end #function moveAStep
"""
# 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
"""
function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real)
function getLowestSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::Real, trainLength::Real)
v_limit = CSs[csWithTrainHeadId][:v_limit]
s_exit = CSs[csWithTrainHeadId][:s_exit]
if csWithTrainHeadId > 1 && s -trainLength < CSs[csWithTrainHeadId][:s_entry]
@ -300,17 +289,17 @@ function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s::
formerCsId = formerCsId -1
end
end
currentSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength)
return currentSpeedLimit
end #function getCurrentSpeedLimit
lowestSpeedLimit = Dict(:v => v_limit, :s_end => s_exit + trainLength)
return lowestSpeedLimit
end #function getLowestSpeedLimit
"""
TODO
"""
function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real)
function getNextPointOfInterest(pointsOfInterest::Vector{NamedTuple}, s::Real)
for POI in pointsOfInterest
if POI[1] > s
if POI[:s] > s
return POI
end
end
@ -321,22 +310,20 @@ end #function getNextPointOfInterest
## create vectors with the moving section's points of interest and with the characteristic sections with secured braking and accelerating behavior
function determineCharacteristics(path::Path, train::Train, settings::Settings)
# determine the positions of the points of interest depending on the interesting part of the train (front/rear) and the train's length
##TODO: use a tuple with naming
pointsOfInterest = Tuple[]
pointsOfInterest = NamedTuple[]
if !isempty(path.poi)
for POI in path.poi
s_poi = POI[:station]
if POI[:measure] == "rear"
s_poi += train.length
end
push!(pointsOfInterest, (s_poi, POI[:label]) )
push!(pointsOfInterest, (s = s_poi, label = POI[:label]) )
end
sort!(pointsOfInterest, by = x -> x[1])
sort!(pointsOfInterest, by = x -> x[:s])
end
characteristicSections = CharacteristicSections(path, train.v_limit, train.length, pointsOfInterest)
characteristicSections = secureBrakingBehavior!(characteristicSections, train.a_braking, settings.approxLevel)
characteristicSections = secureAcceleratingBehavior!(characteristicSections, settings, train)
return (characteristicSections, pointsOfInterest)
end #function determineCharacteristics

View File

@ -614,59 +614,52 @@ function Train(file, type = :YAML)
end #function Train() # outer constructor
## create the moving section's characteristic sections
function CharacteristicSections(path::Path, v_trainLimit::Real, s_trainLength::Real, MS_poi::Vector{Tuple})
function CharacteristicSections(path::Path, v_trainLimit::Real, s_trainLength::Real, MS_poi::Vector{NamedTuple})
# create and return the characteristic sections of a moving section dependent on the paths attributes
CSs=Vector{Dict}()
CSs = Vector{Dict}()
s_csStart = path.sections[1][:s_start] # first position (in m)
csId = 1
#csId = 1
for row in 2:length(path.sections)
previousSection = path.sections[row-1]
currentSection = path.sections[row]
speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit)
pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp]
if speedLimitIsDifferent || pathResistanceIsDifferent
push!(CSs, CharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, MS_poi))
push!(CSs, CharacteristicSection(s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, MS_poi))
s_csStart = currentSection[:s_start]
csId = csId+1
#csId = csId+1
end #if
end #for
push!(CSs, CharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, MS_poi))
push!(CSs, CharacteristicSection(s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, MS_poi))
return CSs
end #function CharacteristicSections
## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections.
function CharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, MS_poi::Vector{Tuple})
## create a characteristic section for a path section.
function CharacteristicSection(s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, MS_poi::Vector{NamedTuple})
# Create and return a characteristic section dependent on the paths attributes
characteristicSection::Dict{Symbol, Any} = Dict(:id => id, # identifier
:s_entry => s_entry, # first position (in m)
characteristicSection::Dict{Symbol, Any} = Dict(:s_entry => s_entry, # first position (in m)
:s_exit => section[:s_end], # last position (in m)
:length => section[:s_end] -s_entry, # total length (in m)
:r_path => section[:f_Rp], # path resistance (in ‰)
:v_limit => v_limit, # speed limit (in m/s)
# initializing :v_entry, :v_peak and :v_exit with :v_limit
:v_peak => v_limit, # maximum reachable speed (in m/s)
:v_entry => v_limit, # maximum entry speed (in m/s)
:v_exit => v_limit) # maximum exit speed (in m/s)
:v_exit => v_limit) # maximum exit speed (in m/s) initialized with v_limit
# list of positions of every point of interest (POI) in this charateristic section for which support points should be calculated
# get the list of positions of every point of interest (POI) in this charateristic section for which support points should be calculated from the list of the whole moving section's POI
s_exit = characteristicSection[:s_exit]
##TODO: use a tuple with naming
pointsOfInterest = Tuple[]
CS_poi = NamedTuple[]
if !isempty(MS_poi)
for POI in MS_poi
s_poi = POI[1]
s_poi = POI[:s]
if s_entry < s_poi && s_poi <= s_exit
push!(pointsOfInterest, (POI))
push!(CS_poi, POI)
end
end
end
if isempty(pointsOfInterest) || pointsOfInterest[end][1] < s_exit
push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
if isempty(CS_poi) || CS_poi[end][:s] < s_exit
push!(CS_poi, (s = s_exit, label = "")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with
end
merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest))
merge!(characteristicSection, Dict(:pointsOfInterest => CS_poi))
return characteristicSection
end #function CharacteristicSection
@ -676,9 +669,8 @@ a SupportPoint is the smallest element of the driving course. One step of the st
"""
function SupportPoint()
supportPoint = Dict(
:i => 0, # identifier and counter variable of the driving course
:behavior => "", # type of behavior section the support point is part of - see BehaviorSection()
# a support point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter
# a support point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter
:s => 0.0, # position (in m)
:t => 0.0, # point in time (in s)
:v => 0.0, # velocity (in m/s)

View File

@ -4,7 +4,7 @@
# __copyright__ = "2020-2022"
# __license__ = "ISC"
function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfInterest::Vector{Tuple})
function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfInterest::Vector{NamedTuple})
if settings.outputDetail == :running_time
output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])]
@ -19,7 +19,7 @@ function createOutput(settings::Settings, drivingCourse::Vector{Dict}, pointsOfI
supportPoint = 1
for POI in 1:length(pointsOfInterest)
while supportPoint <= length(drivingCourse)
if pointsOfInterest[POI][1] == drivingCourse[supportPoint][:s]
if pointsOfInterest[POI][:s] == drivingCourse[supportPoint][:s]
push!(output, drivingCourse[supportPoint])
break
end