Skip to content

Commit

Permalink
Matsim 15 (#186)
Browse files Browse the repository at this point in the history
* update IdF emission to matsim 15

* update log4j import

* make sure Osm mapping is used on osm:way:highway tag

* add matsim-examples to pom to get hbefa-41 sample for emissions tests

* make the desired pollutant list defined in the commandline

* test the emissions part
  • Loading branch information
Nitnelav authored Dec 16, 2023
1 parent 919b699 commit 8a409f8
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.eqasim.core.tools;

import org.apache.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Identifiable;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.population.Activity;
Expand All @@ -16,7 +17,7 @@

public class RemovePersonsWithActivityTypes {

private static final Logger logger = Logger.getLogger(RemovePersonsWithActivityTypes.class);
private static final Logger logger = LogManager.getLogger(RemovePersonsWithActivityTypes.class);

public static void main(String[] args) throws CommandLine.ConfigurationException {
CommandLine commandLine = new CommandLine.Builder(args).requireOptions("input-path", "output-path", "activity-types").build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.eqasim.ile_de_france.emissions;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.eqasim.ile_de_france.IDFConfigurator;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.emissions.EmissionModule;
import org.matsim.contrib.emissions.OsmHbefaMapping;
Expand All @@ -17,6 +19,7 @@
import org.matsim.core.events.EventsUtils;
import org.matsim.core.events.MatsimEventsReader;
import org.matsim.core.events.algorithms.EventWriterXML;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.scenario.ScenarioUtils;

public class RunComputeEmissionsEvents {
Expand Down Expand Up @@ -53,6 +56,26 @@ public static void main(String[] args) throws CommandLine.ConfigurationException

OsmHbefaMapping osmHbefaMapping = OsmHbefaMapping.build();
Network network = scenario.getNetwork();
// if the network is from pt2matsim it might not have "type" but "osm:way:highway" attribute instead
for (Link link: network.getLinks().values()) {
String roadTypeAttribute = NetworkUtils.getType(link);
String osmRoadTypeAttribute = (String) link.getAttributes().getAttribute("osm:way:highway");
if (StringUtils.isBlank(roadTypeAttribute)) {
if (!StringUtils.isBlank(osmRoadTypeAttribute)) {
NetworkUtils.setType(link, osmRoadTypeAttribute);
}
else { // not a road (railway for example)
NetworkUtils.setType(link, "unclassified");
}
}
// '_link' types are not defined in the OSM mapping, set t undefined
if (NetworkUtils.getType(link).contains("_link")) {
NetworkUtils.setType(link, "unclassified");
}
if (NetworkUtils.getType(link).equals("living_street")) {
NetworkUtils.setType(link, "living");
}
}
osmHbefaMapping.addHbefaMappings(network);

EventsManager eventsManager = EventsUtils.createEventsManager();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static void main(String[] args) throws CommandLine.ConfigurationException
CommandLine cmd = new CommandLine.Builder(args) //
.requireOptions("config-path") //
.allowOptions("time-bin-size")
.allowOptions("pollutants")
.build();

ConfigGroup[] configGroups = ArrayUtils.addAll(new IDFConfigurator().getConfigGroups(), new EmissionsConfigGroup());
Expand All @@ -44,6 +45,8 @@ public static void main(String[] args) throws CommandLine.ConfigurationException

int timeBinSize = Integer.parseInt(cmd.getOption("time-bin-size").orElse("3600"));

String[] wanted_pollutants = cmd.getOption("pollutants").orElse("PM,CO,NOx").split(",");

EventsManager eventsManager = EventsUtils.createEventsManager();
EmissionsOnLinkEventHandler handler = new EmissionsOnLinkEventHandler(timeBinSize);

Expand All @@ -59,19 +62,14 @@ public static void main(String[] args) throws CommandLine.ConfigurationException
Map<Id<Link>, ? extends Link> links = network.getLinks();
TimeBinMap<Map<Id<Link>, EmissionsByPollutant>> res = handler.getTimeBins();
Collection<SimpleFeature> features = new LinkedList<>();

PolylineFeatureFactory linkFactory = new PolylineFeatureFactory.Builder() //
PolylineFeatureFactory.Builder builder = new PolylineFeatureFactory.Builder() //
.setCrs(MGC.getCRS("epsg:2154")).setName("Emissions") //
.addAttribute("link", String.class) //
.addAttribute("time", Integer.class) //
.addAttribute("PM", Double.class) //
.addAttribute("FC", Double.class) //
.addAttribute("CO", Double.class) //
.addAttribute("FC_MJ", Double.class) //
.addAttribute("HC", Double.class) //
.addAttribute("NOx", Double.class) //
.addAttribute("CO2_rep", Double.class) //
.create();
.addAttribute("time", Integer.class);
for (String pollutant: wanted_pollutants) {
builder.addAttribute(pollutant, Double.class);
}
PolylineFeatureFactory linkFactory = builder.create();

for (TimeBinMap.TimeBin<Map<Id<Link>, EmissionsByPollutant>> timeBin : res.getTimeBins()) {
int startTime = (int) timeBin.getStartTime();
Expand All @@ -90,8 +88,15 @@ public static void main(String[] args) throws CommandLine.ConfigurationException
attributes.add(startTime);
EmissionsByPollutant emissions = entry.getValue();
Map<Pollutant, Double> pollutants = emissions.getEmissions();
for (Map.Entry<Pollutant, Double> pollutant : pollutants.entrySet()) {
attributes.add(pollutant.getValue());
for (String pollutant: wanted_pollutants) {
try {
Pollutant pollutant_key = Pollutant.valueOf(pollutant);
attributes.add(pollutants.getOrDefault(pollutant_key, Double.NaN));
}
catch (IllegalArgumentException e) {
attributes.add(Double.NaN);
}

}

SimpleFeature feature = linkFactory.createPolyline( //
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package org.eqasim.ile_de_france;

import org.apache.commons.io.FileUtils;
import org.eqasim.core.simulation.EqasimConfigurator;
import org.eqasim.core.simulation.analysis.EqasimAnalysisModule;
import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension;
import org.eqasim.core.simulation.mode_choice.EqasimModeChoiceModule;
import org.eqasim.core.simulation.mode_choice.parameters.ModeParameters;
import org.eqasim.ile_de_france.emissions.RunComputeEmissionsEvents;
import org.eqasim.ile_de_france.emissions.RunExportEmissionsNetwork;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.config.CommandLine;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ControlerConfigGroup;
import org.matsim.core.config.groups.QSimConfigGroup;
import org.matsim.core.controler.Controler;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.gis.ShapeFileReader;
import org.matsim.examples.ExamplesUtils;
import org.matsim.utils.objectattributes.attributable.Attributes;
import org.matsim.vehicles.*;
import org.opengis.feature.simple.SimpleFeature;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class TestEmissions {

@Before
public void setUp() throws IOException {
URL fixtureUrl = getClass().getResource("/melun");
FileUtils.copyDirectory(new File(fixtureUrl.getPath()), new File("melun_test/input"));
var coldAverageFile = "sample_41_EFA_ColdStart_vehcat_2020average.csv";
var coldDetailedFile = "sample_41_EFA_ColdStart_SubSegm_2020detailed.csv";
var hotAverageFile = "sample_41_EFA_HOT_vehcat_2020average.csv";
var hotDetailedFile = "sample_41_EFA_HOT_SubSegm_2020detailed.csv";
for (String file: new String[]{ coldAverageFile, coldDetailedFile, hotAverageFile, hotDetailedFile}) {
Files.copy(ExamplesUtils.class.getResourceAsStream("/test/scenarios/emissions-sampleScenario/" + file),
Paths.get("melun_test/input/", file),
REPLACE_EXISTING);
}
}

@After
public void tearDown() throws IOException {
FileUtils.deleteDirectory(new File("melun_test"));
}

private void runMelunSimulation() {
EqasimConfigurator eqasimConfigurator = new EqasimConfigurator();
Config config = ConfigUtils.loadConfig("melun_test/input/config_emissions.xml", eqasimConfigurator.getConfigGroups());
((ControlerConfigGroup) config.getModules().get(ControlerConfigGroup.GROUP_NAME)).setOutputDirectory("melun_test/output");

Scenario scenario = ScenarioUtils.createScenario(config);
eqasimConfigurator.configureScenario(scenario);
ScenarioUtils.loadScenario(scenario);
eqasimConfigurator.adjustScenario(scenario);


Controler controller = new Controler(scenario);
eqasimConfigurator.configureController(controller);
controller.addOverridingModule(new EqasimModeChoiceModule());
controller.addOverridingModule(new EqasimAnalysisModule());
controller.addOverridingModule(new AbstractEqasimExtension() {
@Override
protected void installEqasimExtension() {
bind(ModeParameters.class);
bindModeAvailability("DefaultModeAvailability").toProvider(() -> (person, trips) -> {
Set<String> modes = new HashSet<>();
modes.add(TransportMode.walk);
modes.add(TransportMode.pt);
modes.add(TransportMode.car);
modes.add(TransportMode.bike);
// Add special mode "car_passenger" if applicable
Boolean isCarPassenger = (Boolean) person.getAttributes().getAttribute("isPassenger");
if(isCarPassenger) {
modes.add("car_passenger");
}
return modes;
}).asEagerSingleton();
}
});
controller.run();
}

private void runCreateVehicles() {
VehicleType testCarType = VehicleUtils.createVehicleType(Id.create("test_car", VehicleType.class));
testCarType.setLength(7.5);
testCarType.setWidth(1.);
testCarType.setNetworkMode("car");
Attributes hbefa_attributes = testCarType.getEngineInformation().getAttributes();
hbefa_attributes.putAttribute("HbefaVehicleCategory", "PASSENGER_CAR");
hbefa_attributes.putAttribute("HbefaTechnology", "diesel");
hbefa_attributes.putAttribute("HbefaSizeClass", "&lt;1,4L");
hbefa_attributes.putAttribute("HbefaEmissionsConcept", "PC diesel Euro-3 (DPF)");

Vehicles vehicles = VehicleUtils.createVehiclesContainer();
vehicles.addVehicleType(testCarType);

EqasimConfigurator eqasimConfigurator = new EqasimConfigurator();
Config config = ConfigUtils.loadConfig("melun_test/input/config.xml", eqasimConfigurator.getConfigGroups());
Scenario scenario = ScenarioUtils.loadScenario(config);
for (Person person: scenario.getPopulation().getPersons().values()) {
Vehicle vehicle = VehicleUtils.createVehicle(
Id.createVehicleId(person.getId().toString()),
testCarType);
vehicles.addVehicle(vehicle);
}

MatsimVehicleWriter writer = new MatsimVehicleWriter(vehicles);
writer.writeFile("melun_test/input/vehicles.xml");
}

private void runModifyConfig() {
Config config = ConfigUtils.loadConfig("melun_test/input/config.xml");
config.controler().setOutputDirectory("melun_test/output");
config.qsim().setVehiclesSource(QSimConfigGroup.VehiclesSource.fromVehiclesData);
config.vehicles().setVehiclesFile("vehicles.xml");
ConfigUtils.writeConfig(config, "melun_test/input/config_emissions.xml");
}

private void runModifyNetwork() {
Config config = ConfigUtils.loadConfig("melun_test/input/config.xml");
Scenario scenario = ScenarioUtils.loadScenario(config);
Network network = scenario.getNetwork();
for (Link link: network.getLinks().values()) {
// this forces the OSM Mapping code to use URB/Local/50 as it the only thing we have in the sample HBEFA.
NetworkUtils.setType(link, "tertiary");
link.getAttributes().putAttribute(NetworkUtils.ALLOWED_SPEED, 50 / 3.6);
}
NetworkUtils.writeNetwork(network, "melun_test/input/network.xml.gz");
}

private void runMelunEmissions() throws CommandLine.ConfigurationException {
RunComputeEmissionsEvents.main(new String[] {
"--config-path", "melun_test/input/config_emissions.xml",
"--hbefa-cold-avg", "sample_41_EFA_ColdStart_vehcat_2020average.csv",
"--hbefa-hot-avg", "sample_41_EFA_HOT_vehcat_2020average.csv",
"--hbefa-cold-detailed", "sample_41_EFA_ColdStart_SubSegm_2020detailed.csv",
"--hbefa-hot-detailed", "sample_41_EFA_HOT_SubSegm_2020detailed.csv",
});

RunExportEmissionsNetwork.main(new String[] {
"--config-path", "melun_test/input/config_emissions.xml",
"--pollutants", "PM,CO,NOx,Unknown",
"--time-bin-size", "3600"
});

Collection<SimpleFeature> features = ShapeFileReader.getAllFeatures("melun_test/output/emissions_network.shp");
assert features.size() == 32999;
SimpleFeature feature = features.stream().filter(f ->
f.getAttribute("link").toString().equals("163994")
& f.getAttribute("time").toString().equals("43200")
).findFirst().orElse(null);
assert feature != null;
assert feature.getAttribute("PM").equals(0.006847378350421);
assert feature.getAttribute("CO").equals(0.456258730331835);
assert feature.getAttribute("NOx").equals(0.477558671071797);
assert feature.getAttribute("Unknown").equals(Double.NaN);

// TODO : test RunComputeEmissionsGrid
}

@Test
public void runTestEmissions() throws CommandLine.ConfigurationException {
runCreateVehicles();
runModifyConfig();
runModifyNetwork();
runMelunSimulation();
runMelunEmissions();
}

}
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@
<version>${matsim.version}</version>
</dependency>

<dependency>
<groupId>org.matsim</groupId>
<artifactId>matsim-examples</artifactId>
<version>${matsim.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down

0 comments on commit 8a409f8

Please sign in to comment.