diff --git a/CITATION.cff b/CITATION.cff
index d2263b7c..d2788e95 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -34,8 +34,8 @@ authors:
affiliation: Technische Universität Berlin
orcid: 'https://orcid.org/0000-0003-2775-6898'
url: "https://github.com/matsim-scenarios/matsim-kelheim"
-doi: 10.5281/zenodo.8322240
-date-released: 2023-09-06
-year: 2023
-version: 3.1
+doi: 10.5281/zenodo.8322239
+date-released: 2024-06-25
+year: 2024
+version: 3.1.1
license: AGPL-3.0
diff --git a/README.md b/README.md
index 734b2496..20723278 100644
--- a/README.md
+++ b/README.md
@@ -3,20 +3,18 @@
[![Build Status](https://github.com/matsim-scenarios/matsim-kelheim/actions/workflows/build.yaml/badge.svg)](https://github.com/matsim-scenarios/matsim-kelheim/actions/workflows/build.yaml)
![license](https://img.shields.io/github/license/matsim-scenarios/matsim-kelheim.svg)
[![DOI (v3.0)](https://zenodo.org/badge/360167859.svg)](https://zenodo.org/badge/latestdoi/360167859)
+[![DOI (v3.1.1)](https://zenodo.org/badge/DOI/10.5281/zenodo.13132756.svg)](https://doi.org/10.5281/zenodo.13132756)
![JDK](https://img.shields.io/badge/JDK-17+-green.svg)
![Kelheim MATSim network and agents](visualization-kelheim.png "Kelheim MATSim network and agents")
-
-
-
-
### About this project
This repository provides an open MATSim transport model for Kelheim, provided by the [Transport Systems Planning and Transport Telematics group](https://www.tu.berlin/vsp) of [Technische Universität Berlin](http://www.tu-berlin.de).
+It is developed as part of the [KelRide](https://kelride.com/) project and thus funded by the [German Federal Minstery for Digital and Transport](https://bmdv.bund.de/DE/Home/home.html).
-
+
This scenario contains a 25pct sample of Kelheim and its surrounding area; road capacities are accordingly reduced. The scenario is calibrated taking into consideration the traffic counts, modal split and mode-specific trip distance distributions.
@@ -58,7 +56,7 @@ It can be used by using either of these methods:
(Requires either cloning or downloading the repository and java)
1. Open the cmd and go to your project directory
-2. Build the scenario using `mvnw package`. Add the option `-Dskiptests=true` in order to skip tests and speed up the process.
+2. Build the scenario using `./mvnw package`. Add the option `-DskipTests=true` in order to skip tests and speed up the process.
3. There should be a file directly in the `matsim-kelheim` directory with name approximately as `matsim-kelheim-3.x-SNAPSHOT-.jar`.
4. Run this file from the command line using `java -jar matsim-kelheim-3.x-SNAPSHOT-.jar --help` to see all possible options.
1. For example, one can disable lanes or run smaller sample sizes using the available options
@@ -66,7 +64,7 @@ It can be used by using either of these methods:
1. If you want to run the scenario somewhere else, e.g. on a computation cluster, make sure to not only copy the jar but also the 'input' directory and put it right next to the jar.
6. "Open" the output directory.
1. You can drag files into VIA as was already done above.
- 2. You can also browse the output directory on vsp.berlin/simwrapper and analyze some of your results with interactive dashboards.
+ 2. You can also browse the output directory on vsp.berlin/simwrapper and analyse some of your results with interactive dashboards.
----
### Results and analysis
@@ -78,7 +76,7 @@ Here are the most common ways to analyse and visualize the results (and inputs):
1. (use Google for the best experience)
2. Browse your local output directory or [the public matsim-kelheim data repo](https://vsp.berlin/simwrapper/public/de/kelheim)
2. Explore and create many interactive visualisations and dashboards
-3. Analysis the output .csv tables using the R language and [the matsim-r package](https://github.com/matsim-vsp/matsim-r)
+3. Analyse the output .csv tables using the R language and [the matsim-r package](https://github.com/matsim-vsp/matsim-r)
If you have questions, feel free to contact us [(VSP)](https://www.tu.berlin/vsp) any time :)
@@ -86,6 +84,7 @@ If you have questions, feel free to contact us [(VSP)](https://www.tu.berlin/vsp
## More information
For more information about MATSim, see here: https://www.matsim.org/
+
## Internal documentation
Internal documentation can be found here:
diff --git a/input/v3.1/kelheim-v3.1-25pct.kexi-with-av-intermodal.config.xml b/input/v3.1/kelheim-v3.1-25pct.kexi-with-av-intermodal.config.xml
new file mode 100644
index 00000000..51301517
--- /dev/null
+++ b/input/v3.1/kelheim-v3.1-25pct.kexi-with-av-intermodal.config.xml
@@ -0,0 +1,412 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/v3.1/kelheim-v3.1-25pct.kexi-with-av.config.xml b/input/v3.1/kelheim-v3.1-25pct.kexi-with-av.config.xml
new file mode 100644
index 00000000..e105b8eb
--- /dev/null
+++ b/input/v3.1/kelheim-v3.1-25pct.kexi-with-av.config.xml
@@ -0,0 +1,392 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/input/v3.1/kelheim-v3.1-25pct.kexi.config.xml b/input/v3.1/kelheim-v3.1-25pct.kexi.config.xml
index facb12ee..541495fe 100644
--- a/input/v3.1/kelheim-v3.1-25pct.kexi.config.xml
+++ b/input/v3.1/kelheim-v3.1-25pct.kexi.config.xml
@@ -1,17 +1,17 @@
-
+
-
+
-
-
-
-
+
+
+
+
@@ -42,7 +42,7 @@
-
+
@@ -72,7 +72,7 @@
-
+
@@ -86,7 +86,7 @@
-
+
@@ -130,13 +130,6 @@
-
-
@@ -156,7 +149,7 @@
-
+
@@ -266,9 +259,9 @@
-
-
-
+
+
+
+
@@ -286,7 +280,10 @@
-
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 8dd724e9..64101f47 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
matsim-all
- 2025.0-PR3271
+ 2025.0-PR3328
diff --git a/src/main/R/drtAnalysis/readValuesFromRunSummaries.R b/src/main/R/drtAnalysis/readValuesFromRunSummaries.R
new file mode 100644
index 00000000..7369b90b
--- /dev/null
+++ b/src/main/R/drtAnalysis/readValuesFromRunSummaries.R
@@ -0,0 +1,284 @@
+library(dplyr)
+library(readr)
+library(tidyr)
+library(ggplot2) # Für das Plotting mit ggplot2
+library(plotly)
+
+# Funktion zum Extrahieren der Parameter aus dem Ordnernamen
+extract_parameters <- function(folder_name, speed) {
+ # Extrahiere 'area'
+ area <- strsplit(folder_name, '-')[[1]][1]
+
+ # Extrahiere 'fleetSize'
+ fleet_size_match <- regmatches(folder_name, regexpr("AV\\d+", folder_name))
+ fleet_size <- as.numeric(gsub("AV", "", fleet_size_match))
+
+ # Setze 'intermodal'
+ intermodal <- grepl("intermodal", folder_name)
+
+ # Setze 'allDay'
+ all_day <- grepl("allDay", folder_name)
+
+ return(list(speed = speed, area = area, fleetSize = fleet_size, intermodal = intermodal, allDay = all_day))
+}
+
+# Funktion zum Einlesen der CSV-Datei und Extrahieren der "mean"-Werte
+read_stats <- function(folder_path, file_name) {
+ csv_path <- file.path(folder_path, "analysis/drt-drt-av", file_name)
+
+ if (file.exists(csv_path)) {
+ df <- read_csv(csv_path)
+ mean_values <- df %>% select(parameter, mean)
+ return(mean_values)
+ } else {
+ return(NULL)
+ }
+}
+
+# Hauptfunktion zum Iterieren durch Unterordner
+process_folders <- function(main_folder, speed) {
+ # Liste aller Unterordner im Hauptordner
+ subfolders <- list.dirs(main_folder, recursive = FALSE, full.names = FALSE)
+
+ # Initialisiere eine Liste zum Speichern der Ergebnisse
+ results <- list()
+
+ # Iteriere durch alle Unterordner
+ for (subfolder in subfolders) {
+ parameters <- extract_parameters(subfolder, speed)
+ full_path <- file.path(main_folder, subfolder)
+
+ demand_mean_values <- read_stats(full_path, "avg_demand_stats.csv")
+ supply_mean_values <- read_stats(full_path, "avg_supply_stats.csv")
+
+ if (!is.null(demand_mean_values) || !is.null(supply_mean_values)) {
+ if (!is.null(demand_mean_values)) {
+ demand_mean_values <- demand_mean_values %>%
+ mutate(type = "demand",
+ speed = parameters$speed,
+ area = parameters$area,
+ fleetSize = parameters$fleetSize,
+ intermodal = parameters$intermodal,
+ allDay = parameters$allDay)
+ }
+
+ if (!is.null(supply_mean_values)) {
+ supply_mean_values <- supply_mean_values %>%
+ mutate(type = "supply",
+ speed = parameters$speed,
+ area = parameters$area,
+ fleetSize = parameters$fleetSize,
+ intermodal = parameters$intermodal,
+ allDay = parameters$allDay)
+ }
+
+ combined_values <- bind_rows(demand_mean_values, supply_mean_values)
+ results[[subfolder]] <- combined_values
+ }
+ }
+
+ # Kombiniere alle Ergebnisse in eine Tabelle
+ final_result <- bind_rows(results)
+ return(final_result)
+}
+
+#############
+
+mainDir <- "D:/Projekte/KelRide/runs/v3.1.1/output-KEXI-2.45-AV--0.0/"
+
+mainDir <- "E:/matsim-kelheim/v3.1.1/output-KEXI-2.45-AV--0.0/"
+
+speeds <- list(3.3, 5, 8.3)
+
+results <- list()
+for (speed in speeds) {
+ main_folder <- paste(mainDir, "AV-speed-mps-", speed, "/", sep="")
+ runResults <- process_folders(main_folder, speed)
+ results[[speed]] <- runResults
+}
+
+results <- bind_rows(results)
+
+
+# Transponiere die Tabelle, um Parameter als Spalten zu setzen
+transposed_result <- results %>%
+ select(speed, area, fleetSize, intermodal, allDay, parameter, mean) %>%
+ spread(key = parameter, value = mean)
+
+
+# Ergebnisse ausgeben
+print(results)
+print(transposed_result)
+
+write_csv(transposed_result, paste(mainDir, "results.csv", sep=""))
+
+#####################################################################
+######PLOTS####
+
+# Filtern der Daten für die gewünschten Parameter
+#plot_data <- results %>%
+# filter(parameter %in% c("Handled Requests"))
+
+## Erstellen des interaktiven dreidimensionalen Plots
+#plot <- plot_ly(plot_data,
+# x = ~speed,
+# y = ~fleetSize,
+# z = ~mean,
+# color = ~area,
+# type = "scatter3d",
+# mode = "markers",
+# marker = list(size = 5)) %>%
+# add_markers() %>%
+# layout(title = "Handled Requests by speed, area and Fleet Size",
+# scene = list(xaxis = list(title = "Speed"),
+# yaxis = list(title = "Fleet Size"),
+# zaxis = list(title = "Handled Requests")))
+#
+## Plot anzeigen
+#plot
+
+# Erstellen des interaktiven dreidimensionalen Plots mit Mesh
+plot <- plot_ly(plot_data) %>%
+ add_mesh(x = ~speed,
+ y = ~fleetSize,
+ z = ~mean,
+ color = ~area,
+ opacity = 0.6, # Opazität der Flächen
+ text = ~paste("Area:", area),
+ colors = c("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"), # Farben für jede Area
+ showscale = TRUE) %>%
+ layout(title = "Handled Requests by speed, fleetSize and area",
+ scene = list(xaxis = list(title = "Speed"),
+ yaxis = list(title = "Fleet Size"),
+ zaxis = list(title = "Mean Handled Requests")))
+
+# Plot anzeigen
+plot
+
+#mesh_data <- plot_data %>%
+# group_by(area) %>%
+# summarise(speed = mean(speed),
+# fleetSize = mean(fleetSize),
+# mean = mean(mean)) %>%
+# arrange(area)
+
+## Erstellen des interaktiven dreidimensionalen Plots mit Meshes für jede Area
+#plot <- plot_ly(plot_data) %>%
+# add_trace(x = ~speed,
+# y = ~fleetSize,
+# z = ~mean,
+# color = ~area,
+# type = "scatter3d",
+# mode = "markers",
+# marker = list(size = 5)) %>%
+# add_trace(data = mesh_data,
+# x = ~speed,
+# y = ~fleetSize,
+# z = ~mean,
+# color = ~area,
+# type = "mesh3d",
+# opacity = 0.6, # Opazität der Flächen
+# colorscale = "Viridis", # Farbskala für die Flächen
+# showscale = TRUE) %>%
+# layout(title = "Handled Requests by speed, fleetSize and area",
+# scene = list(xaxis = list(title = "Speed"),
+# yaxis = list(title = "Fleet Size"),
+# zaxis = list(title = "Mean Handled Requests")))
+
+## Plot anzeigen
+#plot
+
+
+###########################
+plotByConfiguration <- function(parameterStr){
+
+ # Filtern der Daten für die gewünschten Parameter
+ plot_data <- results %>%
+ filter(parameter == parameterStr,
+ intermodal == TRUE | area == "SAR2023")
+
+ # Erstellen des Facet-Plots
+ ggplot(plot_data, aes(x = fleetSize, y = mean, color = area, linetype = as.factor(allDay), group = interaction(area, allDay))) +
+ geom_line(size = 1.2) +
+ geom_point(size = 3,
+ #aes(shape = as.factor(intermodal))
+ ) +
+ facet_wrap(~ speed,
+ scales = "free"
+ ) +
+ labs(title = paste(parameterStr, "by Fleet Size, Speed, Area and Service Hours"),
+ x = "Fleet Size",
+ y = parameterStr,
+ color = "Area",
+ linetype = "All Day"
+ #,shape = "Intermodal"
+ ) +
+ theme_dark() +
+ theme(
+ plot.title = element_text(size = 16, face = "bold"), # Titelgröße anpassen
+ axis.title.x = element_text(size = 14), # X-Achsentitelgröße anpassen
+ axis.title.y = element_text(size = 14), # Y-Achsentitelgröße anpassen
+ axis.text = element_text(size = 12), # Achsentextgröße anpassen
+ legend.title = element_text(size = 14), # Legendentitelgröße anpassen
+ legend.text = element_text(size = 12), # Legendtextgröße anpassen
+ strip.text = element_text(size = 12) # Facet-Textgröße anpassen
+ )
+
+}
+
+unique(results$parameter)
+plotByConfiguration("Handled Requests")
+plotByConfiguration("Avg. wait time")
+plotByConfiguration("Avg. ride distance [km]")
+plotByConfiguration("Empty ratio")
+plotByConfiguration("Total vehicle mileage [km]")
+plotByConfiguration("Avg. fare [MoneyUnit]" )
+plotByConfiguration("Pax per veh-km")
+
+
+#####################
+##Zusammenhang wait time und Nachfrage
+
+ handled_requests_data <- results %>%
+ filter(parameter == "Handled Requests") %>%
+ select(area, speed, fleetSize, allDay, mean, intermodal) %>%
+ rename(handled_requests = mean)
+
+ avg_wait_time_data <- results %>%
+ filter(parameter == "Avg. wait time") %>%
+ select(area, speed, fleetSize, allDay, mean, intermodal) %>%
+ rename(avg_wait_time = mean)
+
+ # Zusammenführen der Daten
+ plot_data <- left_join(handled_requests_data, avg_wait_time_data, by = c("area", "speed", "fleetSize", "allDay", "intermodal"))
+
+ # Erstellen des Facet-Plots
+ facet_plot <- ggplot(plot_data, aes(x = avg_wait_time, y = handled_requests, color = area, linetype = as.factor(allDay), group = interaction(area, allDay))) +
+ geom_line(size = 1.2) +
+ geom_point(size = 3
+ #,aes(shape = as.factor(intermodal))
+ ) +
+ facet_wrap(~ speed
+ #, scales = "free"
+ ) +
+ labs(title = "Handled Requests by Avg. Wait Time, Speed, Area, and All Day",
+ x = "Avg. Wait Time",
+ y = "Handled Requests",
+ color = "Area",
+ linetype = "All Day"
+ #,shape = "Intermodal"
+ ) +
+ theme_dark() +
+ theme(
+ plot.title = element_text(size = 16, face = "bold"), # Titelgröße anpassen
+ axis.title.x = element_text(size = 14), # X-Achsentitelgröße anpassen
+ axis.title.y = element_text(size = 14), # Y-Achsentitelgröße anpassen
+ axis.text = element_text(size = 12), # Achsentextgröße anpassen
+ legend.title = element_text(size = 14), # Legendentitelgröße anpassen
+ legend.text = element_text(size = 12), # Legendtextgröße anpassen
+ strip.text = element_text(size = 12) # Facet-Textgröße anpassen
+ )
+
+ # Plot anzeigen
+ print(facet_plot)
+
\ No newline at end of file
diff --git a/src/main/R/drtAnalysis/readValuesFromRunSummaries_v3.0.1-fareExperiments.R b/src/main/R/drtAnalysis/readValuesFromRunSummaries_v3.0.1-fareExperiments.R
new file mode 100644
index 00000000..acc5a567
--- /dev/null
+++ b/src/main/R/drtAnalysis/readValuesFromRunSummaries_v3.0.1-fareExperiments.R
@@ -0,0 +1,188 @@
+library(dplyr)
+library(readr)
+library(tidyr)
+library(ggplot2) # Für das Plotting mit ggplot2
+library(plotly)
+
+# Funktion zum Extrahieren der Parameter aus dem Ordnernamen
+extract_parameters <- function(folder_name) {
+ # Extrahiere 'area'
+ fares <- strsplit(folder_name, '-')[[1]][2]
+
+ return(list(fares = fares))
+}
+
+# Funktion zum Einlesen der CSV-Datei und Extrahieren der "mean"-Werte
+read_stats <- function(folder_path, file_name) {
+ csv_path <- file.path(folder_path, "analysis/drt-drt", file_name)
+
+ if (file.exists(csv_path)) {
+ df <- read_csv(csv_path)
+ mean_values <- df %>% select(parameter, mean)
+ return(mean_values)
+ } else {
+ return(NULL)
+ }
+}
+
+# Hauptfunktion zum Iterieren durch Unterordner
+process_folders <- function(main_folder) {
+ # Liste aller Unterordner im Hauptordner
+ subfolders <- list.dirs(main_folder, recursive = FALSE, full.names = FALSE)
+
+ # Initialisiere eine Liste zum Speichern der Ergebnisse
+ results <- list()
+
+ # Iteriere durch alle Unterordner
+ for (subfolder in subfolders) {
+ parameters <- extract_parameters(subfolder)
+ full_path <- file.path(main_folder, subfolder)
+
+ demand_mean_values <- read_stats(full_path, "avg_demand_stats.csv")
+ supply_mean_values <- read_stats(full_path, "avg_supply_stats.csv")
+
+ if (!is.null(demand_mean_values) || !is.null(supply_mean_values)) {
+ if (!is.null(demand_mean_values)) {
+ demand_mean_values <- demand_mean_values %>%
+ mutate(type = "demand",
+ fares = parameters$fares)
+ }
+
+ if (!is.null(supply_mean_values)) {
+ supply_mean_values <- supply_mean_values %>%
+ mutate(type = "supply",
+ fares = parameters$fares)
+ }
+
+ combined_values <- bind_rows(demand_mean_values, supply_mean_values)
+ results[[subfolder]] <- combined_values
+ }
+ }
+
+ # Kombiniere alle Ergebnisse in eine Tabelle
+ final_result <- bind_rows(results)
+ return(final_result)
+}
+
+#############
+
+mainDir <- "D:/Projekte/KelRide/runs/v3.0.1-fare-experiments/output-KEXI-kexi"
+
+#speeds <- list(3.3, 5, 8.3)
+#results <- list()
+#for (speed in speeds) {
+# main_folder <- paste(mainDir, "AV-speed-mps-", speed, "/", sep="")
+# runResults <- process_folders(mainDir)
+# results[[speed]] <- runResults
+#}
+
+#results <- bind_rows(results)
+
+
+results <- process_folders(mainDir)
+
+# Transponiere die Tabelle, um Parameter als Spalten zu setzen
+transposed_result <- results %>%
+ select(fares, parameter, mean) %>%
+ spread(key = parameter, value = mean)
+
+
+# Ergebnisse ausgeben
+print(results)
+print(transposed_result)
+
+write_csv(transposed_result, paste(mainDir, "results.csv", sep=""))
+
+
+
+
+###########################
+plotByConfiguration <- function(parameterStr){
+
+ # Filtern der Daten für die gewünschten Parameter
+ plot_data <- results %>%
+ filter(parameter == parameterStr)
+
+ # Erstellen des Facet-Plots
+ ggplot(plot_data, aes(x = fares, y = mean)) +
+ #geom_line(size = 1.2) +
+ geom_point(size = 3,
+ #aes(shape = as.factor(intermodal))
+ ) +
+ #facet_wrap(~ speed,
+ # scales = "free"
+ #) +
+ labs(title = paste(parameterStr, "by fare system (conv. KEXI)"),
+ x = "Fare System",
+ y = parameterStr,
+ #color = "Area",
+ #linetype = "All Day"
+ #,shape = "Intermodal"
+ ) +
+ theme_dark() +
+ theme(
+ plot.title = element_text(size = 16, face = "bold"), # Titelgröße anpassen
+ axis.title.x = element_text(size = 14), # X-Achsentitelgröße anpassen
+ axis.title.y = element_text(size = 14), # Y-Achsentitelgröße anpassen
+ axis.text = element_text(size = 12), # Achsentextgröße anpassen
+ legend.title = element_text(size = 14), # Legendentitelgröße anpassen
+ legend.text = element_text(size = 12), # Legendtextgröße anpassen
+ strip.text = element_text(size = 12) # Facet-Textgröße anpassen
+ )
+
+}
+
+unique(results$parameter)
+plotByConfiguration("Rides")
+plotByConfiguration("Avg. wait time")
+plotByConfiguration("Avg. ride distance [km]")
+plotByConfiguration("Empty ratio")
+plotByConfiguration("Total vehicle mileage [km]")
+plotByConfiguration("Avg. fare [MoneyUnit]" )
+plotByConfiguration("Pax per veh-km")
+
+#####################
+##Zusammenhang wait time und Nachfrage
+
+handled_requests_data <- results %>%
+ filter(parameter == "Rides") %>%
+ select(fares, mean) %>%
+ rename(handled_requests = mean)
+
+avg_wait_time_data <- results %>%
+ filter(parameter == "Avg. wait time") %>%
+ select(fares, mean) %>%
+ rename(avg_wait_time = mean)
+
+# Zusammenführen der Daten
+plot_data <- left_join(handled_requests_data, avg_wait_time_data, by = c("fares"))
+
+# Erstellen des Facet-Plots
+facet_plot <- ggplot(plot_data, aes(x = avg_wait_time, y = handled_requests)) +
+ #geom_line(size = 1.2) +
+ geom_point(size = 3
+ #,aes(shape = as.factor(intermodal))
+ ) +
+ geom_text(aes(label = fares), vjust = -1, hjust = 0.5, size = 3, color = "white") +
+ #facet_wrap(~ speed, scales = "free") +
+ labs(title = "Handled Requests by Avg. Wait Time and Fare System (conv. KEXI)",
+ x = "Avg. Wait Time",
+ y = "Handled Requests",
+ #color = "Area",
+ #linetype = "All Day"
+ #,shape = "Intermodal"
+ ) +
+ theme_dark() +
+ theme(
+ plot.title = element_text(size = 16, face = "bold"), # Titelgröße anpassen
+ axis.title.x = element_text(size = 14), # X-Achsentitelgröße anpassen
+ axis.title.y = element_text(size = 14), # Y-Achsentitelgröße anpassen
+ axis.text = element_text(size = 12), # Achsentextgröße anpassen
+ legend.title = element_text(size = 14), # Legendentitelgröße anpassen
+ legend.text = element_text(size = 12), # Legendtextgröße anpassen
+ strip.text = element_text(size = 12) # Facet-Textgröße anpassen
+ )
+
+# Plot anzeigen
+print(facet_plot)
+
diff --git a/src/main/java/org/matsim/analysis/emissions/KelheimOfflineAirPollutionAnalysisByEngineInformation.java b/src/main/java/org/matsim/analysis/emissions/KelheimOfflineAirPollutionAnalysisByEngineInformation.java
index 099f658a..1d0c91c4 100644
--- a/src/main/java/org/matsim/analysis/emissions/KelheimOfflineAirPollutionAnalysisByEngineInformation.java
+++ b/src/main/java/org/matsim/analysis/emissions/KelheimOfflineAirPollutionAnalysisByEngineInformation.java
@@ -50,6 +50,7 @@
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
+import org.matsim.core.controler.Injector;
import org.matsim.core.events.EventsUtils;
import org.matsim.core.events.MatsimEventsReader;
import org.matsim.core.network.NetworkUtils;
@@ -159,6 +160,10 @@ public void install(){
}
};
+ com.google.inject.Injector injector = Injector.createInjector(config, module);
+ // Emissions module will be installed to the event handler
+ injector.getInstance(EmissionModule.class);
+
EmissionsOnLinkEventHandler emissionsEventHandler = new EmissionsOnLinkEventHandler(3600);
eventsManager.addHandler(emissionsEventHandler);
eventsManager.initProcessing();
diff --git a/src/main/java/org/matsim/analysis/postAnalysis/NoiseAverageAnalysis.java b/src/main/java/org/matsim/analysis/postAnalysis/NoiseAverageAnalysis.java
index dc4593f0..33974c26 100644
--- a/src/main/java/org/matsim/analysis/postAnalysis/NoiseAverageAnalysis.java
+++ b/src/main/java/org/matsim/analysis/postAnalysis/NoiseAverageAnalysis.java
@@ -51,7 +51,6 @@ public class NoiseAverageAnalysis implements MATSimAppCommand {
@CommandLine.Option(names = "--no-runs", defaultValue = "5", description = "Number of simulation runs to be averaged.")
private Integer noRuns;
- private final CsvOptions csv = new CsvOptions();
private static final String ANALYSIS_DIR = "/analysis/noise";
private static final String LINK_ID = "Link Id";
private static final String VALUE = "value";
@@ -65,6 +64,11 @@ public static void main(String[] args) {
new NoiseAverageAnalysis().execute(args);
}
+ public NoiseAverageAnalysis() {
+// constructor needed for test only.. otherwise the read and write methods of this class would have to be copied, which is ugly. -sme0624
+
+ }
+
@Override
public Integer call() throws Exception {
String runs = input.getPath("runs");
@@ -76,13 +80,13 @@ public Integer call() throws Exception {
final Path analysisDir = Path.of(folder + ANALYSIS_DIR);
String emissionsCsv = globFile(analysisDir, "*emission_per_day.csv*").toString();
String imissionsPerDayAvro = globFile(analysisDir, "*immission_per_day.avro*").toString();
- String imissionsPerHourAvro = globFile(analysisDir, "*immission_per_day.avro*").toString();
+ String imissionsPerHourAvro = globFile(analysisDir, "*immission_per_hour.avro*").toString();
// read
Table emissions = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(emissionsCsv))
.columnTypesPartial(Map.of(LINK_ID, ColumnType.STRING, VALUE, ColumnType.DOUBLE))
.sample(false)
- .separator(csv.detectDelimiter(emissionsCsv)).build());
+ .separator(CsvOptions.detectDelimiter(emissionsCsv)).build());
// read avro file
readAvroFile(imissionsPerDayAvro, imissionsPerDay);
@@ -128,7 +132,10 @@ public Integer call() throws Exception {
return 0;
}
- private void writeAvro(XYTData xytData, File outputFile) {
+ /**
+ * write an .avro file containing immission data.
+ */
+ public void writeAvro(XYTData xytData, File outputFile) {
DatumWriter datumWriter = new SpecificDatumWriter<>(XYTData.class);
try (DataFileWriter dataFileWriter = new DataFileWriter<>(datumWriter)) {
dataFileWriter.setCodec(CodecFactory.deflateCodec(9));
@@ -148,6 +155,7 @@ private XYTData calcAvroMeans(List recordList) {
for (GenericRecord genericRecord: recordList) {
+// for every record: 0 crs, 1 xCoords, 2 yCoords, 3 timeStamps, 4 actual immission data
String object0 = genericRecord.get(0).toString();
Object object1 = genericRecord.get(1);
Object object2 = genericRecord.get(2);
@@ -225,7 +233,10 @@ private void getCoordData(Object object, List target) {
}
}
- private void readAvroFile(String input, List target) {
+ /**
+ * read an .avro file containing immissions.
+ */
+ public void readAvroFile(String input, List target) {
try {
// Read the schema from the Avro file
FileReader fileReader = DataFileReader.openReader(new File(input), new GenericDatumReader<>());
diff --git a/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtPostProcessingAverageAnalysis.java b/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtPostProcessingAverageAnalysis.java
index 035d0c26..fa2a8cba 100644
--- a/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtPostProcessingAverageAnalysis.java
+++ b/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtPostProcessingAverageAnalysis.java
@@ -17,6 +17,8 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.time.LocalTime;
import java.util.*;
@@ -25,11 +27,7 @@
@CommandLine.Command(name = "average-drt", description = "Calculates average drt stats based on several sim runs with different random seeds.")
@CommandSpec(
requires = {"runs", "mode"},
- produces = {"rides_per_veh_avg_demand_stats.csv", "avg_wait_time_avg_demand_stats.csv", "requests_avg_demand_stats.csv", "avg_total_travel_time_avg_demand_stats.csv",
- "rides_avg_demand_stats.csv", "avg_direct_distance_[km]_avg_demand_stats.csv", "rejections_avg_demand_stats.csv", "95th_percentile_wait_time_avg_demand_stats.csv",
- "avg_in-vehicle_time_avg_demand_stats.csv", "avg_ride_distance_[km]_avg_demand_stats.csv", "rejection_rate_avg_demand_stats.csv",
- "avg_fare_[MoneyUnit]_avg_demand_stats.csv", "total_service_hours_avg_supply_stats.csv", "pooling_ratio_avg_supply_stats.csv", "detour_ratio_avg_supply_stats.csv",
- "total_vehicle_mileage_[km]_avg_supply_stats.csv", "empty_ratio_avg_supply_stats.csv", "number_of_stops_avg_supply_stats.csv", "total_pax_distance_[km]_avg_supply_stats.csv", "vehicles_avg_supply_stats.csv"}
+ produces = {"avg_demand_stats.csv", "avg_supply_stats.csv"}
)
public class DrtPostProcessingAverageAnalysis implements MATSimAppCommand {
@@ -44,7 +42,6 @@ public class DrtPostProcessingAverageAnalysis implements MATSimAppCommand {
private final Map> supplyStats = new HashMap<>();
private final Map demandAvgs = new HashMap<>();
private final Map supplyAvgs = new HashMap<>();
- Map> params = new HashMap<>();
private final CsvOptions csv = new CsvOptions();
@@ -70,11 +67,11 @@ public Integer call() throws Exception {
Table demand = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(demandKpiCsv))
.sample(false)
- .separator(csv.detectDelimiter(demandKpiCsv)).build());
+ .separator(CsvOptions.detectDelimiter(demandKpiCsv)).build());
Table supply = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(supplyKpiCsv))
.sample(false)
- .separator(csv.detectDelimiter(supplyKpiCsv)).build());
+ .separator(CsvOptions.detectDelimiter(supplyKpiCsv)).build());
// get all demand stats
for (int i = 0; i < demand.rowCount(); i++) {
@@ -113,38 +110,30 @@ public Integer call() throws Exception {
fillAvgMap(demandStats, demandAvgs);
fillAvgMap(supplyStats, supplyAvgs);
- params.put("avg_demand_stats.csv", List.of("rides_per_veh", "avg_wait_time", "requests", "avg_total_travel_time", "rides", "avg_direct_distance_[km]",
- "rejections", "95th_percentile_wait_time", "avg_in-vehicle_time", "avg_ride_distance_[km]", "rejection_rate", "avg_fare_[MoneyUnit]"));
- params.put("avg_supply_stats.csv", List.of("total_service_hours", "pooling_ratio", "detour_ratio", "total_vehicle_mileage_[km]", "empty_ratio", "number_of_stops",
- "total_pax_distance_[km]", "vehicles"));
+// ordered list of params to display them in same order as in single-run DrtDashboard
+ List orderedDemandParams = List.of("Handled Requests", "Passengers (Pax)", "Avg Group Size", "Pax per veh", "Pax per veh-h", "Pax per veh-km",
+ "Rejections", "Rejection rate", "Avg. total travel time", "Avg. in-vehicle time", "Avg. wait time", "95th percentile wait time", "Avg. ride distance [km]",
+ "Avg. direct distance [km]", "Avg. fare [MoneyUnit]");
+ List orderedSupplyParams = List.of("Number of stops", "Vehicles", "Total vehicle mileage [km]", "Empty ratio", "Total pax distance [km]",
+ "Occupancy rate [pax-km/v-km]", "Detour ratio", "Total service hours");
- for (Map.Entry> e : params.entrySet()) {
- for (String param : params.get(e.getKey())) {
- if (e.getKey().contains("demand")) {
- writeFile(e.getKey(), demandAvgs, param);
- } else {
- writeFile(e.getKey(), supplyAvgs, param);
- }
- }
- }
+ writeFile("avg_demand_stats.csv", demandAvgs, orderedDemandParams);
+ writeFile("avg_supply_stats.csv", supplyAvgs, orderedSupplyParams);
return 0;
}
- private void writeFile(String fileName, Map values, String param) throws IOException {
- try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath(param + "_" + fileName)), CSVFormat.DEFAULT)) {
+ private void writeFile(String fileName, Map values, List orderedParams) throws IOException {
+ try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath(fileName)), CSVFormat.DEFAULT)) {
+ DecimalFormat df = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.US));
- printer.printRecord("info", value);
+// as of 19.06.24 min and max values are not printed anymore. they will still be calculated though.
+// if one wants to include them to dashboard tables one just has to re-include them in this print method. -sme0624
+ printer.printRecord("parameter", "mean", "median", "standard deviation");
- for (Map.Entry e : values.entrySet()) {
- String transformed = e.getKey().toLowerCase().replace(".", "").replace(" ", "_");
- if (transformed.contains(param)) {
- printer.printRecord("mean-" + e.getKey(), e.getValue()[0]);
- printer.printRecord("median-" + e.getKey(), e.getValue()[1]);
- printer.printRecord("sd-" + e.getKey(), e.getValue()[2]);
- printer.printRecord("min-" + e.getKey(), e.getValue()[3]);
- printer.printRecord("max-" + e.getKey(), e.getValue()[4]);
- }
+
+ for (String param : orderedParams) {
+ printer.printRecord(param, df.format(values.get(param)[0]), df.format(values.get(param)[1]), df.format(values.get(param)[2]));
}
}
}
diff --git a/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtServiceQualityAnalysis.java b/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtServiceQualityAnalysis.java
index b1027c2a..6391f16d 100644
--- a/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtServiceQualityAnalysis.java
+++ b/src/main/java/org/matsim/analysis/postAnalysis/drt/DrtServiceQualityAnalysis.java
@@ -8,6 +8,7 @@
import org.apache.commons.math3.util.Precision;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Geometry;
import org.matsim.analysis.postAnalysis.traffic.TrafficAnalysis;
import org.matsim.api.core.v01.Coord;
@@ -35,7 +36,6 @@
import org.matsim.vehicles.Vehicle;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;
-import org.opengis.feature.simple.SimpleFeature;
import picocli.CommandLine;
import java.io.FileWriter;
diff --git a/src/main/java/org/matsim/dashboard/AverageDrtDashboard.java b/src/main/java/org/matsim/dashboard/AverageDrtDashboard.java
index 82ed8fde..cb467c21 100644
--- a/src/main/java/org/matsim/dashboard/AverageDrtDashboard.java
+++ b/src/main/java/org/matsim/dashboard/AverageDrtDashboard.java
@@ -39,142 +39,20 @@ public void configure(Header header, Layout layout) {
header.description = "Overview for the demand-responsive mode '" + mode + "'. This dashboard shows average values for " + noRuns +
" simulation runs. For the results of the specific runs please choose the according directory next to this dashboard.yaml.";
-// DEMAND
- layout.row("one")
- .el(Table.class, (viz, data) -> {
- viz.title = "Rides per vehicle";
- viz.dataset = postProcess(data, "rides_per_veh_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg wait time";
- viz.dataset = postProcess(data, "avg_wait_time_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Requests";
- viz.dataset = postProcess(data, "requests_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- });
-
- layout.row("two")
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg total travel time";
- viz.dataset = postProcess(data, "avg_total_travel_time_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Rides";
- viz.dataset = postProcess(data, "rides_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg direct distance [km]";
- viz.dataset = postProcess(data, "avg_direct_distance_[km]_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- });
-
- layout.row("three")
- .el(Table.class, (viz, data) -> {
- viz.title = "Rejections";
- viz.dataset = postProcess(data, "rejections_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "95th percentile wait time";
- viz.dataset = postProcess(data, "95th_percentile_wait_time_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg in-vehicle time";
- viz.dataset = postProcess(data, "avg_in-vehicle_time_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- });
-
- layout.row("four")
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg ride distance [km]";
- viz.dataset = postProcess(data, "avg_ride_distance_[km]_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Rejection rate";
- viz.dataset = postProcess(data, "rejection_rate_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Avg fare [MoneyUnit]";
- viz.dataset = postProcess(data, "avg_fare_[MoneyUnit]_avg_demand_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- });
-
// SUPPLY
- supplyTabs(layout);
- }
-
- private void supplyTabs(Layout layout) {
- layout.row("six")
+ layout.row("supply")
.el(Table.class, (viz, data) -> {
- viz.title = "Total service hours";
- viz.dataset = postProcess(data, "total_service_hours_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Pooling ratio";
- viz.dataset = postProcess(data, "pooling_ratio_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Detour ratio";
- viz.dataset = postProcess(data, "detour_ratio_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- });
-
- layout.row("seven")
- .el(Table.class, (viz, data) -> {
- viz.title = "Total vehicle mileage [km]";
- viz.dataset = postProcess(data, "total_vehicle_mileage_[km]_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Empty ratio";
- viz.dataset = postProcess(data, "empty_ratio_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
- .el(Table.class, (viz, data) -> {
- viz.title = "Number of stops";
- viz.dataset = postProcess(data, "number_of_stops_avg_supply_stats.csv");
+ viz.title = "Service summary";
+ viz.dataset = postProcess(data, "avg_supply_stats.csv");
viz.showAllRows = true;
viz.width = 1.;
});
- layout.row("eight")
- .el(Table.class, (viz, data) -> {
- viz.title = "Total pax distance [km]";
- viz.dataset = postProcess(data, "total_pax_distance_[km]_avg_supply_stats.csv");
- viz.showAllRows = true;
- viz.width = 1.;
- })
+ // DEMAND
+ layout.row("demand")
.el(Table.class, (viz, data) -> {
- viz.title = "Vehicles";
- viz.dataset = postProcess(data, "vehicles_avg_supply_stats.csv");
+ viz.title = "Demand summary";
+ viz.dataset = postProcess(data, "avg_demand_stats.csv");
viz.showAllRows = true;
viz.width = 1.;
});
diff --git a/src/main/java/org/matsim/dashboard/CreateAverageDashboards.java b/src/main/java/org/matsim/dashboard/CreateAverageDashboards.java
index d4c1f9e6..cc0dd7f5 100644
--- a/src/main/java/org/matsim/dashboard/CreateAverageDashboards.java
+++ b/src/main/java/org/matsim/dashboard/CreateAverageDashboards.java
@@ -19,7 +19,7 @@
/**
* class to create average dashboards and run the necessary analysis for that.
*/
-public class CreateAverageDashboards implements MATSimAppCommand {
+final class CreateAverageDashboards implements MATSimAppCommand {
@CommandLine.Option(names = "--input-path", required = true, description = "Path to directory with run directories.")
private String inputPath;
@CommandLine.Option(names = "--no-runs", defaultValue = "5", description = "Number of simulation runs to be averaged.")
@@ -62,7 +62,7 @@ public Integer call() throws Exception {
Arrays.stream(new File(analysisDir).listFiles())
.filter(d -> d.getAbsolutePath().contains(TransportMode.drt))
- .forEach(f -> modes.add(f.getAbsolutePath().substring(f.getAbsolutePath().lastIndexOf("\\") + 1)));
+ .forEach(f -> modes.add(f.getName()));
SimWrapper sw = SimWrapper.create();
diff --git a/src/main/java/org/matsim/dashboard/KelheimDashboardProvider.java b/src/main/java/org/matsim/dashboard/KelheimDashboardProvider.java
index 19a478d2..17a1a6c3 100644
--- a/src/main/java/org/matsim/dashboard/KelheimDashboardProvider.java
+++ b/src/main/java/org/matsim/dashboard/KelheimDashboardProvider.java
@@ -6,7 +6,6 @@
import org.matsim.simwrapper.Dashboard;
import org.matsim.simwrapper.DashboardProvider;
import org.matsim.simwrapper.SimWrapper;
-import org.matsim.simwrapper.dashboard.NoiseDashboard;
import org.matsim.simwrapper.dashboard.TravelTimeComparisonDashboard;
import org.matsim.simwrapper.dashboard.TripDashboard;
@@ -27,8 +26,9 @@ public List getDashboards(Config config, SimWrapper simWrapper) {
return List.of(
trips,
new TravelTimeComparisonDashboard(IOUtils.resolveFileOrResource( "kelheim-v3.0-routes-ref.csv.gz").toString()),
- new KelheimEmissionsDashboard(),
- new NoiseDashboard()
+ new KelheimEmissionsDashboard()
+ //the NoiseAnalysis needs more RAM than the entire simulation, which leads to VM crashes and prevents other analysis to run. We have to run it separately (e.g. with KelheimSimWrapperRunner)
+// new NoiseDashboard()
);
}
diff --git a/src/main/java/org/matsim/analysis/CreateEmissionDashboard.java b/src/main/java/org/matsim/dashboard/KelheimSimWrapperRunner.java
similarity index 68%
rename from src/main/java/org/matsim/analysis/CreateEmissionDashboard.java
rename to src/main/java/org/matsim/dashboard/KelheimSimWrapperRunner.java
index 6ea2e798..e6fdc075 100644
--- a/src/main/java/org/matsim/analysis/CreateEmissionDashboard.java
+++ b/src/main/java/org/matsim/dashboard/KelheimSimWrapperRunner.java
@@ -18,7 +18,7 @@
* *
* *********************************************************************** */
-package org.matsim.analysis;
+package org.matsim.dashboard;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -26,24 +26,25 @@
import org.matsim.application.ApplicationUtils;
import org.matsim.application.MATSimAppCommand;
import org.matsim.application.options.ShpOptions;
+import org.matsim.contrib.drt.extension.dashboards.DrtDashboardProvider;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.simwrapper.SimWrapper;
import org.matsim.simwrapper.SimWrapperConfigGroup;
+import org.matsim.simwrapper.dashboard.NoiseDashboard;
import picocli.CommandLine;
-import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
@CommandLine.Command(
- name = "emissions",
+ name = "simwrapper",
description = "Run emission analysis and create SimWrapper dashboard for existing run output."
)
-final class CreateEmissionDashboard implements MATSimAppCommand {
+final class KelheimSimWrapperRunner implements MATSimAppCommand {
- private static final Logger log = LogManager.getLogger(CreateEmissionDashboard.class);
+ private static final Logger log = LogManager.getLogger(KelheimSimWrapperRunner.class);
@CommandLine.Parameters(arity = "1..*", description = "Path to run output directories for which emission dashboards are to be generated.")
private List inputPaths;
@@ -53,15 +54,29 @@ final class CreateEmissionDashboard implements MATSimAppCommand {
@CommandLine.Option(names = "--base", description = "Optional. " +
"Relative path (from each! output directory provided) to main output folder for the base MATSim run. " +
- "Will be used to compare emissions per link.", required = false)
+ "Will be used to compare emissions per link.")
private String baseRun;
- private CreateEmissionDashboard(){
+ @CommandLine.Option(names = "--emissions", defaultValue = "false", description = "create emissions dashboard")
+ private boolean emissions;
+
+ @CommandLine.Option(names = "--noise", defaultValue = "false", description = "create noise dashboard")
+ private boolean noise;
+
+ @CommandLine.Option(names = "--drt", defaultValue = "false", description = "create DRT + AV dashboards")
+ private boolean drt;
+
+
+ private KelheimSimWrapperRunner(){
}
@Override
public Integer call() throws Exception {
+ if (!drt && !emissions && !noise){
+ throw new IllegalArgumentException("you have not configured any dashboard to be created! Use command line parameters!");
+ }
+
for (Path runDirectory : inputPaths) {
log.info("Running on {}", runDirectory);
@@ -81,10 +96,19 @@ public Integer call() throws Exception {
simwrapperCfg.defaultDashboards = SimWrapperConfigGroup.Mode.disabled;
simwrapperCfg.defaultParams().mapCenter = "48.91265,11.89223";
- if (baseRun != null){
- sw.addDashboard(new KelheimEmissionsDashboard(baseRun));
- } else {
- sw.addDashboard(new KelheimEmissionsDashboard());
+ //add dashboards according to command line parameters
+ if (emissions){
+ if (baseRun != null){
+ sw.addDashboard(new KelheimEmissionsDashboard(baseRun));
+ } else {
+ sw.addDashboard(new KelheimEmissionsDashboard());
+ }
+ }
+ if (drt){
+ new DrtDashboardProvider().getDashboards(config, sw).forEach(sw::addDashboard);
+ }
+ if (noise){
+ sw.addDashboard(new NoiseDashboard());
}
try {
@@ -99,45 +123,8 @@ public Integer call() throws Exception {
}
public static void main(String[] args) {
- new CreateEmissionDashboard().execute(args);
+ new KelheimSimWrapperRunner().execute(args);
}
- private static void renameExistingDashboardYAMLs(Path runDirectory) {
- // List of files in the folder
- File folder = new File(runDirectory.toString());
- File[] files = folder.listFiles();
-
- // Loop through all files in the folder
- if (files != null) {
- for (File file : files) {
- if (file.isFile()) {
- // Check if the file name starts with "dashboard-" and ends with ".yaml"
- if (file.getName().startsWith("dashboard-") && file.getName().endsWith(".yaml")) {
- // Get the current file name
- String oldName = file.getName();
-
- // Extract the number from the file name
- String numberPart = oldName.substring(oldName.indexOf('-') + 1, oldName.lastIndexOf('.'));
-
- // Increment the number by ten
- int number = Integer.parseInt(numberPart) + 10;
-
- // Create the new file name
- String newName = "dashboard-" + number + ".yaml";
-
- // Create the new File object with the new file name
- File newFile = new File(file.getParent(), newName);
-
- // Rename the file
- if (file.renameTo(newFile)) {
- log.info("File successfully renamed: " + newName);
- } else {
- log.info("Error renaming file: " + file.getName());
- }
- }
- }
- }
- }
- }
}
diff --git a/src/main/java/org/matsim/drtFare/KelheimDrtFareHandler.java b/src/main/java/org/matsim/drtFare/KelheimDrtFareHandler.java
index d689c1d7..25ce692a 100644
--- a/src/main/java/org/matsim/drtFare/KelheimDrtFareHandler.java
+++ b/src/main/java/org/matsim/drtFare/KelheimDrtFareHandler.java
@@ -3,6 +3,7 @@
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Geometry;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.events.PersonMoneyEvent;
@@ -19,7 +20,6 @@
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.utils.geometry.geotools.MGC;
import org.matsim.core.utils.gis.GeoFileReader;
-import org.opengis.feature.simple.SimpleFeature;
import java.net.MalformedURLException;
import java.net.URL;
diff --git a/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java b/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java
index d69d3f85..ab5fdf86 100644
--- a/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java
+++ b/src/main/java/org/matsim/run/prepare/DrtStopsWriter.java
@@ -5,6 +5,7 @@
import org.apache.commons.csv.CSVRecord;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Geometry;
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
@@ -18,7 +19,6 @@
import org.matsim.core.utils.io.IOUtils;
import org.matsim.core.utils.io.MatsimXmlWriter;
import org.matsim.run.RunKelheimScenario;
-import org.opengis.feature.simple.SimpleFeature;
import java.io.FileWriter;
import java.io.IOException;
diff --git a/src/main/java/org/matsim/run/prepare/PrepareNetwork.java b/src/main/java/org/matsim/run/prepare/PrepareNetwork.java
index 3bafb9f9..b22fb53a 100644
--- a/src/main/java/org/matsim/run/prepare/PrepareNetwork.java
+++ b/src/main/java/org/matsim/run/prepare/PrepareNetwork.java
@@ -2,6 +2,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
@@ -13,7 +14,6 @@
import org.matsim.application.options.ShpOptions;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.utils.geometry.geotools.MGC;
-import org.opengis.feature.simple.SimpleFeature;
import picocli.CommandLine;
import java.util.HashSet;
diff --git a/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java b/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java
index a7fd41a8..689e5bf5 100644
--- a/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java
+++ b/src/main/java/org/matsim/run/prepare/PrepareTransitSchedule.java
@@ -1,5 +1,6 @@
package org.matsim.run.prepare;
+import org.geotools.api.feature.simple.SimpleFeature;
import org.locationtech.jts.geom.Geometry;
import org.matsim.api.core.v01.Scenario;
import org.matsim.application.MATSimAppCommand;
@@ -12,7 +13,6 @@
import org.matsim.pt.transitSchedule.api.TransitSchedule;
import org.matsim.pt.transitSchedule.api.TransitScheduleWriter;
import org.matsim.pt.transitSchedule.api.TransitStopFacility;
-import org.opengis.feature.simple.SimpleFeature;
import picocli.CommandLine;
import java.util.List;
diff --git a/src/test/java/org/matsim/run/MeanNoiseDashboardTest.java b/src/test/java/org/matsim/run/MeanNoiseDashboardTest.java
new file mode 100644
index 00000000..e53ed822
--- /dev/null
+++ b/src/test/java/org/matsim/run/MeanNoiseDashboardTest.java
@@ -0,0 +1,133 @@
+package org.matsim.run;
+
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.util.Utf8;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.matsim.analysis.postAnalysis.NoiseAverageAnalysis;
+import org.matsim.application.avro.XYTData;
+import org.matsim.application.options.CsvOptions;
+import org.matsim.application.prepare.network.CreateGeoJsonNetwork;
+import org.matsim.core.utils.io.IOUtils;
+import org.matsim.dashboard.AverageKelheimNoiseDashboard;
+import org.matsim.simwrapper.Dashboard;
+import org.matsim.simwrapper.SimWrapper;
+import org.matsim.testcases.MatsimTestUtils;
+import tech.tablesaw.api.ColumnType;
+import tech.tablesaw.api.Table;
+import tech.tablesaw.io.csv.CsvReadOptions;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class MeanNoiseDashboardTest {
+
+ @RegisterExtension
+ public final MatsimTestUtils utils = new MatsimTestUtils();
+
+ /**
+ * Test for building means over noise emission and immission values of several runs. The display of the values has to be done manually by looking at the resulting mean noise dashbaord.
+ */
+ @Test
+ void runMeanNoiseDashboardTest() throws IOException {
+
+ String networkPath = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/kelheim/kelheim-v3.0/input/kelheim-v3.0-network.xml.gz";
+ String crs = "EPSG:25832";
+ String path = utils.getInputDirectory();
+ NoiseAverageAnalysis analysis = new NoiseAverageAnalysis();
+
+ List foldersSeeded = new ArrayList<>();
+
+ new CreateGeoJsonNetwork().execute(List.of("--network", networkPath, "--with-properties", "--shp", "./input/shp/dilutionArea.shp", "--output-network", path + "1seed/analysis/network/network.geojson",
+ "--input-crs", "EPSG:25832").toArray(new String[0]));
+
+// write dummy data
+ for (int i = 1; i <= 3; i++) {
+ List xCoords = new ArrayList<>();
+ List yCoords = new ArrayList<>();
+ List timeStamps = new ArrayList<>();
+ Map> data = new HashMap<>();
+
+ xCoords.add(710419.08F);
+ xCoords.add(710424.82F);
+ yCoords.add(5421673.49F);
+ yCoords.add(5422288.95F);
+
+ timeStamps.add(28800);
+
+ data.put("imissions", List.of((float) i));
+
+ String seedDir = path + i + "seed/";
+ foldersSeeded.add(seedDir);
+
+// write avro dummy files
+ Files.createDirectories(Path.of(seedDir + "analysis/noise/"));
+ analysis.writeAvro(new XYTData(crs, xCoords, yCoords, List.of(0), data), new File(seedDir + "analysis/noise/immission_per_day.avro"));
+ analysis.writeAvro(new XYTData(crs, xCoords, yCoords, timeStamps, data), new File(seedDir + "analysis/noise/immission_per_hour.avro"));
+
+// write emissions csv dummy file
+ try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(Path.of(seedDir + "analysis/noise/emission_per_day.csv")), CSVFormat.DEFAULT)) {
+ printer.printRecord("Link Id", "value");
+ printer.printRecord("-27443742#0", i);
+ }
+ }
+
+ SimWrapper sw = SimWrapper.create();
+ sw.getConfigGroup().defaultParams().mapCenter = "11.89,48.91";
+ sw.addDashboard(Dashboard.customize(new AverageKelheimNoiseDashboard(foldersSeeded, 3)).context("noise"));
+ try {
+ sw.generate(Path.of(path), true);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ sw.run(Path.of(path));
+
+// assert that: a) mean immission is 2.0 on daily and hourly data b) hourly data has timestamp 28800 c) mean emission is 2.0
+ List daily = new ArrayList<>();
+ List hourly = new ArrayList<>();
+ analysis.readAvroFile(path + "analysis/postAnalysis-noise/mean_immission_per_day.avro", daily);
+ analysis.readAvroFile(path + "analysis/postAnalysis-noise/mean_immission_per_hour.avro", hourly);
+
+ if (daily.getFirst().get(4) instanceof HashMap, ?>) {
+ Map.Entry, ?> entry = ((HashMap, ?>) daily.getFirst().get(4)).entrySet().stream().toList().getFirst();
+ if (entry.getKey() instanceof Utf8 && entry.getValue() instanceof GenericData.Array>) {
+ float dailyImmission = ((GenericData.Array) entry.getValue()).getFirst();
+ Assertions.assertEquals(2.0, dailyImmission);
+ }
+ }
+
+ if (hourly.getFirst().get(4) instanceof HashMap, ?>) {
+ Map.Entry, ?> entry = ((HashMap, ?>) hourly.getFirst().get(4)).entrySet().stream().toList().getFirst();
+ if (entry.getKey() instanceof Utf8 && entry.getValue() instanceof GenericData.Array>) {
+ float hourlyImmission = ((GenericData.Array) entry.getValue()).getFirst();
+ Assertions.assertEquals(2.0, hourlyImmission);
+ }
+ }
+
+ if (hourly.getFirst().get(3) instanceof GenericData.Array>) {
+ int timeStamp = ((GenericData.Array) hourly.getFirst().get(3)).getFirst();
+ Assertions.assertEquals(28800, timeStamp);
+ }
+
+ Table emissions = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path + "analysis/postAnalysis-noise/mean_emission_per_day.csv"))
+ .columnTypesPartial(Map.of("Link Id", ColumnType.STRING, "value", ColumnType.DOUBLE))
+ .sample(false)
+ .separator(CsvOptions.detectDelimiter(path + "analysis/postAnalysis-noise/mean_emission_per_day.csv")).build());
+
+ String linkId = emissions.row(0).getString("Link Id");
+ double emission = emissions.row(0).getDouble("value");
+
+ Assertions.assertEquals("-27443742#0", linkId);
+ Assertions.assertEquals(2.0, emission);
+ }
+}