Refactor output detail and format and adapt examples

development
Max Kannenberg 2022-06-02 12:32:00 +02:00
parent 8a97de3fdf
commit 99c873a4e7
10 changed files with 68 additions and 117 deletions

View File

@ -1,6 +1,7 @@
#!/usr/bin/env julia #!/usr/bin/env julia
using TrainRuns using TrainRuns
using CSV
paths=[] paths=[]
push!(paths, Path("test/data/paths/const.yaml")) push!(paths, Path("test/data/paths/const.yaml"))
@ -8,28 +9,16 @@ push!(paths, Path("test/data/paths/slope.yaml"))
push!(paths, Path("test/data/paths/speed.yaml")) push!(paths, Path("test/data/paths/speed.yaml"))
push!(paths, Path("test/data/paths/realworld.yaml")) push!(paths, Path("test/data/paths/realworld.yaml"))
settings=[]
push!(settings, Settings("test/data/settings/driving_course.yaml"))
trains=[] trains=[]
push!(trains, Train("test/data/trains/freight.yaml")) push!(trains, Train("test/data/trains/freight.yaml"))
push!(trains, Train("test/data/trains/local.yaml")) push!(trains, Train("test/data/trains/local.yaml"))
push!(trains, Train("test/data/trains/longdistance.yaml")) push!(trains, Train("test/data/trains/longdistance.yaml"))
driving_courses=[] settings = Settings("test/data/settings/driving_course.yaml")
for path in paths
# println(" - - - - - - - - -")
# println("path: ", path[:name])
for train in trains
# println("train: ", train[:name])
for settings in settings
push!(driving_courses, trainrun(train, path, settings))
#driving_course = trainrun(train, path, settings)
# old: if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV" for p in 1:length(paths)
# old: exportToCsv(resultsDict, settings) for t in 1:length(trains)
# old: sleep(2) driving_course = trainrun(trains[t], paths[p], settings)
# old: end CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course, header=false)
end
end end
end end

View File

@ -5,6 +5,7 @@ using TrainRuns
train = Train("test/data/trains/freight.yaml") train = Train("test/data/trains/freight.yaml")
path = Path("test/data/paths/const.yaml") path = Path("test/data/paths/const.yaml")
runtime = trainrun(train, path) runtime_dataFrame = trainrun(train, path)
runtime = runtime_dataFrame[!, 1][2]
println("The train needs $runtime seconds for the running path.") println("The train needs $runtime seconds for the running path.")

View File

@ -13,13 +13,13 @@ using UUIDs, Dates, Statistics
## loading external packages ## loading external packages
using YAML, JSONSchema, DataFrames using YAML, JSONSchema, DataFrames
export export
## Interface ## Interface
trainrun, Train, Path, Settings trainrun, Train, Path, Settings
## global variables ## global variables
global g = 9.80665 # acceleration due to gravity (in m/s^2) global g = 9.80665 # acceleration due to gravity (in m/s^2)
global μ = 0.2 # friction as constant, todo: implement as function global μ = 0.2 # friction as constant, TODO: implement as function
global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s) global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s)
## include package files ## include package files
@ -49,14 +49,14 @@ xxx.xx # in seconds
function trainrun(train::Train, path::Path, settings=Settings()::Settings) function trainrun(train::Train, path::Path, settings=Settings()::Settings)
# prepare the input data # prepare the input data
movingSection = determineCharacteristics(path, train, settings) movingSection = determineCharacteristics(path, train, settings)
settings.outputDetail == :everything && println("The moving section has been prepared.") # settings.outputDetail == :verbose && 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"
(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.outputDetail == :verbose && 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(settings, path, drivingCourse)
return output return output
end # function trainrun end # function trainrun

View File

@ -52,12 +52,12 @@ function Settings(file="DEFAULT")
"outputDetail": { "outputDetail": {
"description": "Selecting the detail of the result", "description": "Selecting the detail of the result",
"type": "string", "type": "string",
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ] "enum": [ "running_time", "points_of_interest", "driving_course" ]
}, },
"outputFormat": { "outputFormat": {
"description": "Output format", "description": "Output format",
"type": "string", "type": "string",
"enum": [ "dataframe", "dict" ] "enum": [ "dataframe", "vector" ]
} }
} }
}""") }""")
@ -256,7 +256,7 @@ function Path(file, type = :YAML)
sort!(tmp_points, by = x -> x[1]) sort!(tmp_points, by = x -> x[1])
for elem in tmp_points for elem in tmp_points
station = elem[1] # first point of the section (in m) station = elem[1] # first point of the section (in m)
label = elem[2] # paths speed limt (in m/s) label = elem[2] # paths speed limt (in m/s)
measure = elem[3] # specific path resistance of the section (in ‰) measure = elem[3] # specific path resistance of the section (in ‰)
point = Dict(:station => station, point = Dict(:station => station,
@ -302,7 +302,7 @@ function Train(file, type = :YAML)
ξ_cars = 1.06 # rotation mass factor ξ_cars = 1.06 # rotation mass factor
transportType = :freight # "freight" or "passenger" for resistance calculation transportType = :freight # "freight" or "passenger" for resistance calculation
v_limit = 140 # in m/s (default 504 km/h) v_limit = 140 # in m/s (default 504 km/h)
a_braking = 0 # in m/s^2, todo: implement as function a_braking = 0 # in m/s^2, TODO: implement as function
f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰) f_Rtd0 = 0 # coefficient for basic resistance due to the traction unit's driving axles (in ‰)
f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰) f_Rtc0 = 0 # coefficient for basic resistance due to the traction unit's carring axles (in ‰)
f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰) f_Rt2 = 0 # coefficient for air resistance of the traction unit (in ‰)
@ -712,7 +712,7 @@ function createDataPoint()
:R_train => 0.0, # train resistance (in N) :R_train => 0.0, # train resistance (in N)
:R_traction => 0.0, # traction unit resistance (in N) :R_traction => 0.0, # traction unit resistance (in N)
:R_wagons => 0.0, # set of wagons resistance (in N) :R_wagons => 0.0, # set of wagons resistance (in N)
:label => "" # a label for importend points :label => "" # a label for important points
) )
return dataPoint return dataPoint
end #function createDataPoint end #function createDataPoint

