From 876852dc2ff03bb5d8556eab60c375d5a2dff898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Wed, 17 Jul 2024 12:21:39 +0200 Subject: [PATCH] feat: script to export link traversals --- .../core/tools/ExportLinkTraversals.java | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 core/src/main/java/org/eqasim/core/tools/ExportLinkTraversals.java diff --git a/core/src/main/java/org/eqasim/core/tools/ExportLinkTraversals.java b/core/src/main/java/org/eqasim/core/tools/ExportLinkTraversals.java new file mode 100644 index 000000000..ec355631e --- /dev/null +++ b/core/src/main/java/org/eqasim/core/tools/ExportLinkTraversals.java @@ -0,0 +1,162 @@ +package org.eqasim.core.tools; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Arrays; +import java.util.Optional; + +import org.eqasim.core.scenario.cutter.extent.ScenarioExtent; +import org.eqasim.core.scenario.cutter.extent.ShapeScenarioExtent; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; +import org.matsim.api.core.v01.events.LinkEnterEvent; +import org.matsim.api.core.v01.events.LinkLeaveEvent; +import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; +import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; +import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler; +import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler; +import org.matsim.api.core.v01.events.handler.VehicleEntersTrafficEventHandler; +import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; +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.api.experimental.events.EventsManager; +import org.matsim.core.config.CommandLine; +import org.matsim.core.config.CommandLine.ConfigurationException; +import org.matsim.core.events.EventsUtils; +import org.matsim.core.events.MatsimEventsReader; +import org.matsim.core.network.NetworkUtils; +import org.matsim.core.network.io.MatsimNetworkReader; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.vehicles.Vehicle; + +import com.google.common.base.Verify; + +public class ExportLinkTraversals { + static public void main(String[] args) throws ConfigurationException, MalformedURLException, IOException { + CommandLine cmd = new CommandLine.Builder(args) // + .requireOptions("events-path", "output-path") // + .allowOptions("network-path", "extent-path") // + .build(); + + ScenarioExtent extent = null; + Network network = null; + + if (cmd.hasOption("extent-path")) { + Verify.verify(cmd.hasOption("network-path"), "Network path must be given"); + + network = NetworkUtils.createNetwork(); + new MatsimNetworkReader(network).readFile(cmd.getOptionStrict("network-path")); + + extent = new ShapeScenarioExtent.Builder(new File(cmd.getOptionStrict("extent-path")), Optional.empty(), + Optional.empty()).build(); + } + + BufferedWriter writer = IOUtils.getBufferedWriter(cmd.getOptionStrict("output-path")); + + EventsManager eventsManager = EventsUtils.createEventsManager(); + eventsManager.addHandler(new TraversalExporter(writer, extent, network)); + new MatsimEventsReader(eventsManager).readFile(cmd.getOptionStrict("events-path")); + + writer.close(); + } + + private static class TraversalExporter implements VehicleEntersTrafficEventHandler, + VehicleLeavesTrafficEventHandler, LinkEnterEventHandler, LinkLeaveEventHandler { + private final BufferedWriter writer; + private final ScenarioExtent extent; + private final Network network; + + private final IdMap> drivers = new IdMap<>(Vehicle.class); + private final IdMap enterEvents = new IdMap<>(Person.class); + + TraversalExporter(BufferedWriter writer, ScenarioExtent extent, Network network) { + this.writer = writer; + this.extent = extent; + this.network = network; + + try { + writer.write(String.join(";", Arrays.asList( // + "person_id", "vehicle_id", "link_id", "enter_time", "leave_time")) + "\n"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void handleEvent(VehicleEntersTrafficEvent event) { + if (event.getNetworkMode().equals("car")) { + drivers.put(event.getVehicleId(), event.getPersonId()); + } + } + + @Override + public void handleEvent(VehicleLeavesTrafficEvent event) { + if (drivers.remove(event.getVehicleId()) != null) { + writeTraversal(event.getPersonId(), enterEvents.remove(event.getPersonId()), null); + } + } + + @Override + public void handleEvent(LinkEnterEvent event) { + Id personId = drivers.get(event.getVehicleId()); + + if (personId != null) { + enterEvents.put(personId, event); + } + } + + @Override + public void handleEvent(LinkLeaveEvent event) { + Id personId = drivers.get(event.getVehicleId()); + + if (personId != null) { + // enter event can be null (first leave event on trip) + writeTraversal(personId, enterEvents.remove(personId), event); + } + } + + private void writeTraversal(Id personId, LinkEnterEvent enterEvent, LinkLeaveEvent leaveEvent) { + final Id vehicleId; + final Id linkId; + + if (enterEvent != null) { + vehicleId = enterEvent.getVehicleId(); + linkId = enterEvent.getLinkId(); + } else if (leaveEvent != null) { + vehicleId = leaveEvent.getVehicleId(); + linkId = leaveEvent.getLinkId(); + } else { + return; // no actual driving happened + } + + final double enterTime = enterEvent != null ? enterEvent.getTime() : Double.NaN; + final double leaveTime = leaveEvent != null ? leaveEvent.getTime() : Double.NaN; + + if (extent != null) { + Link link = network.getLinks().get(linkId); + Coord fromCoord = link.getFromNode().getCoord(); + Coord toCoord = link.getToNode().getCoord(); + + if (!extent.isInside(fromCoord) && !extent.isInside(toCoord)) { + return; // ignore this one as it doesn't touch the requested extent + } + } + + try { + writer.write(String.join(";", new String[] { // + personId.toString(), // + vehicleId.toString(), // + linkId.toString(), // + String.valueOf(enterTime), // + String.valueOf(leaveTime) // + }) + "\n"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +}