Skip to content

Commit

Permalink
setup emission analysis correctly + test class
Browse files Browse the repository at this point in the history
  • Loading branch information
simei94 committed Aug 21, 2024
1 parent 3986b35 commit fff091d
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 1 deletion.
100 changes: 99 additions & 1 deletion 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,6 +157,19 @@ protected Config prepareConfig(Config config) {
throw new RuntimeException(e);
}


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);
eConfig.setAverageColdEmissionFactorsFile(HBEFA_FILE_COLD_AVERAGE);
eConfig.setAverageWarmEmissionFactorsFile(HBEFA_FILE_WARM_AVERAGE);
eConfig.setHbefaTableConsistencyCheckingLevel(EmissionsConfigGroup.HbefaTableConsistencyCheckingLevel.consistent);
eConfig.setDetailedVsAverageLookupBehavior(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable);
}


// TODO: recreate counts format with car and trucks

return config;
Expand All @@ -158,6 +190,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());

prepareVehicleTypesForEmissionAnalysis(scenario);
}
}

@Override
Expand Down Expand Up @@ -225,4 +273,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()));
}

/**
* 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}
}
115 changes: 115 additions & 0 deletions src/test/java/org/matsim/run/EmissionAnalysisOutputTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package org.matsim.run;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.population.*;
import org.matsim.application.MATSimApplication;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.population.PersonUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.testcases.MatsimTestUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import static org.matsim.application.ApplicationUtils.globFile;

class EmissionAnalysisOutputTest {

@RegisterExtension
public MatsimTestUtils utils = new MatsimTestUtils();

@TempDir
public Path p;

private final static Id<Person> ptPersonId = Id.createPersonId("Hoyerswerda-Cottbus_CAR");

@Test
void runEmissionAnalysisOutputTest() throws IOException {
Config config = ConfigUtils.loadConfig(String.format("input/v%s/lausitz-v%s-10pct.config.xml", LausitzScenario.VERSION, LausitzScenario.VERSION));

Path inputPath = p.resolve("emissions-test-population.xml.gz");

Population population = PopulationUtils.createPopulation(config);
PopulationFactory fac = population.getFactory();
Person person = fac.createPerson(ptPersonId);
Plan plan = PopulationUtils.createPlan(person);

// home in hoyerswerda, nearest link 28922425#0
Activity home = fac.createActivityFromCoord("home_2400", new Coord(863538.13,5711028.24));
home.setEndTime(8 * 3600);
Activity home2 = fac.createActivityFromCoord("home_2400", new Coord(863538.13,5711028.24));
home2.setEndTime(19 * 3600);
// work in hoyerswerda, nearest link(s): 686055693#1, -686055693#1
Activity work = fac.createActivityFromCoord("work_2400", new Coord(863866.47,5710961.86));
work.setEndTime(17 * 3600 + 25 * 60);

Leg leg = fac.createLeg(TransportMode.car);

plan.addActivity(home);
plan.addLeg(leg);
plan.addActivity(work);
plan.addLeg(leg);
plan.addActivity(home2);

person.addPlan(plan);
PersonUtils.setIncome(person, 1000.);
person.getAttributes().putAttribute("subpopulation", "person");
population.addPerson(person);

new PopulationWriter(population).write(inputPath.toString());

assert MATSimApplication.execute(LausitzScenario.class, config,
"--1pct",
"--iterations", "0",
"--output", utils.getOutputDirectory(),
"--config:plans.inputPlansFile", inputPath.toString(),
"--config:controller.overwriteFiles=deleteDirectoryIfExists") == 0 : "Must return non error code";


Path csvPath = globFile(Path.of(utils.getOutputDirectory() + "/analysis/emissions"), "*emissions_per_link.csv*");

Map<String, Double[]> nonZeroLinks = new HashMap<>();

try {
BufferedReader reader = IOUtils.getBufferedReader(csvPath.toUri().toURL());
String line;

// skip header
reader.readLine();

while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");

// if first value (CO) is zero, all others are too
if (Double.parseDouble(parts[1]) == 0.) {
continue;
}

Double[] values = new Double[23];

for (int i = 1; i < parts.length; i++) {
values[i - 1] = Double.parseDouble(parts[i]);
}

nonZeroLinks.put(parts[0], values);
}
} finally {

}

Assertions.assertFalse(nonZeroLinks.isEmpty());
Assertions.assertTrue(nonZeroLinks.containsKey("28922425#0"));
Assertions.assertTrue(nonZeroLinks.containsKey("-686055693#1"));
}
}

0 comments on commit fff091d

Please sign in to comment.