View File

@ -5,15 +5,12 @@
# __copyright__ = "2020-2022" # __copyright__ = "2020-2022"
# __license__ = "ISC" # __license__ = "ISC"
using DataFrames function createOutput(settings::Settings, path::Path, drivingCourse::Vector{Dict})
function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict})
if settings.outputDetail == :running_time if settings.outputDetail == :running_time
output = drivingCourse[end][:t] output::Vector{Dict} = [Dict(:t => drivingCourse[end][:t])]
elseif settings.outputDetail == :points_of_interest elseif settings.outputDetail == :points_of_interest && !isempty(path.poi)
# add points of interest # add points of interest
if !isempty(path.poi)
# output = Dict[] # output = Dict[]
# POI = 1 # POI = 1
@ -26,79 +23,47 @@ function createOutput(train::Train, settings::Settings, path::Path, movingSectio
# i = i+1 # i = i+1
# end # end
# get only the driving course's data points with POI labels # get only the driving course's data points with POI labels
output = Dict[] output = Dict[]
for point in 1:length(drivingCourse) for point in drivingCourse
if point[:label] != "" if point[:label] != ""
push!(output, point) push!(output, point)
end
end end
end end
elseif settings.outputDetail == :driving_course else #if settings.outputDetail == :driving_course || (settings.outputDetail == :points_of_interest && !isempty(path.poi))
output = drivingCourse output = drivingCourse
elseif settings.outputDetail == :everything
output = Dict{Symbol,Any}()
merge!(output, Dict(:train => train, :path => path, :settings => settings))
# add moving section and driving courses
merge!(output, Dict(:movingSection => movingSection,
:drivingCourse => drivingCourse))
# add points of interest
if !isempty(path.poi)
pointsOfInterest = Dict[]
# get only the driving course's data points with POI labels
output = Dict[]
for point in 1:length(drivingCourse)
if point[:label] != ""
push!(pointsOfInterest, point)
end
end
merge!(output, Dict(:pointsOfInterest => pointsOfInterest))
end
if settings.outputFormat == :dataframe
return createDataFrameForDataPoints(output[:drivingCourse])
else
return output
end
end end
if settings.outputFormat == :dataframe if settings.outputFormat == :dataframe
return createDataFrame(output) return createDataFrame(output, settings.outputDetail)
else elseif settings.outputFormat == :vector
return output return output
end end
end end
function createDataFrame(runningTime::AbstractFloat) function createDataFrame(output_vector::Vector{Dict}, outputDetail)
# create DataFrame with running time information if outputDetail == :running_time
dataFrame = DataFrame(column1=["t (in s)", runningTime]) # create DataFrame with running time information
end dataFrame = DataFrame(column1=["t (in s)", output_vector[end][:t]])
else # :points_of_interest or :driving_course
header = ["label", "driving mode", "s (in m)", "v (in m/s)", "t (in s)", "a (in m/s^2)", "F_T (in N)", "F_R (in N)", "R_path (in N)", "R_traction (in N)", "R_wagons (in N)"]
columnSymbols = [:label, :behavior, :s, :v, :t, :a, :F_T, :F_R, :R_path, :R_traction, :R_wagons]
function createDataFrame(dataPoints::Vector{Dict}) allColumns = Array{Any,1}[]
header = ["i", "behavior", "station label", "Δ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)","a (in m/s^2)"] for column in 1:length(header)
columnSymbols = [:i, :behavior, :label, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :a] currentColumn = Any[]
push!(currentColumn, header[column])
for point in output_vector
push!(currentColumn, point[columnSymbols[column]])
end
push!(allColumns, currentColumn)
end # for
allColumns = Array{Any,1}[] # combine the columns in a data frame
for column in 1:length(header) dataFrame = 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])
currentColumn = Any[] end
push!(currentColumn, header[column])
for point in dataPoints
push!(currentColumn, point[columnSymbols[column]])
end
push!(allColumns, currentColumn)
end # for
# combine the columns in a data frame
dataFrame = 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])
return dataFrame return dataFrame
end #createDataFrameForDrivingCourse end #createDataFrameForDrivingCourse

