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

Emission noise analysis #9

Merged
merged 4 commits into from
Aug 22, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.matsim.simwrapper.Dashboard;
import org.matsim.simwrapper.DashboardProvider;
import org.matsim.simwrapper.SimWrapper;
import org.matsim.simwrapper.dashboard.EmissionsDashboard;
import org.matsim.simwrapper.dashboard.TripDashboard;

import java.util.List;
Expand All @@ -14,12 +15,18 @@
public class LausitzDashboardProvider implements DashboardProvider {
@Override
public List<Dashboard> getDashboards(Config config, SimWrapper simWrapper) {
return List.of(new TripDashboard(

TripDashboard trips = new TripDashboard(
"lausitz_mode_share.csv",
"lausitz_mode_share_per_dist.csv",
"lausitz_mode_users.csv")
.withGroupedRefData("lausitz_mode_share_per_group_dist_ref.csv", "age", "economic_status")
.withDistanceDistribution("lausitz_mode_share_distance_distribution.csv")
.withDistanceDistribution("lausitz_mode_share_distance_distribution.csv");

return List.of(trips,
new EmissionsDashboard()
// 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)
);
}
}
104 changes: 104 additions & 0 deletions src/main/java/org/matsim/dashboards/LausitzSimWrapperRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* *********************************************************************** *
* project: org.matsim.*
* Controler.java
* *
* *********************************************************************** *
* *
* copyright : (C) 2007 by the members listed in the COPYING, *
* LICENSE and WARRANTY file. *
* email : info at matsim dot org *
* *
* *********************************************************************** *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* See also COPYING, LICENSE and WARRANTY file *
* *
* *********************************************************************** */

package org.matsim.dashboards;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.application.ApplicationUtils;
import org.matsim.application.MATSimAppCommand;
import org.matsim.application.options.ShpOptions;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.simwrapper.Dashboard;
import org.matsim.simwrapper.SimWrapper;
import org.matsim.simwrapper.SimWrapperConfigGroup;
import org.matsim.simwrapper.dashboard.NoiseDashboard;
import picocli.CommandLine;

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

@CommandLine.Command(
name = "simwrapper",
description = "Run additional analysis and create SimWrapper dashboard for existing run output."
)
final class LausitzSimWrapperRunner implements MATSimAppCommand {

private static final Logger log = LogManager.getLogger(LausitzSimWrapperRunner.class);

@CommandLine.Parameters(arity = "1..*", description = "Path to run output directories for which dashboards are to be generated.")
private List<Path> inputPaths;

@CommandLine.Mixin
private final ShpOptions shp = new ShpOptions();

@CommandLine.Option(names = "--noise", defaultValue = "false", description = "create noise dashboard")
private boolean noise;


private LausitzSimWrapperRunner(){
}

@Override
public Integer call() throws Exception {

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

for (Path runDirectory : inputPaths) {
log.info("Running on {}", runDirectory);

Path configPath = ApplicationUtils.matchInput("config.xml", runDirectory);
Config config = ConfigUtils.loadConfig(configPath.toString());
SimWrapper sw = SimWrapper.create(config);

SimWrapperConfigGroup simwrapperCfg = ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class);
if (shp.isDefined()){
simwrapperCfg.defaultParams().shp = shp.getShapeFile();
}
//skip default dashboards
simwrapperCfg.defaultDashboards = SimWrapperConfigGroup.Mode.disabled;

//add dashboards according to command line parameters
// TODO: if more dashboards are to be added here, we need to check if noise==true before adding noise dashboard here
sw.addDashboard(Dashboard.customize(new NoiseDashboard()).context("noise"));


try {
sw.generate(runDirectory, true);
sw.run(runDirectory);
} catch (IOException e) {
throw new InterruptedIOException();
}
}

return 0;
}

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

}

}
98 changes: 96 additions & 2 deletions src/main/java/org/matsim/run/LausitzScenario.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import org.matsim.application.prepare.network.CreateNetworkFromSumo;
import org.matsim.application.prepare.population.*;
import org.matsim.application.prepare.pt.CreateTransitScheduleFromGtfs;
import org.matsim.contrib.emissions.HbefaRoadTypeMapping;
import org.matsim.contrib.emissions.HbefaVehicleCategory;
import org.matsim.contrib.emissions.OsmHbefaMapping;
import org.matsim.contrib.emissions.utils.EmissionsConfigGroup;
import org.matsim.contrib.vsp.scenario.SnzActivities;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
Expand All @@ -25,6 +29,7 @@
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule;
import org.matsim.core.router.costcalculators.TravelDisutilityFactory;
import org.matsim.core.router.util.TravelTime;
Expand All @@ -33,6 +38,9 @@
import org.matsim.run.prepare.PreparePopulation;
import org.matsim.simwrapper.SimWrapperConfigGroup;
import org.matsim.simwrapper.SimWrapperModule;
import org.matsim.vehicles.EngineInformation;
import org.matsim.vehicles.VehicleType;
import org.matsim.vehicles.VehicleUtils;
import picocli.CommandLine;
import playground.vsp.pt.fare.DistanceBasedPtFareParams;
import playground.vsp.pt.fare.PtFareConfigGroup;
Expand Down Expand Up @@ -60,10 +68,21 @@ public class LausitzScenario extends MATSimApplication {

public static final String VERSION = "1.1";
private static final String FREIGHT = "freight";
private static final String AVERAGE = "average";

// To decrypt hbefa input files set MATSIM_DECRYPTION_PASSWORD as environment variable. ask VSP for access.
private static final String HBEFA_2020_PATH = "https://svn.vsp.tu-berlin.de/repos/public-svn/3507bb3997e5657ab9da76dbedbb13c9b5991d3e/0e73947443d68f95202b71a156b337f7f71604ae/";
private static final String HBEFA_FILE_COLD_DETAILED = HBEFA_2020_PATH + "82t7b02rc0rji2kmsahfwp933u2rfjlkhfpi2u9r20.enc";
private static final String HBEFA_FILE_WARM_DETAILED = HBEFA_2020_PATH + "944637571c833ddcf1d0dfcccb59838509f397e6.enc";
private static final String HBEFA_FILE_COLD_AVERAGE = HBEFA_2020_PATH + "r9230ru2n209r30u2fn0c9rn20n2rujkhkjhoewt84202.enc" ;
private static final String HBEFA_FILE_WARM_AVERAGE = HBEFA_2020_PATH + "7eff8f308633df1b8ac4d06d05180dd0c5fdf577.enc";

@CommandLine.Mixin
private final SampleOptions sample = new SampleOptions( 100, 25, 10, 1);

@CommandLine.Option(names = "--emissions", defaultValue = "PERFORM_EMISSIONS_ANALYSIS", description = "Define if emission analysis should be performed or not.")
private EmissionAnalysisHandling emissions;


public LausitzScenario(@Nullable Config config) {
super(config);
Expand Down Expand Up @@ -124,7 +143,7 @@ protected Config prepareConfig(Config config) {
config.routing().setAccessEgressType(RoutingConfigGroup.AccessEgressType.accessEgressModeToLink);

prepareCommercialTrafficConfig(config);
// TODO: Config options

// set pt fare calc model to fareZoneBased = fare of vvo tarifzone 20 is paid for trips within fare zone
// every other trip: Deutschlandtarif
// for more info see FareZoneBasedPtFareHandler class in vsp contrib
Expand All @@ -138,8 +157,17 @@ protected Config prepareConfig(Config config) {
throw new RuntimeException(e);
}

// TODO: recreate counts format with car and trucks

if (emissions == EmissionAnalysisHandling.PERFORM_EMISSIONS_ANALYSIS) {
// set hbefa input files for emission analysis
EmissionsConfigGroup eConfig = ConfigUtils.addOrGetModule(config, EmissionsConfigGroup.class);
eConfig.setDetailedColdEmissionFactorsFile(HBEFA_FILE_COLD_DETAILED);
eConfig.setDetailedWarmEmissionFactorsFile(HBEFA_FILE_WARM_DETAILED);
Comment on lines +164 to +165
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you only use AVERAGE, you should be able to run it without the detailed tables.

eConfig.setAverageColdEmissionFactorsFile(HBEFA_FILE_COLD_AVERAGE);
eConfig.setAverageWarmEmissionFactorsFile(HBEFA_FILE_WARM_AVERAGE);
eConfig.setHbefaTableConsistencyCheckingLevel(EmissionsConfigGroup.HbefaTableConsistencyCheckingLevel.consistent);
eConfig.setDetailedVsAverageLookupBehavior(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If only running AVERAGE vehicle types, the LookupBehaviour could be set IMO to directlyAverage (or whatever its name is). Together with just setting the average tables, it makes a bit more clear, that you run an average analysis (which is totally fine!)

}
return config;
}

Expand All @@ -158,6 +186,22 @@ protected void prepareScenario(Scenario scenario) {
link.setAllowedModes(newModes);
}
}

if (emissions == EmissionAnalysisHandling.PERFORM_EMISSIONS_ANALYSIS) {
// do not use VspHbefaRoadTypeMapping() as it results in almost every road to mapped to "highway"!
HbefaRoadTypeMapping roadTypeMapping = OsmHbefaMapping.build();
// the type attribute in our network has the prefix "highway" for all links but pt links.
// we need to delete that because OsmHbefaMapping does not handle that.
for (Link link : scenario.getNetwork().getLinks().values()) {
//pt links can be disregarded
if (!link.getAllowedModes().contains("pt")) {
NetworkUtils.setType(link, NetworkUtils.getType(link).replaceFirst("highway.", ""));
}
}
roadTypeMapping.addHbefaMappings(scenario.getNetwork());
Comment on lines +189 to +201
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As also written directly to Simon: We at VSP should have our current scenarios in a state, that the HBEFA attributes are part of the input network. This is a network property and thus should not depend on the mapping in the analysis script itself.


prepareVehicleTypesForEmissionAnalysis(scenario);
}
}

@Override
Expand Down Expand Up @@ -225,4 +269,54 @@ public static void prepareCommercialTrafficConfig(Config config) {
);
}
}

private static void prepareVehicleTypesForEmissionAnalysis(Scenario scenario) {
for (VehicleType type : scenario.getVehicles().getVehicleTypes().values()) {
EngineInformation engineInformation = type.getEngineInformation();

// only set engine information if none are present
if (engineInformation.getAttributes().isEmpty()) {
switch (type.getId().toString()) {
case TransportMode.car -> {
VehicleUtils.setHbefaVehicleCategory(engineInformation, HbefaVehicleCategory.PASSENGER_CAR.toString());
VehicleUtils.setHbefaTechnology(engineInformation, AVERAGE);
VehicleUtils.setHbefaSizeClass(engineInformation, AVERAGE);
VehicleUtils.setHbefaEmissionsConcept(engineInformation, AVERAGE);
}
case TransportMode.ride -> {
// ignore ride, the mode routed on network, but then teleported
VehicleUtils.setHbefaVehicleCategory(engineInformation, HbefaVehicleCategory.NON_HBEFA_VEHICLE.toString());
VehicleUtils.setHbefaTechnology(engineInformation, AVERAGE);
VehicleUtils.setHbefaSizeClass(engineInformation, AVERAGE);
VehicleUtils.setHbefaEmissionsConcept(engineInformation, AVERAGE);
}
case FREIGHT -> {
VehicleUtils.setHbefaVehicleCategory(engineInformation, HbefaVehicleCategory.HEAVY_GOODS_VEHICLE.toString());
VehicleUtils.setHbefaTechnology(engineInformation, AVERAGE);
VehicleUtils.setHbefaSizeClass(engineInformation, AVERAGE);
VehicleUtils.setHbefaEmissionsConcept(engineInformation, AVERAGE);
}
case TransportMode.bike -> {
// ignore bikes
VehicleUtils.setHbefaVehicleCategory(engineInformation, HbefaVehicleCategory.NON_HBEFA_VEHICLE.toString());
VehicleUtils.setHbefaTechnology(engineInformation, AVERAGE);
VehicleUtils.setHbefaSizeClass(engineInformation, AVERAGE);
VehicleUtils.setHbefaEmissionsConcept(engineInformation, AVERAGE);
}
default -> throw new IllegalArgumentException("does not know how to handle vehicleType " + type.getId().toString());
}
}
}

// ignore all pt veh types
scenario.getTransitVehicles()
.getVehicleTypes()
.values().forEach(type -> VehicleUtils.setHbefaVehicleCategory(type.getEngineInformation(), HbefaVehicleCategory.NON_HBEFA_VEHICLE.toString()));
Comment on lines +274 to +314
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit the same as for the links... should be IMO part of the input. Since this script here only sets average values, if no value is set, I do not know if the input has the engineInformation set correctly or not.

Maybe also make a bit more clear that you set here everything to average.

}

/**
* Defines if all necessary configs for emissions analysis should be made
* and hence if emissions analysis is performed or not (will fail without configs).
*/
enum EmissionAnalysisHandling {PERFORM_EMISSIONS_ANALYSIS, DO_NOT_PERFORM_EMISSIONS_ANALYSIS}
}
Loading
Loading