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

Matsim 15 #186

Merged
merged 7 commits into from
Dec 16, 2023
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
@@ -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