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
using TrainRuns
using CSV
paths=[]
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/realworld.yaml"))
settings=[]
push!(settings, Settings("test/data/settings/driving_course.yaml"))
trains=[]
push!(trains, Train("test/data/trains/freight.yaml"))
push!(trains, Train("test/data/trains/local.yaml"))
push!(trains, Train("test/data/trains/longdistance.yaml"))
driving_courses=[]
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)
settings = Settings("test/data/settings/driving_course.yaml")
# old: if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV"
# old: exportToCsv(resultsDict, settings)
# old: sleep(2)
# old: end
end
for p in 1:length(paths)
for t in 1:length(trains)
driving_course = trainrun(trains[t], paths[p], settings)
CSV.write("docs/examples/drivingCourse_path"*string(p)*"_train"*string(t)*".csv", driving_course, header=false)
end
end

View File

@ -5,6 +5,7 @@ using TrainRuns
train = Train("test/data/trains/freight.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.")

View File

@ -13,13 +13,13 @@ using UUIDs, Dates, Statistics
## loading external packages
using YAML, JSONSchema, DataFrames
export
export
## Interface
trainrun, Train, Path, Settings
## global variables
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)
## include package files
@ -49,14 +49,14 @@ xxx.xx # in seconds
function trainrun(train::Train, path::Path, settings=Settings()::Settings)
# prepare the input data
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"
(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
output = createOutput(train, settings, path, movingSection, drivingCourse)
output = createOutput(settings, path, drivingCourse)
return output
end # function trainrun

View File

@ -52,12 +52,12 @@ function Settings(file="DEFAULT")
"outputDetail": {
"description": "Selecting the detail of the result",
"type": "string",
"enum": [ "running_time", "points_of_interest", "driving_course", "everything" ]
"enum": [ "running_time", "points_of_interest", "driving_course" ]
},
"outputFormat": {
"description": "Output format",
"type": "string",
"enum": [ "dataframe", "dict" ]
"enum": [ "dataframe", "vector" ]
}
}
}""")
@ -256,7 +256,7 @@ function Path(file, type = :YAML)
sort!(tmp_points, by = x -> x[1])
for elem in tmp_points
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 ‰)
point = Dict(:station => station,
@ -302,7 +302,7 @@ function Train(file, type = :YAML)
ξ_cars = 1.06 # rotation mass factor
transportType = :freight # "freight" or "passenger" for resistance calculation
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_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 ‰)
@ -712,7 +712,7 @@ function createDataPoint()
:R_train => 0.0, # train resistance (in N)
:R_traction => 0.0, # traction unit 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
end #function createDataPoint

View File

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

View File

@ -11,9 +11,9 @@ struct Settings
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 iterating.
outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest",
# complete Array() ":driving_course", or Dict() ":everything".
outputFormat::Symbol # output as ":dataframe" or as ":dict".
outputDetail::Symbol # single Float() ":running_time", Vector() of ":points_of_interest",
# or complete Vector() ":driving_course"
outputFormat::Symbol # output as ":dataframe" or as ":vector".
end #struct Settings

View File

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