From 07b0d9fd8624682506aa825904fa7df5868508fc Mon Sep 17 00:00:00 2001 From: "Snehal M. Shekatkar" Date: Wed, 4 Oct 2023 11:27:11 +0200 Subject: [PATCH 1/3] Implement generic rerouting The rerouting now works for an arbitrary number of trains at arbitrary stations via an arbitrary station. The information of the trains to be rerouted needs to be specified in the file `configure/data/trains-to-reroute.csv`. Each row in this file should contain four columns: "trainid,reroute_start_station,reroute_via_station,reroute_end_station" --- configuration/configure.jl | 20 ++++++++-- configuration/strategies.jl | 79 ++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/configuration/configure.jl b/configuration/configure.jl index 5c6dd6a..db821a8 100644 --- a/configuration/configure.jl +++ b/configuration/configure.jl @@ -78,7 +78,8 @@ BLOCK_EXCEPTION_FILE = "$(config_path)/block-exceptions.csv"; TRAINS_TO_REMOVE_FILE = "$(config_path)/trains-to-remove.csv"; # list of trains to reroute to Pottendorfer line (10601) from Sudbahn (10501) # at Wiener Neustadt up to Wien Meidling -TRAINS_TO_REROUTE_FILE = "$(config_path)/trains-to-reroute-to-Pottendorfer.csv" +#TRAINS_TO_REROUTE_FILE = "$(config_path)/trains-to-reroute-to-Pottendorfer.csv" +TRAINS_TO_REROUTE_FILE = "$(config_path)/trains-to-reroute.csv" # #CLI parser # parsed_args = parse_commandline() @@ -1091,11 +1092,22 @@ function composeTimetable(padfile::String, xmlfile::String, stationfile::String, # Rerouting to Pottendorfer Linie from Sudbahn if reroute - for trainid in readlines(TRAINS_TO_REROUTE_FILE) - @info "Rerouting $(trainid) to Pottendorfer Linie.." - reroute_sudbahn_to_pottendorfer!(dfout, trainid=trainid) + for line in readlines(TRAINS_TO_REROUTE_FILE) + line = split(line, ",") + trainid = String(line[1]) + reroute_start = String(line[2]) + reroute_via = String(line[3]) + reroute_end = String(line[4]) + @info "Rerouting $(trainid) at $(reroute_start) via $(reroute_via) up to $(reroute_end)..." + #reroute_sudbahn_to_pottendorfer!(dfout, trainid=trainid) + construct_rerouted_schedule!(dfout, + reroute_start=reroute_start, + reroute_via=reroute_via, + reroute_end=reroute_end, + trainid=trainid) @info "Rerouting of $(trainid) done!" end + sort!(dfout, :trainid) end passingStation!(dfout,dfsta); diff --git a/configuration/strategies.jl b/configuration/strategies.jl index 36b8456..40f70a2 100644 --- a/configuration/strategies.jl +++ b/configuration/strategies.jl @@ -168,7 +168,7 @@ function reroute_sudbahn_to_pottendorfer!(df_full; trainid="RJ_130") if nrow(df_upto_NB) > 0 df_pottendorfer[!, :distance] .+= df_upto_NB[end, :distance] end - println(first(df_pottendorfer, 5)) + #println(first(df_pottendorfer, 5)) if nrow(df_after_MI) > 0 # Correct the scheduledtime along Sudbahn after exiting MI df_after_MI[!, :scheduledtime] = df_pottendorfer[end, :scheduledtime] .+ df_after_MI[!, :block_reach_time] @@ -193,3 +193,80 @@ function reroute_sudbahn_to_pottendorfer!(df_full; trainid="RJ_130") sort!(df_full, :trainid) #return df_full end + +function extract_reroute_schedule(df::DataFrame; + reroute_start::String, + reroute_via::String, + reroute_end::String, + train_type::String + )::DataFrame + + #println(first(df, 5)) + #println(first(filter(row -> row[:bst] == "PM", df), 5)) + # Add train types + transform!(df, :trainid => ByRow(x -> match(r"([A-Z]+)_[\d]", x)[1]) => :traintype) + + # Keep only the relevant train type and then drop the traintype column + filter!(row -> row[:traintype] == train_type, df) + select!(df, Not([:traintype])) + + # Now keep only those trains which run via the "reroute_via" station + df = combine(groupby(df, [:trainid]), group -> any(group[!, :bst] .== reroute_via) ? group : DataFrame()) + + train_found = false + for group in groupby(df, [:trainid]) + ix_reroute_start = findfirst(==(reroute_start), group.bst) + ix_reroute_end = findfirst(==(reroute_end), group.bst) + if ix_reroute_start < ix_reroute_end + # Now we have found a right train whose schedule can be copied! + @info "We have found a right train! It is $(group[1, :trainid])" + train_found = true + df_reroute = DataFrame(group[ix_reroute_start:ix_reroute_end, :]) + + # Correct the scheduledtime + df_reroute[!, :scheduledtime] .-= df_reroute[1, :scheduledtime] + return df_reroute + end + end + if ~train_found + @warn "There is no train available whose schedule can be copied for rerouting, exiting now ..." + exit() + end +end + +function construct_rerouted_schedule!(df_full::DataFrame; + reroute_start::String, + reroute_via::String, + reroute_end::String, + trainid::String, + ) + + #println(first(df_full, 5)) + #println(first(filter(row -> row[:bst] == "PM", df_full), 5)) + # Extract sub-dataframe corresponding to the given trainid + df = filter(row -> row[:trainid] == trainid, df_full) + train_type = String(match(r"([A-Z]+)_[\d]+", trainid)[1]) + + ix_reroute_start = findfirst(==(reroute_start), df[!, :bst]) + ix_reroute_end = findfirst(==(reroute_end), df[!, :bst]) + + # Create a base schedule for rerouting + df_reroute = extract_reroute_schedule(df_full, + reroute_start=reroute_start, + reroute_via=reroute_via, + reroute_end=reroute_end, + train_type=train_type) + df_reroute[!, :trainid] .= trainid + + # Now construct the full schedule + df_first = DataFrame(df[1:ix_reroute_start-1, :]) + df_reroute[!, :scheduledtime] .+= df[ix_reroute_start, :scheduledtime] + df_last = df[ix_reroute_end+2:end, :] + df_last[!, :scheduledtime] .-= df_last[1, :scheduledtime] + df_last[!, :scheduledtime] .+= df_reroute[end, :scheduledtime] + df = vcat(df_first, df_reroute, df_last) + filter!(row -> row[:trainid] != trainid, df_full) + append!(df_full, df, promote=true) + #sort!(df_full, :trainid) + +end From ca631cd300cfbb2496b279fe8f10e3833a038287 Mon Sep 17 00:00:00 2001 From: "Snehal M. Shekatkar" Date: Wed, 4 Oct 2023 12:21:52 +0200 Subject: [PATCH 2/3] Correct the start and ending times of rerouting --- configuration/strategies.jl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/configuration/strategies.jl b/configuration/strategies.jl index 40f70a2..76bf265 100644 --- a/configuration/strategies.jl +++ b/configuration/strategies.jl @@ -215,16 +215,16 @@ function extract_reroute_schedule(df::DataFrame; train_found = false for group in groupby(df, [:trainid]) - ix_reroute_start = findfirst(==(reroute_start), group.bst) + ix_reroute_start = findlast(==(reroute_start), group.bst) ix_reroute_end = findfirst(==(reroute_end), group.bst) if ix_reroute_start < ix_reroute_end # Now we have found a right train whose schedule can be copied! - @info "We have found a right train! It is $(group[1, :trainid])" + @info "We have found a train whose schedule can be copied! It is $(group[1, :trainid])" train_found = true - df_reroute = DataFrame(group[ix_reroute_start:ix_reroute_end, :]) + df_reroute = DataFrame(group[ix_reroute_start+1:ix_reroute_end, :]) - # Correct the scheduledtime - df_reroute[!, :scheduledtime] .-= df_reroute[1, :scheduledtime] + # Correct the scheduledtime by subtracting the departure time at reroute_start + df_reroute[!, :scheduledtime] .-= group[ix_reroute_start, :scheduledtime] return df_reroute end end @@ -247,7 +247,7 @@ function construct_rerouted_schedule!(df_full::DataFrame; df = filter(row -> row[:trainid] == trainid, df_full) train_type = String(match(r"([A-Z]+)_[\d]+", trainid)[1]) - ix_reroute_start = findfirst(==(reroute_start), df[!, :bst]) + ix_reroute_start = findlast(==(reroute_start), df[!, :bst]) ix_reroute_end = findfirst(==(reroute_end), df[!, :bst]) # Create a base schedule for rerouting @@ -259,12 +259,12 @@ function construct_rerouted_schedule!(df_full::DataFrame; df_reroute[!, :trainid] .= trainid # Now construct the full schedule - df_first = DataFrame(df[1:ix_reroute_start-1, :]) + df_first = DataFrame(df[1:ix_reroute_start, :]) df_reroute[!, :scheduledtime] .+= df[ix_reroute_start, :scheduledtime] - df_last = df[ix_reroute_end+2:end, :] + df_last = df[ix_reroute_end:end, :] df_last[!, :scheduledtime] .-= df_last[1, :scheduledtime] - df_last[!, :scheduledtime] .+= df_reroute[end, :scheduledtime] - df = vcat(df_first, df_reroute, df_last) + df_last[!, :scheduledtime] .+= df_reroute[end, :scheduledtime] + df = vcat(df_first, df_reroute[1:end-1, :], df_last) filter!(row -> row[:trainid] != trainid, df_full) append!(df_full, df, promote=true) #sort!(df_full, :trainid) From 945faa102f935ddd2786cb32d75c932b250dff0c Mon Sep 17 00:00:00 2001 From: "Snehal M. Shekatkar" Date: Mon, 9 Oct 2023 15:17:27 +0200 Subject: [PATCH 3/3] Fix a major but related to rerouting --- configuration/configure.jl | 30 +++++++++++++++++------------- configuration/strategies.jl | 10 ++++++++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/configuration/configure.jl b/configuration/configure.jl index db821a8..b62a1a4 100644 --- a/configuration/configure.jl +++ b/configuration/configure.jl @@ -1092,21 +1092,25 @@ function composeTimetable(padfile::String, xmlfile::String, stationfile::String, # Rerouting to Pottendorfer Linie from Sudbahn if reroute + println(filter(row -> startswith(row[:trainid], "R_"), dfout)) for line in readlines(TRAINS_TO_REROUTE_FILE) - line = split(line, ",") - trainid = String(line[1]) - reroute_start = String(line[2]) - reroute_via = String(line[3]) - reroute_end = String(line[4]) - @info "Rerouting $(trainid) at $(reroute_start) via $(reroute_via) up to $(reroute_end)..." - #reroute_sudbahn_to_pottendorfer!(dfout, trainid=trainid) - construct_rerouted_schedule!(dfout, - reroute_start=reroute_start, - reroute_via=reroute_via, - reroute_end=reroute_end, - trainid=trainid) - @info "Rerouting of $(trainid) done!" + if !startswith(line, '#') + line = split(line, ",") + trainid = String(line[1]) + reroute_start = String(line[2]) + reroute_via = String(line[3]) + reroute_end = String(line[4]) + @info "Rerouting $(trainid) at $(reroute_start) via $(reroute_via) up to $(reroute_end)..." + #reroute_sudbahn_to_pottendorfer!(dfout, trainid=trainid) + construct_rerouted_schedule!(dfout, + reroute_start=reroute_start, + reroute_via=reroute_via, + reroute_end=reroute_end, + trainid=trainid) + @info "Rerouting of $(trainid) done!" + end end + println(filter(row -> startswith(row[:trainid], "R_"), dfout)) sort!(dfout, :trainid) end diff --git a/configuration/strategies.jl b/configuration/strategies.jl index 76bf265..fbf9fc7 100644 --- a/configuration/strategies.jl +++ b/configuration/strategies.jl @@ -207,7 +207,7 @@ function extract_reroute_schedule(df::DataFrame; transform!(df, :trainid => ByRow(x -> match(r"([A-Z]+)_[\d]", x)[1]) => :traintype) # Keep only the relevant train type and then drop the traintype column - filter!(row -> row[:traintype] == train_type, df) + df = filter(row -> row[:traintype] == train_type, df) select!(df, Not([:traintype])) # Now keep only those trains which run via the "reroute_via" station @@ -251,6 +251,7 @@ function construct_rerouted_schedule!(df_full::DataFrame; ix_reroute_end = findfirst(==(reroute_end), df[!, :bst]) # Create a base schedule for rerouting + #println(first(filter(row -> startswith(row[:trainid], "R_"), df_full), 5)) df_reroute = extract_reroute_schedule(df_full, reroute_start=reroute_start, reroute_via=reroute_via, @@ -258,6 +259,7 @@ function construct_rerouted_schedule!(df_full::DataFrame; train_type=train_type) df_reroute[!, :trainid] .= trainid + #println(first(filter(row -> startswith(row[:trainid], "R_"), df_full), 5)) # Now construct the full schedule df_first = DataFrame(df[1:ix_reroute_start, :]) df_reroute[!, :scheduledtime] .+= df[ix_reroute_start, :scheduledtime] @@ -266,7 +268,11 @@ function construct_rerouted_schedule!(df_full::DataFrame; df_last[!, :scheduledtime] .+= df_reroute[end, :scheduledtime] df = vcat(df_first, df_reroute[1:end-1, :], df_last) filter!(row -> row[:trainid] != trainid, df_full) - append!(df_full, df, promote=true) + select!(df_full, Not([:traintype])) + #println(first(df_full, 5)) + #println(first(df, 5)) + append!(df_full, df) + #append!(df_full, df, promote=true) #sort!(df_full, :trainid) end