Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next version update #16

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion input/v2024.2/lausitz-v2024.2-10pct.config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<param name="lastIteration" value="500"/>
<param name="overwriteFiles" value="failIfDirectoryExists"/>
<param name="runId" value="lausitz-10pct"/>
<param name="outputDirectory" value="./output/output-lausitz-25pct"/>
<param name="outputDirectory" value="./output/output-lausitz-10pct"/>
<param name="writeEventsInterval" value="100"/>
<param name="writePlansInterval" value="100"/>
<param name="enableLinkToLinkRouting" value="false"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public List<Dashboard> getDashboards(Config config, SimWrapper simWrapper) {
.setAnalysisArgs("--person-filter", "subpopulation=person");

return List.of(trips,
new EmissionsDashboard(config.global().getCoordinateSystem())
new EmissionsDashboard(config.global().getCoordinateSystem()),
new PtLineDashboard("https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/lausitz/output/v2024.2/")
// the NoiseAnalysis is not run here because it 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 LausitzSimWrapperRunner)
);
Expand Down
56 changes: 44 additions & 12 deletions src/main/java/org/matsim/dashboards/LausitzSimWrapperRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

Expand All @@ -66,16 +67,24 @@ public final class LausitzSimWrapperRunner implements MATSimAppCommand {
private boolean trips;
@CommandLine.Option(names = "--emissions", defaultValue = "false", description = "create emission dashboard")
private boolean emissions;
@CommandLine.Option(names = "--pt-line-base-dir", description = "create pt line dashboard with base run dir as input")
private String baseDir;

private static final String FILE_TYPE = "_before_emissions.xml";


public LausitzSimWrapperRunner(){
// public constructor needed for testing purposes.
}

public static void main(String[] args) {
new LausitzSimWrapperRunner().execute(args);
}

@Override
public Integer call() throws Exception {

if (!noise && !trips && !emissions){
if (!noise && !trips && !emissions && baseDir == null){
throw new IllegalArgumentException("you have not configured any dashboard to be created! Please use command line parameters!");
}

Expand Down Expand Up @@ -112,30 +121,40 @@ public Integer call() throws Exception {
sw.addDashboard(Dashboard.customize(new EmissionsDashboard(config.global().getCoordinateSystem())).context("emissions"));

LausitzScenario.setEmissionsConfigs(config);
ConfigUtils.writeConfig(config, configPath);

Config dummyConfig = new Config();

String networkPath = ApplicationUtils.matchInput("output_network.xml.gz", runDirectory).toString();
String vehiclesPath = ApplicationUtils.matchInput("output_vehicles.xml.gz", runDirectory).toString();
String transitVehiclesPath = ApplicationUtils.matchInput("output_transitVehicles.xml.gz", runDirectory).toString();
String populationPath = ApplicationUtils.matchInput("output_plans.xml.gz", runDirectory).toString();

dummyConfig.network().setInputFile(networkPath);
dummyConfig.vehicles().setVehiclesFile(vehiclesPath);
dummyConfig.transit().setVehiclesFile(transitVehiclesPath);
config.network().setInputFile(networkPath);
config.vehicles().setVehiclesFile(vehiclesPath);
config.transit().setVehiclesFile(transitVehiclesPath);
config.plans().setInputFile(populationPath);

Scenario scenario = ScenarioUtils.loadScenario(dummyConfig);
Scenario scenario = ScenarioUtils.loadScenario(config);

// adapt network and veh types for emissions analysis like in LausitzScenario base run class
PrepareNetwork.prepareEmissionsAttributes(scenario.getNetwork());
LausitzScenario.prepareVehicleTypesForEmissionAnalysis(scenario);

// overwrite outputs with adapted files
// write outputs with adapted files.
// original output files need to be overwritten as AirPollutionAnalysis searches for "config.xml".
// copy old files to separate files
Files.copy(Path.of(configPath), getUniqueTargetPath(Path.of(configPath.split(".xml")[0] + FILE_TYPE)));
Files.copy(Path.of(networkPath), getUniqueTargetPath(Path.of(networkPath.split(".xml")[0] + FILE_TYPE + ".gz")));
Files.copy(Path.of(vehiclesPath), getUniqueTargetPath(Path.of(vehiclesPath.split(".xml")[0] + FILE_TYPE + ".gz")));
Files.copy(Path.of(transitVehiclesPath), getUniqueTargetPath(Path.of(transitVehiclesPath.split(".xml")[0] + FILE_TYPE + ".gz")));

ConfigUtils.writeConfig(config, configPath);
NetworkUtils.writeNetwork(scenario.getNetwork(), networkPath);
new MatsimVehicleWriter(scenario.getVehicles()).writeFile(vehiclesPath);
new MatsimVehicleWriter(scenario.getTransitVehicles()).writeFile(transitVehiclesPath);
}

if (baseDir != null) {
sw.addDashboard(new PtLineDashboard(baseDir));
}

try {
sw.generate(runDirectory, true);
Expand All @@ -148,9 +167,22 @@ public Integer call() throws Exception {
return 0;
}

public static void main(String[] args) {
new LausitzSimWrapperRunner().execute(args);
private static Path getUniqueTargetPath(Path targetPath) {
int counter = 1;
Path uniquePath = targetPath;

// Add a suffix if the file already exists
while (Files.exists(uniquePath)) {
String originalPath = targetPath.toString();
int dotIndex = originalPath.lastIndexOf(".");
if (dotIndex == -1) {
uniquePath = Path.of(originalPath + "_" + counter);
} else {
uniquePath = Path.of(originalPath.substring(0, dotIndex) + "_" + counter + originalPath.substring(dotIndex));
}
counter++;
}

return uniquePath;
}

}
153 changes: 153 additions & 0 deletions src/main/java/org/matsim/dashboards/PtLineDashboard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package org.matsim.dashboards;

import org.matsim.run.analysis.PtLineAnalysis;
import org.matsim.run.scenarios.LausitzScenario;
import org.matsim.simwrapper.Dashboard;
import org.matsim.simwrapper.Header;
import org.matsim.simwrapper.Layout;
import org.matsim.simwrapper.viz.*;
import tech.tablesaw.plotly.traces.BarTrace;

import java.util.ArrayList;
import java.util.List;

/**
* Shows information about an optional policy case, which implements a pt line between Cottbus and Hoyerswerda.
* It also compares the agents and their trips using the new pt line with their respective trips in the base case.
*/
public class PtLineDashboard implements Dashboard {
private final String basePath;
private static final String SHARE = "share";
private static final String ABSOLUTE = "Count [person]";
private static final String INCOME_GROUP = "incomeGroup";
private static final String DESCRIPTION = "... in base and policy case";

PtLineDashboard(String basePath) {
if (!basePath.endsWith("/")) {
basePath += "/";
}
this.basePath = basePath;
}

@Override
public void configure(Header header, Layout layout) {
header.title = "Pt Line Dashboard";
header.description = "Shows statistics about agents, who used the newly implemented pt line between Cottbus and Hoyerswerda " +
"and compares to the trips of those agents in the base case.";

String[] args = new ArrayList<>(List.of("--base-path", basePath)).toArray(new String[0]);

layout.row("first")
.el(Tile.class, (viz, data) -> {
viz.dataset = data.compute(PtLineAnalysis.class, "mean_travel_stats.csv", args);
viz.height = 0.1;
});

layout.row("income")
.el(Bar.class, (viz, data) -> {
viz.title = "Agents per income group";
viz.stacked = false;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_income_groups.csv", args);
viz.x = INCOME_GROUP;
viz.xAxisName = INCOME_GROUP;
viz.yAxisName = SHARE;
viz.columns = List.of(SHARE);
})
.el(Bar.class, (viz, data) -> {
viz.title = "Agents per income group";
viz.stacked = false;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_income_groups.csv", args);
viz.x = INCOME_GROUP;
viz.xAxisName = INCOME_GROUP;
viz.yAxisName = ABSOLUTE;
viz.columns = List.of(ABSOLUTE);
})
.el(Bar.class, (viz, data) -> {
viz.title = "Mean score per income group";
viz.stacked = false;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_mean_score_per_income_group.csv", args);
viz.x = INCOME_GROUP;
viz.xAxisName = INCOME_GROUP;
viz.yAxisName = "mean score";
viz.columns = List.of("mean_score_base", "mean_score_policy");
});

layout.row("age")
.el(Bar.class, (viz, data) -> {
viz.title = "Agents per age group";
viz.stacked = false;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_age_groups.csv", args);
viz.x = "ageGroup";
viz.xAxisName = "age group";
viz.yAxisName = SHARE;
viz.columns = List.of(SHARE);
})
.el(Bar.class, (viz, data) -> {
viz.title = "Agents per age group";
viz.stacked = false;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_age_groups.csv", args);
viz.x = "ageGroup";
viz.xAxisName = "age group";
viz.yAxisName = ABSOLUTE;
viz.columns = List.of(ABSOLUTE);
});

layout.row("third")
.el(Plotly.class, (viz, data) -> {
viz.title = "Modal split (base case)";
viz.description = "Shows mode of agents in base case, which used the new pt line in the policy case.";

viz.layout = tech.tablesaw.plotly.components.Layout.builder()
.barMode(tech.tablesaw.plotly.components.Layout.BarMode.STACK)
.build();

Plotly.DataSet ds = viz.addDataset(data.compute(PtLineAnalysis.class, "pt_persons_base_modal_share.csv", args))
.constant("source", "Base Case Mode")
.aggregate(List.of("main_mode"), SHARE, Plotly.AggrFunc.SUM);

viz.mergeDatasets = true;
viz.addTrace(BarTrace.builder(Plotly.OBJ_INPUT, Plotly.INPUT).orientation(BarTrace.Orientation.HORIZONTAL).build(),
ds.mapping()
.name("main_mode")
.y("source")
.x(SHARE)
);
})
.el(Hexagons.class, (viz, data) -> {

viz.title = "Pt line agents home locations";
viz.center = data.context().getCenter();
viz.zoom = data.context().mapZoomLevel;
viz.height = 7.5;
viz.width = 2.0;

viz.file = data.compute(PtLineAnalysis.class, "pt_persons_home_locations.csv");
viz.projection = LausitzScenario.CRS;
viz.addAggregation("home locations", "person", "home_x", "home_y");
});

createTableLayouts(layout);
}

private static void createTableLayouts(Layout layout) {
layout.row("fourth")
.el(Table.class, (viz, data) -> {
viz.title = "Executed scores";
viz.description = DESCRIPTION;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_executed_score.csv");
viz.showAllRows = true;
})
.el(Table.class, (viz, data) -> {
viz.title = "Travel times";
viz.description = DESCRIPTION;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_trav_time.csv");
viz.showAllRows = true;
})
.el(Table.class, (viz, data) -> {
viz.title = "Travel distances";
viz.description = DESCRIPTION;
viz.dataset = data.compute(PtLineAnalysis.class, "pt_persons_traveled_distance.csv");
viz.showAllRows = true;
});
}
}
Loading
Loading