View File

@ -11,9 +11,9 @@ struct Settings
stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity". 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. 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 iterating. approxLevel::Int # value for approximation; used when rounding or iterating.
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest", outputDetail::Symbol # single Float() ":running_time", Vector() of ":points_of_interest",
# complete Array() ":driving_course", or Dict() ":everything". # or complete Vector() ":driving_course"
outputFormat::Symbol # output as ":dataframe" or as ":dict". outputFormat::Symbol # output as ":dataframe" or as ":vector".
end #struct Settings end #struct Settings

View File

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

View File

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

View File

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

View File

@ -14,25 +14,24 @@ settings = Dict()
@testset "load data" begin @testset "load data" begin
println("testing load train data") println("testing load train data")
push!(trains, :freight => @time Train("data/trains/freight.yaml")) push!(trains, :freight => @time Train("test/data/trains/freight.yaml"))
push!(trains, :local => @time Train("data/trains/local.yaml")) push!(trains, :local => @time Train("test/data/trains/local.yaml"))
push!(trains, :longdistance => @time Train("data/trains/longdistance.yaml")) push!(trains, :longdistance => @time Train("test/data/trains/longdistance.yaml"))
println("testing load path data") println("testing load path data")
push!(paths, :const => @time Path("data/paths/const.yaml")) push!(paths, :const => @time Path("test/data/paths/const.yaml"))
push!(paths, :slope => @time Path("data/paths/slope.yaml")) push!(paths, :slope => @time Path("test/data/paths/slope.yaml"))
push!(paths, :speed => @time Path("data/paths/speed.yaml")) push!(paths, :speed => @time Path("test/data/paths/speed.yaml"))
push!(paths, :realworld => @time Path("data/paths/realworld.yaml")) push!(paths, :realworld => @time Path("test/data/paths/realworld.yaml"))
println("testing load settings data") println("testing load settings data")
push!(settings, "default" => @time Settings()) push!(settings, "default" => @time Settings())
push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml")) push!(settings, "poi" => @time Settings("test/data/settings/points_of_interest.yaml"))
push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml")) push!(settings, "drivingcourse" => @time Settings("test/data/settings/driving_course.yaml"))
push!(settings, "everything" => @time Settings("data/settings/everything.yaml")) push!(settings, "strip" => @time Settings("test/data/settings/strip.yaml"))
push!(settings, "strip" => @time Settings("data/settings/strip.yaml")) push!(settings, "time" => @time Settings("test/data/settings/time.yaml"))
push!(settings, "time" => @time Settings("data/settings/time.yaml")) push!(settings, "timestrip" => @time Settings("test/data/settings/time_strip.yaml"))
push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml")) push!(settings, "velocity" => @time Settings("test/data/settings/velocity.yaml"))
push!(settings, "velocity" => @time Settings("data/settings/velocity.yaml"))
@test typeof(first(paths)[2]) == Path @test typeof(first(paths)[2]) == Path
@test typeof(first(settings)[2]) == Settings @test typeof(first(settings)[2]) == Settings
@ -75,7 +74,8 @@ anticipated = Dict(
for test in tests for test in tests
test_name = String(test[1][1]) * "_" * String(test[2][1]) test_name = String(test[1][1]) * "_" * String(test[2][1])
println("testing $test_name") println("testing $test_name")
@time result = trainrun(test[1][2],test[2][2]) @time result_dataFrame = trainrun(test[1][2], test[2][2])
result = result_dataFrame[!, 1][2]
expected = anticipated[:default][Symbol(test_name)] expected = anticipated[:default][Symbol(test_name)]
# compare result to test data set # compare result to test data set
@test isapprox(result, expected, rtol=0.01) @test isapprox(result, expected, rtol=0.01)