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

Two new tools and extending an existing one #187

Merged
merged 4 commits into from
Dec 19, 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
@@ -0,0 +1,92 @@
package org.eqasim.core.tools;

import org.locationtech.jts.geom.Coordinate;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.api.core.v01.population.Population;
import org.matsim.core.config.CommandLine;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.population.io.PopulationReader;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.geometry.geotools.MGC;
import org.matsim.core.utils.gis.PointFeatureFactory;
import org.matsim.core.utils.gis.ShapeFileWriter;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.util.*;
import java.util.stream.Collectors;

public class ExportActivitiesToShapefile {

public static void exportActivitiesToShapeFile(Population population, String crsString, Set<String> ignoredActivityTypesSet, String outputPath) {

CoordinateReferenceSystem crs = MGC.getCRS(crsString);

PointFeatureFactory pointFactory = new PointFeatureFactory.Builder() //
.setCrs(crs).setName("id") //
.addAttribute("personId", String.class)
.addAttribute("activityIndex", Integer.class)
.addAttribute("type", String.class)//
.addAttribute("linkId", String.class)
.addAttribute("facilityId", String.class)
.addAttribute("startTime", Double.class)
.addAttribute("endTime", Double.class)//
.create();

Collection<SimpleFeature> features = new LinkedList<>();

for(Person person: population.getPersons().values()) {
if(person.getSelectedPlan() == null) {
continue;
}
int activityIndex = -1;
for(PlanElement planElement: person.getSelectedPlan().getPlanElements()) {
if (!(planElement instanceof Activity)) {
continue;
}
Activity a = (Activity) planElement;
activityIndex++;
if(ignoredActivityTypesSet.contains(a.getType())) {
continue;
}
Coordinate coordinate = new Coordinate(a.getCoord().getX(), a.getCoord().getY());
SimpleFeature feature = pointFactory.createPoint(coordinate,
new Object[] {
person.getId().toString(),
activityIndex,
a.getType(),
a.getLinkId().toString(),
a.getFacilityId() == null ? null : a.getFacilityId().toString(),
a.getStartTime().orElse(Double.NaN),
a.getEndTime().orElse(Double.NaN)
},
null);
features.add(feature);
}
}
ShapeFileWriter.writeGeometries(features, outputPath);
}


public static void main(String[] args) throws CommandLine.ConfigurationException {
CommandLine commandLine = new CommandLine.Builder(args).requireOptions("plans-path", "output-path", "crs")
.allowOptions("ignored-activity-types").build();

String plansPath = commandLine.getOptionStrict("plans-path");
String outputPath = commandLine.getOptionStrict("output-path");
String crs = commandLine.getOptionStrict("crs");
Set<String> ignoredActivityTypes = Arrays.stream(commandLine.getOption("ignored-activity-types").orElse("").split(","))
.map(String::trim)
.filter(s -> s.length()>0)
.collect(Collectors.toSet());

Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig());
PopulationReader populationReader = new PopulationReader(scenario);
populationReader.readFile(plansPath);

exportActivitiesToShapeFile(scenario.getPopulation(), crs, ignoredActivityTypes, outputPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.eqasim.core.tools;

import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Population;
import org.matsim.core.config.CommandLine;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.population.io.PopulationReader;
import org.matsim.core.scenario.ScenarioUtils;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

public class ExportPopulationToCSV {

public static final String[] IGNORED_ATTRIBUTES = new String[]{"vehicles"};

public static void exportPopulationToCSV(Population population, String filePath) {

List<String> ignoredAttributes = List.of(IGNORED_ATTRIBUTES);

List<String> attributes = population.getPersons().values().stream()
.flatMap(p -> p.getAttributes().getAsMap().keySet().stream())
.distinct()
.filter(attribute -> !ignoredAttributes.contains(attribute))
.collect(Collectors.toList());

String[] header = new String[attributes.size()+1];
header[0] = "person_id";
for(int i=0; i<attributes.size(); i++) {
header[i+1] = attributes.get(i);
}

try {
FileWriter fileWriter = new FileWriter(filePath);
fileWriter.write(String.join(";", header) + "\n");
for(Person person: population.getPersons().values()) {
String[] line = new String[attributes.size()+1];
line[0] = person.getId().toString();
for(int i=0; i<attributes.size(); i++) {
line[i+1] = String.valueOf(person.getAttributes().getAsMap().getOrDefault(attributes.get(i), null));
}
fileWriter.write(String.join(";", line) + "\n");
}
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}


public static void main(String[] args) throws CommandLine.ConfigurationException {
CommandLine commandLine = new CommandLine.Builder(args).requireOptions("plans-path", "output-path").build();

String plansPath = commandLine.getOptionStrict("plans-path");
Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig());

new PopulationReader(scenario).readFile(plansPath);

exportPopulationToCSV(scenario.getPopulation(), commandLine.getOptionStrict("output-path"));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.eqasim.core.tools;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.BooleanUtils;
import org.locationtech.jts.geom.Coordinate;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.IdSet;
import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
Expand All @@ -27,11 +28,19 @@
public class ExportTransitLinesToShapefile {
public static void main(String[] args) throws Exception {
CommandLine cmd = new CommandLine.Builder(args) //
.requireOptions("schedule-path", "network-path", "output-path", "crs") //
.requireOptions("schedule-path", "network-path", "output-path", "crs")
.allowOptions("modes", "transit-lines", "transit-routes")
.build();

String schedulePath = cmd.getOptionStrict("schedule-path");
String networkPath = cmd.getOptionStrict("network-path");
Optional<String> modesOption = cmd.getOption("modes");
Optional<String> transitLinesOption = cmd.getOption("transit-lines");
Optional<String> transitRoutesOption = cmd.getOption("transit-routes");

if(BooleanUtils.toInteger(modesOption.isPresent()) + BooleanUtils.toInteger(transitLinesOption.isPresent()) + BooleanUtils.toInteger(transitRoutesOption.isPresent()) > 1) {
throw new IllegalStateException("Only one of the options 'modes', 'transit-lines' and 'transit-routes' can be used");
}

Config config = ConfigUtils.createConfig();
Scenario scenario = ScenarioUtils.createScenario(config);
Expand All @@ -45,14 +54,34 @@ public static void main(String[] args) throws Exception {
PolylineFeatureFactory linkFactory = new PolylineFeatureFactory.Builder() //
.setCrs(crs).setName("line") //
.addAttribute("line_id", String.class) //
.addAttribute("line_name", String.class)//
.addAttribute("route_id", String.class) //
.addAttribute("mode", String.class) //
.create();

Network network = scenario.getNetwork();

Set<String> modes = new HashSet<>();
IdSet<TransitLine> transitLineIdSet = new IdSet<>(TransitLine.class);
IdSet<TransitRoute> transitRouteIdSet = new IdSet<>(TransitRoute.class);

transitLinesOption.ifPresent(value -> Arrays.stream(value.split(",")).map(String::trim).map(s -> Id.create(s, TransitLine.class)).forEach(transitLineIdSet::add));
transitRoutesOption.ifPresent(value -> Arrays.stream(value.split(",")).map(String::trim).map(s -> Id.create(s, TransitRoute.class)).forEach(transitRouteIdSet::add));
if(modesOption.isPresent()) {
modes = Arrays.stream(modesOption.get().split(",")).map(String::trim).collect(Collectors.toSet());
}

for (TransitLine transitLine : scenario.getTransitSchedule().getTransitLines().values()) {
if(transitLineIdSet.size() > 0 && !transitLineIdSet.contains(transitLine.getId())) {
continue;
}
for (TransitRoute transitRoute : transitLine.getRoutes().values()) {
if(transitRouteIdSet.size() > 0 && !transitRouteIdSet.contains(transitRoute.getId())) {
continue;
}
if(modes.size() > 0 && !modes.contains(transitRoute.getTransportMode())) {
continue;
}
NetworkRoute networkRoute = transitRoute.getRoute();
List<Link> links = new ArrayList<>(networkRoute.getLinkIds().size() + 2);
links.add(network.getLinks().get(networkRoute.getStartLinkId()));
Expand All @@ -76,9 +105,10 @@ public static void main(String[] args) throws Exception {
SimpleFeature feature = linkFactory.createPolyline( //
coordinates, //
new Object[] { //
transitLine.getId().toString(), //
transitLine.getId().toString(),
transitLine.getName(),//
transitRoute.getId().toString(), //
transitRoute.getTransportMode() //
transitRoute.getTransportMode(),//
}, null);

features.add(feature);
Expand Down
51 changes: 42 additions & 9 deletions core/src/test/java/org/eqasim/TestSimulationPipeline.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
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.core.tools.ExportNetworkToShapefile;
import org.eqasim.core.tools.ExportTransitLinesToShapefile;
import org.eqasim.core.tools.ExportTransitStopsToShapefile;
import org.eqasim.core.tools.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -37,7 +35,7 @@ public class TestSimulationPipeline {
public void setUp() throws IOException {
URL fixtureUrl = getClass().getClassLoader().getResource("melun");
FileUtils.copyDirectory(new File(fixtureUrl.getPath()), new File("melun_test/input"));
FileUtils.forceMkdir(new File("melun_test/shp"));
FileUtils.forceMkdir(new File("melun_test/exports"));
}

@After
Expand Down Expand Up @@ -109,31 +107,66 @@ private void runAnalyses() throws CommandLine.ConfigurationException, IOExceptio
assert CRCChecksum.getCRCFromFile("melun_test/output/eqasim_pt.csv") == CRCChecksum.getCRCFromFile("melun_test/output/eqasim_pt_post_sim.csv");
}

private void runShapefileExports() throws Exception {
private void runExports() throws Exception {
ExportTransitLinesToShapefile.main(new String[] {
"--schedule-path", "melun_test/input/transit_schedule.xml.gz",
"--network-path", "melun_test/input/network.xml.gz",
"--crs", "EPSG:2154",
"--output-path", "melun_test/shp/lines.shp"
"--output-path", "melun_test/exports/lines.shp"
});

ExportTransitLinesToShapefile.main(new String[] {
"--schedule-path", "melun_test/input/transit_schedule.xml.gz",
"--network-path", "melun_test/input/network.xml.gz",
"--crs", "EPSG:2154",
"--modes", "rail",
"--output-path", "melun_test/exports/lines_rail.shp"
});

ExportTransitLinesToShapefile.main(new String[] {
"--schedule-path", "melun_test/input/transit_schedule.xml.gz",
"--network-path", "melun_test/input/network.xml.gz",
"--crs", "EPSG:2154",
"--transit-lines", "IDFM:C02364,IDFM:C00879",
"--output-path", "melun_test/exports/lines_line_ids.shp"
});

ExportTransitLinesToShapefile.main(new String[] {
"--schedule-path", "melun_test/input/transit_schedule.xml.gz",
"--network-path", "melun_test/input/network.xml.gz",
"--crs", "EPSG:2154",
"--transit-routes", "IDFM:TRANSDEV_AMV:27719-C00637-14017001,IDFM:SNCF:42048-C01728-9e8c577f-7ff9-4fe7-93e7-3c3854aa5ecf",
"--output-path", "melun_test/exports/lines_route_ids.shp"
});

ExportTransitStopsToShapefile.main(new String[] {
"--schedule-path", "melun_test/input/transit_schedule.xml.gz",
"--crs", "EPSG:2154",
"--output-path", "melun_test/shp/stops.shp"
"--output-path", "melun_test/exports/stops.shp"
});

ExportNetworkToShapefile.main(new String[] {
"--network-path", "melun_test/input/network.xml.gz",
"--crs", "EPSG:2154",
"--output-path", "melun_test/shp/network.shp"
"--output-path", "melun_test/exports/network.shp"
});

ExportActivitiesToShapefile.main(new String[]{
"--plans-path", "melun_test/input/population.xml.gz",
"--output-path", "melun_test/exports/activities.shp",
"--crs", "EPSG:2154"
});

ExportPopulationToCSV.main(new String[]{
"--plans-path", "melun_test/input/population.xml.gz",
"--output-path", "melun_test/exports/persons.csv"
});
}

@Test
public void testPipeline() throws Exception {
runMelunSimulation();
runAnalyses();
runShapefileExports();
runExports();
}
}
Loading