From 99c873a4e7fa735cb83efdebef82a7095ed17e44 Mon Sep 17 00:00:00 2001 From: Max Kannenberg <95709892+MaxKannenberg@users.noreply.github.com> Date: Thu, 2 Jun 2022 12:32:00 +0200 Subject: [PATCH] Refactor output detail and format and adapt examples --- docs/examples/ExtendedWorkingExample.jl | 23 ++---- docs/examples/MinimalWorkingExample.jl | 3 +- src/TrainRuns.jl | 10 +-- src/constructors.jl | 10 +-- src/output.jl | 95 +++++++--------------- src/types.jl | 6 +- test/data/settings/driving_course.yaml | 2 +- test/data/settings/everything.yaml | 4 - test/data/settings/points_of_interest.yaml | 2 +- test/runtests.jl | 30 +++---- 10 files changed, 68 insertions(+), 117 deletions(-) delete mode 100644 test/data/settings/everything.yaml diff --git a/docs/examples/ExtendedWorkingExample.jl b/docs/examples/ExtendedWorkingExample.jl index ded58ba..97be3cb 100644 --- a/docs/examples/ExtendedWorkingExample.jl +++ b/docs/examples/ExtendedWorkingExample.jl @@ -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 diff --git a/docs/examples/MinimalWorkingExample.jl b/docs/examples/MinimalWorkingExample.jl index 129bb2b..ba4577d 100644 --- a/docs/examples/MinimalWorkingExample.jl +++ b/docs/examples/MinimalWorkingExample.jl @@ -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.") diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl index d6de6ad..aeaa827 100644 --- a/src/TrainRuns.jl +++ b/src/TrainRuns.jl @@ -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 diff --git a/src/constructors.jl b/src/constructors.jl index 3500130..9e459dd 100644 --- a/src/constructors.jl +++ b/src/constructors.jl @@ -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 diff --git a/src/output.jl b/src/output.jl index 2282584..b838ac7 100644 --- a/src/output.jl +++ b/src/output.jl @@ -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 diff --git a/src/types.jl b/src/types.jl index fd1c840..5ffee12 100644 --- a/src/types.jl +++ b/src/types.jl @@ -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 diff --git a/test/data/settings/driving_course.yaml b/test/data/settings/driving_course.yaml index 46ac088..3b5bae5 100644 --- a/test/data/settings/driving_course.yaml +++ b/test/data/settings/driving_course.yaml @@ -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" diff --git a/test/data/settings/everything.yaml b/test/data/settings/everything.yaml deleted file mode 100644 index 0e2cdf1..0000000 --- a/test/data/settings/everything.yaml +++ /dev/null @@ -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" diff --git a/test/data/settings/points_of_interest.yaml b/test/data/settings/points_of_interest.yaml index d0784ff..d5e9bed 100644 --- a/test/data/settings/points_of_interest.yaml +++ b/test/data/settings/points_of_interest.yaml @@ -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" diff --git a/test/runtests.jl b/test/runtests.jl index 4baa289..3019c23 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -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)