From afc50ff2d12e3dce2e00872c7ff23521c52a7106 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Sat, 12 Oct 2024 01:38:15 +0200 Subject: [PATCH 01/11] modify schedule to run CircleLine endless --- .../EndlessCircleLineScheduleModifier.java | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java new file mode 100644 index 00000000..a237f613 --- /dev/null +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -0,0 +1,161 @@ +package org.matsim.prepare.transit; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.population.routes.NetworkRoute; +import org.matsim.core.population.routes.RouteUtils; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.pt.transitSchedule.api.*; + +import java.util.*; + +public class EndlessCircleLineScheduleModifier { + private final static Logger log = LogManager.getLogger(EndlessCircleLineScheduleModifier.class); + private TransitSchedule schedule; + private TransitScheduleFactory factory; + + public static void main(String[] args) { + EndlessCircleLineScheduleModifier runner = new EndlessCircleLineScheduleModifier(); + runner.run(); + } + + private void run() { + String inputScheduleFile = "../public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.3/input/berlin-v6.3-transitSchedule.xml.gz"; + String transitLineS41Id = "S41---4715"; + String transitLineS42Id = "S42---5444"; + // check with every schedule update transit route ids (still full loop?), headways, first departure time + String singleLoopingToCopyS41TransitRouteId = "S41---4715_0";// in berlin v6.3 schedule 200 departures, remaining S41 routes less than 8 deps each + String multipleLoopingsS41TransitRouteId1 = "S41---4715_loop1"; + String multipleLoopingsS41TransitRouteId2 = "S41---4715_loop2"; + + int vehIdOffset = 20; // TODO: hacky, get rid of this and cleanly add / remove transit vehicles + + String singleLoopingToCopyS42TransitRouteId = "S42---5444_0";// in berlin v6.3 schedule 180 departures, remaining S42 routes less than 15 deps each + String multipleLoopingsS42TransitRouteId1 = "S42---5444_loop1"; + String multipleLoopingsS42TransitRouteId2 = "S42---5444_loop2"; + + //departureTransitStopS41FacilityId = "469985" Beusselstr., link pt_46478 from pt_469985 to pt_469985 -> loop link, do not use. Unfortunately, other partial looping routes keep using it. Agents will either wait at this stop or the other and cannot switch freely. + //loopStartTransitStopS41FacilityId = "469985.1" Beusselstr., link pt_46505 from pt_16724 to pt_469985 -> connecting link, use this + + double loopingTravelTime = 60 * 60.0; + + // TODO: necessary? private double bufferTimeToCompensateLongerFirstLink = 2 * 60.0; // if starting from a long + + // first S41---4715_0 departure at 4:08:24 in Beusselstr., then 10 min headway until 5:08:24, then 5 min until 20:18:24, then 10 min headway until 23:58:24. + // for simplification and reducing number of concurrent transit routes and associated issues oif agents prefering one tranist route over others of the same transit line + // have one transit route reflecting a 5 min headway until 20:03:24, i.e. 4:08 dep starts last loop 19:08. + int numberLoopingsTransitRoute1 = 19-4; + double headwayTransitRoute1 = 5 * 60.0; + double firstDepartureTimeS41TransitRoute1 = 4 * 3600.0 + 8 * 60.0 + 24; + // then another transit route from 20:08 every 10 min until 23:58, i.e. 20:08 starts last loop at 23:08 + int numberLoopingsTransitRoute2 = 23-20; + double headwayTransitRoute2 = 10 * 60.0; + double firstDepartureTimeS41TransitRoute2 = 20 * 3600.0 + 8 * 60.0 + 24; + + // S42 is more complex. For simplificatrion re-use many S41 values for S42 despite differences + // to be precise S42---5444_0 operates from 3:58:18 to,5:28:18 every 10 min, then every 5 min until 20:18:18, then every 10 min until 21:08:18. Then 5444_1 every 10 min from 21:18.18 until 22:08:18 (65 min loop time!) and 5444_5 from 22:23:18 every 10 min until 24:33:18 + double firstDepartureTimeS42TransitRoute1 = 3 * 3600.0 + 58 * 60.0 + 18; + double firstDepartureTimeS42TransitRoute2 = 19 * 3600.0 + 58 * 60.0 + 18; + + String outputScheduleFile = "../public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.3/input/berlin-v6.3-transitSchedule_endlessCircleLine.xml.gz"; + + Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); + TransitScheduleReader scheduleReader = new TransitScheduleReader(scenario); + scheduleReader.readFile(inputScheduleFile); + schedule = scenario.getTransitSchedule(); + factory = schedule.getFactory(); + + // S41 + createLoopingTransitRoute(Id.create(transitLineS41Id, TransitLine.class), + Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class), + Id.create(multipleLoopingsS41TransitRouteId1, TransitRoute.class), + loopingTravelTime, numberLoopingsTransitRoute1, headwayTransitRoute1, + firstDepartureTimeS41TransitRoute1, 0); + + createLoopingTransitRoute(Id.create(transitLineS41Id, TransitLine.class), + Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class), + Id.create(multipleLoopingsS41TransitRouteId2, TransitRoute.class), + loopingTravelTime, numberLoopingsTransitRoute2, headwayTransitRoute2, + firstDepartureTimeS41TransitRoute2, vehIdOffset); + + // delete old non-looping transit route + schedule.getTransitLines().get(Id.create(transitLineS41Id, TransitLine.class)).removeRoute(schedule.getTransitLines().get(Id.create(transitLineS41Id, TransitLine.class)).getRoutes().get(Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class))); + + // S42 + createLoopingTransitRoute(Id.create(transitLineS42Id, TransitLine.class), + Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class), + Id.create(multipleLoopingsS42TransitRouteId1, TransitRoute.class), + loopingTravelTime, numberLoopingsTransitRoute1, headwayTransitRoute1, + firstDepartureTimeS42TransitRoute1, 0); + + createLoopingTransitRoute(Id.create(transitLineS42Id, TransitLine.class), + Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class), + Id.create(multipleLoopingsS42TransitRouteId2, TransitRoute.class), + loopingTravelTime, numberLoopingsTransitRoute2, headwayTransitRoute2, + firstDepartureTimeS42TransitRoute2, vehIdOffset); + + // delete old non-looping transit route + schedule.getTransitLines().get(Id.create(transitLineS42Id, TransitLine.class)).removeRoute(schedule.getTransitLines().get(Id.create(transitLineS42Id, TransitLine.class)).getRoutes().get(Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class))); + + + TransitScheduleWriter transitScheduleWriter = new TransitScheduleWriter(schedule); + transitScheduleWriter.writeFile(outputScheduleFile); + } + + private void createLoopingTransitRoute(Id transitLineId, Id singleLoopingToCopyTransitRouteId, + Id loopingTransitRouteId, + double loopingTravelTime, int numberLoopings, + double headway, double firstDepartureTime, int vehIdOffset) { + + TransitLine lineToModify = schedule.getTransitLines().get(transitLineId); + TransitRoute routeToCopy = lineToModify.getRoutes().get(singleLoopingToCopyTransitRouteId); + + List> loopingNetworkRouteLinks = new ArrayList<>(); + List transitRouteStops = new ArrayList<>(); + // add first stop manually + TransitRouteStop firstRouteStop = factory.createTransitRouteStop( + routeToCopy.getStops().getLast().getStopFacility(), + routeToCopy.getStops().getFirst().getArrivalOffset(), + routeToCopy.getStops().getFirst().getDepartureOffset()); + transitRouteStops.add(firstRouteStop); + + loopingNetworkRouteLinks.add(firstRouteStop.getStopFacility().getLinkId()); + + for (int loopingsDone = 0; loopingsDone < numberLoopings; loopingsDone++) { + loopingNetworkRouteLinks.addAll(routeToCopy.getRoute().getLinkIds()); + loopingNetworkRouteLinks.add(routeToCopy.getRoute().getEndLinkId()); + + // skip first and last stop and add merged stop instead to avoid stopping twice at loopStartTransitStopId + for (TransitRouteStop stop : routeToCopy.getStops().subList(1, routeToCopy.getStops().size() - 1)) { + transitRouteStops.add(factory.createTransitRouteStop(stop.getStopFacility(), + stop.getArrivalOffset().seconds() + loopingsDone * loopingTravelTime, + stop.getDepartureOffset().seconds() + loopingsDone * loopingTravelTime)); + } + // add last stop of this looping which is first stop of next looping + TransitRouteStop lastRouteStop = factory.createTransitRouteStop( + routeToCopy.getStops().getLast().getStopFacility(), + routeToCopy.getStops().getLast().getArrivalOffset().seconds() + loopingsDone * loopingTravelTime, + routeToCopy.getStops().getFirst().getDepartureOffset().seconds() + (loopingsDone + 1) * loopingTravelTime); + transitRouteStops.add(lastRouteStop); + } + // at least for S41 and S42 last link in network route ends at same node as first link -> continuous + NetworkRoute networkRoute = RouteUtils.createNetworkRoute(loopingNetworkRouteLinks); + TransitRoute loopingRoute = factory.createTransitRoute(loopingTransitRouteId, networkRoute, transitRouteStops, "multiple loopings in one route"); + + int departureIdCounter = 0; + for (double departureTime = firstDepartureTime; departureTime < firstDepartureTime + loopingTravelTime; departureTime = departureTime + headway) { + Id departureId = Id.create(loopingTransitRouteId + "_" + departureIdCounter, Departure.class); + Departure departure = factory.createDeparture(departureId, departureTime); + // TODO: This makes assumptions on existing transit vehicles that are true for S41, S42. It would be cleaner be to create new vehicles and delete unused old ones and modify transit vehicles file. + departure.setVehicleId(Id.createVehicleId("pt_" + singleLoopingToCopyTransitRouteId + "_" + (departureIdCounter + vehIdOffset))); + loopingRoute.addDeparture(departure); + departureIdCounter++; + } + + lineToModify.addRoute(loopingRoute); + } +} From 9270a9d3b545c2625504cc367e5b1750882e3fbe Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Tue, 15 Oct 2024 22:47:25 +0200 Subject: [PATCH 02/11] endless circle line: set await departure true and transport mode --- .../transit/EndlessCircleLineScheduleModifier.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java index a237f613..f4289b3d 100644 --- a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -121,6 +121,7 @@ private void createLoopingTransitRoute(Id transitLineId, Id transitLineId, Id continuous NetworkRoute networkRoute = RouteUtils.createNetworkRoute(loopingNetworkRouteLinks); TransitRoute loopingRoute = factory.createTransitRoute(loopingTransitRouteId, networkRoute, transitRouteStops, "multiple loopings in one route"); + loopingRoute.setTransportMode(routeToCopy.getTransportMode()); int departureIdCounter = 0; for (double departureTime = firstDepartureTime; departureTime < firstDepartureTime + loopingTravelTime; departureTime = departureTime + headway) { From 95449f6a10496468e656be103932de78700a2e09 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Fri, 13 Dec 2024 23:16:38 +0100 Subject: [PATCH 03/11] attempt to guess ids and departure times of circle line to replace hard coded values, add to make file --- Makefile | 7 + .../EndlessCircleLineScheduleModifier.java | 289 +++++++++++++----- 2 files changed, 216 insertions(+), 80 deletions(-) diff --git a/Makefile b/Makefile index 63cb5f57..c76c8315 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,13 @@ $p/berlin-$V-network-with-pt.xml.gz: $p/berlin-$V-network.xml.gz $(germany)/gtfs/complete-pt-2023-06-06.zip\ --shp $p/pt-area/pt-area.shp + $(sc) prepare endless-circle-line\ + --network $p/berlin-$V-network-with-pt.xml.gz\ + --transit-schedule $p/berlin-$V-transitSchedule.xml.gz\ + --transit-vehicles $p/berlin-$V-transitVehicles.xml.gz\ + --output-transit-schedule $p/berlin-$V-transitSchedule-endless-circle-line.xml.gz + --output-transit-vehicles $p/berlin-$V-transitVehicles-endless-circle-line.xml.gz + $p/berlin-$V-counts-vmz.xml.gz: $p/berlin-$V-network.xml.gz $(sc) prepare counts-from-vmz\ --excel ../shared-svn/projects/matsim-berlin/berlin-v5.5/original_data/vmz_counts_2018/Datenexport_2018_TU_Berlin.xlsx\ diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java index f4289b3d..0056a318 100644 --- a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -5,111 +5,157 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Link; +import org.matsim.application.MATSimAppCommand; import org.matsim.core.config.ConfigUtils; +import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.population.routes.NetworkRoute; import org.matsim.core.population.routes.RouteUtils; import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.collections.Tuple; import org.matsim.pt.transitSchedule.api.*; +import org.matsim.pt.utils.TransitScheduleValidator; +import org.matsim.vehicles.*; +import picocli.CommandLine; +import java.nio.file.Path; import java.util.*; -public class EndlessCircleLineScheduleModifier { - private final static Logger log = LogManager.getLogger(EndlessCircleLineScheduleModifier.class); - private TransitSchedule schedule; - private TransitScheduleFactory factory; +// other schedule modifier in the make file implement Consumer. But here we modify schedule and vehicles, so we cannot use that. +@CommandLine.Command(name = "endless-circle-line", description = "Modifies Berlin S41 and S42 to run circle multiple times.") +public class EndlessCircleLineScheduleModifier implements MATSimAppCommand { - public static void main(String[] args) { - EndlessCircleLineScheduleModifier runner = new EndlessCircleLineScheduleModifier(); - runner.run(); - } + private static final Logger log = LogManager.getLogger(EndlessCircleLineScheduleModifier.class); - private void run() { - String inputScheduleFile = "../public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.3/input/berlin-v6.3-transitSchedule.xml.gz"; - String transitLineS41Id = "S41---4715"; - String transitLineS42Id = "S42---5444"; - // check with every schedule update transit route ids (still full loop?), headways, first departure time - String singleLoopingToCopyS41TransitRouteId = "S41---4715_0";// in berlin v6.3 schedule 200 departures, remaining S41 routes less than 8 deps each - String multipleLoopingsS41TransitRouteId1 = "S41---4715_loop1"; - String multipleLoopingsS41TransitRouteId2 = "S41---4715_loop2"; + @CommandLine.Option(names = {"--transit-schedule"}, description = "Path to the transit schedule file", required = true) + private String transitSchedulePath; + @CommandLine.Option(names = {"--transit-vehicles"}, description = "Path to the transit vehicles file", required = true) + private String transitVehiclesPath; + @CommandLine.Option(names = {"--network"}, description = "Path to the network file (for validation only)", required = false) + private String networkPath; + @CommandLine.Option(names = "--output-transit-schedule", description = "Path to the output transit schedule file", required = true) + private Path outputTransitSchedule; + @CommandLine.Option(names = "--output-transit-vehicles", description = "Path to the output transit vehicles file", required = true) + private Path outputTransitVehicles; - int vehIdOffset = 20; // TODO: hacky, get rid of this and cleanly add / remove transit vehicles + private TransitSchedule schedule; + private Vehicles transitVehicles; + private TransitScheduleFactory transitScheduleFactory; - String singleLoopingToCopyS42TransitRouteId = "S42---5444_0";// in berlin v6.3 schedule 180 departures, remaining S42 routes less than 15 deps each - String multipleLoopingsS42TransitRouteId1 = "S42---5444_loop1"; - String multipleLoopingsS42TransitRouteId2 = "S42---5444_loop2"; + public static void main(String[] args) { + new EndlessCircleLineScheduleModifier().execute(args); + } - //departureTransitStopS41FacilityId = "469985" Beusselstr., link pt_46478 from pt_469985 to pt_469985 -> loop link, do not use. Unfortunately, other partial looping routes keep using it. Agents will either wait at this stop or the other and cannot switch freely. - //loopStartTransitStopS41FacilityId = "469985.1" Beusselstr., link pt_46505 from pt_16724 to pt_469985 -> connecting link, use this + @Override + public Integer call() throws Exception { + replaceS41S42With2LoopingRoutesEach(); + return 0; + } + private void replaceS41S42With2LoopingRoutesEach() { + /* + * basic service pattern of the circle lines S41 and S42 is a 10 min headway service from 4:00 to 24:00 plus additional trains every 10 min + * from circa. 5:30 to 20:20 reinforcing to a 5 min headway. + * + * Here as an example values from a 2023 timetable: + * first S41---4715_0 departure at 4:08:24 in Beusselstr., then 10 min headway until 5:08:24, then 5 min until 20:18:24, + * then 10 min headway until 23:58:24. + * + * S42 was similar to S41 in December 2024, but was more complex in 2023: + * S42---5444_0 operated from 3:58:18 to,5:28:18 every 10 min, then every 5 min until 20:18:18, then every 10 min until 21:08:18. + * Then 5444_1 every 10 min from 21:18.18 until 22:08:18 (65 min loop time!) and 5444_5 from 22:23:18 every 10 min until 24:33:18. + * + * For simplification implement 2 looping TransitRoutes per circle line, both every 10 min with approximated first and last departure times. + */ double loopingTravelTime = 60 * 60.0; + double firstDepartureTime = 3 * 60 * 60 + 50 * 60; + double lastDepartureTime = 24 * 60 * 60 + 30 * 60; + double baseHeadway = 10 * 60; + double peakHeadwayStart = 5 * 60 * 60 + 20 * 60; + double peakHeadwayEnd = 20 * 60 * 60 + 20 * 60; - // TODO: necessary? private double bufferTimeToCompensateLongerFirstLink = 2 * 60.0; // if starting from a long - - // first S41---4715_0 departure at 4:08:24 in Beusselstr., then 10 min headway until 5:08:24, then 5 min until 20:18:24, then 10 min headway until 23:58:24. - // for simplification and reducing number of concurrent transit routes and associated issues oif agents prefering one tranist route over others of the same transit line - // have one transit route reflecting a 5 min headway until 20:03:24, i.e. 4:08 dep starts last loop 19:08. - int numberLoopingsTransitRoute1 = 19-4; - double headwayTransitRoute1 = 5 * 60.0; - double firstDepartureTimeS41TransitRoute1 = 4 * 3600.0 + 8 * 60.0 + 24; - // then another transit route from 20:08 every 10 min until 23:58, i.e. 20:08 starts last loop at 23:08 - int numberLoopingsTransitRoute2 = 23-20; - double headwayTransitRoute2 = 10 * 60.0; - double firstDepartureTimeS41TransitRoute2 = 20 * 3600.0 + 8 * 60.0 + 24; + Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); + schedule = scenario.getTransitSchedule(); + transitScheduleFactory = schedule.getFactory(); + transitVehicles = scenario.getTransitVehicles(); + TransitScheduleReader scheduleReader = new TransitScheduleReader(scenario); + scheduleReader.readFile(transitSchedulePath); + MatsimVehicleReader vehicleReader = new MatsimVehicleReader(transitVehicles); + vehicleReader.readFile(transitVehiclesPath); - // S42 is more complex. For simplificatrion re-use many S41 values for S42 despite differences - // to be precise S42---5444_0 operates from 3:58:18 to,5:28:18 every 10 min, then every 5 min until 20:18:18, then every 10 min until 21:08:18. Then 5444_1 every 10 min from 21:18.18 until 22:08:18 (65 min loop time!) and 5444_5 from 22:23:18 every 10 min until 24:33:18 - double firstDepartureTimeS42TransitRoute1 = 3 * 3600.0 + 58 * 60.0 + 18; - double firstDepartureTimeS42TransitRoute2 = 19 * 3600.0 + 58 * 60.0 + 18; + // attempt to find ids automatically (change with every new input gtfs file) + Tuple, Id> lineRouteS41 = findSingleLoopTransitRouteToCopy("S41"); + Tuple, Id> lineRouteS42 = findSingleLoopTransitRouteToCopy("S42"); - String outputScheduleFile = "../public-svn/matsim/scenarios/countries/de/berlin/berlin-v6.3/input/berlin-v6.3-transitSchedule_endlessCircleLine.xml.gz"; + double typicalDepartureSecondS41 = findTypicalDepartureSecond(lineRouteS41.getFirst(), lineRouteS41.getSecond()); + double typicalDepartureSecondS42 = findTypicalDepartureSecond(lineRouteS42.getFirst(), lineRouteS42.getSecond()); - Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); - TransitScheduleReader scheduleReader = new TransitScheduleReader(scenario); - scheduleReader.readFile(inputScheduleFile); - schedule = scenario.getTransitSchedule(); - factory = schedule.getFactory(); + VehicleType vehicleType = findTypicalVehicleType(lineRouteS41.getFirst(), lineRouteS41.getSecond()); // S41 - createLoopingTransitRoute(Id.create(transitLineS41Id, TransitLine.class), - Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class), - Id.create(multipleLoopingsS41TransitRouteId1, TransitRoute.class), - loopingTravelTime, numberLoopingsTransitRoute1, headwayTransitRoute1, - firstDepartureTimeS41TransitRoute1, 0); - - createLoopingTransitRoute(Id.create(transitLineS41Id, TransitLine.class), - Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class), - Id.create(multipleLoopingsS41TransitRouteId2, TransitRoute.class), - loopingTravelTime, numberLoopingsTransitRoute2, headwayTransitRoute2, - firstDepartureTimeS41TransitRoute2, vehIdOffset); + createLoopingTransitRoute(lineRouteS41.getFirst(), lineRouteS41.getSecond(), + Id.create(lineRouteS41.getFirst() + "_loop", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(firstDepartureTime, lastDepartureTime, loopingTravelTime), + baseHeadway, firstDepartureTime + typicalDepartureSecondS41, vehicleType); + + createLoopingTransitRoute(lineRouteS41.getFirst(), lineRouteS41.getSecond(), + Id.create(lineRouteS41.getFirst() + "_loop_peak", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(peakHeadwayStart, peakHeadwayEnd, loopingTravelTime), + baseHeadway, peakHeadwayStart + typicalDepartureSecondS41 + baseHeadway / 2, vehicleType); + + // add early morning service on following day + createLoopingTransitRoute(lineRouteS41.getFirst(), lineRouteS41.getSecond(), + Id.create(lineRouteS41.getFirst() + "_loop+24h", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600, 30 * 3600, loopingTravelTime), + baseHeadway, firstDepartureTime + 24 * 3600 + typicalDepartureSecondS41, vehicleType); // delete old non-looping transit route - schedule.getTransitLines().get(Id.create(transitLineS41Id, TransitLine.class)).removeRoute(schedule.getTransitLines().get(Id.create(transitLineS41Id, TransitLine.class)).getRoutes().get(Id.create(singleLoopingToCopyS41TransitRouteId, TransitRoute.class))); + removeOldTransitRouteAndItsVehicles(lineRouteS41.getFirst(), lineRouteS41.getSecond()); // S42 - createLoopingTransitRoute(Id.create(transitLineS42Id, TransitLine.class), - Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class), - Id.create(multipleLoopingsS42TransitRouteId1, TransitRoute.class), - loopingTravelTime, numberLoopingsTransitRoute1, headwayTransitRoute1, - firstDepartureTimeS42TransitRoute1, 0); - - createLoopingTransitRoute(Id.create(transitLineS42Id, TransitLine.class), - Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class), - Id.create(multipleLoopingsS42TransitRouteId2, TransitRoute.class), - loopingTravelTime, numberLoopingsTransitRoute2, headwayTransitRoute2, - firstDepartureTimeS42TransitRoute2, vehIdOffset); + createLoopingTransitRoute(lineRouteS42.getFirst(), lineRouteS42.getSecond(), + Id.create(lineRouteS42.getFirst() + "_loop", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(firstDepartureTime, lastDepartureTime, loopingTravelTime), + baseHeadway, firstDepartureTime + typicalDepartureSecondS42, vehicleType); - // delete old non-looping transit route - schedule.getTransitLines().get(Id.create(transitLineS42Id, TransitLine.class)).removeRoute(schedule.getTransitLines().get(Id.create(transitLineS42Id, TransitLine.class)).getRoutes().get(Id.create(singleLoopingToCopyS42TransitRouteId, TransitRoute.class))); + createLoopingTransitRoute(lineRouteS42.getFirst(), lineRouteS42.getSecond(), + Id.create(lineRouteS42.getFirst() + "_loop_peak", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(peakHeadwayStart, peakHeadwayEnd, loopingTravelTime), + baseHeadway, peakHeadwayStart + typicalDepartureSecondS42 + baseHeadway / 2, vehicleType); + + // add early morning service on following day + createLoopingTransitRoute(lineRouteS42.getFirst(), lineRouteS42.getSecond(), + Id.create(lineRouteS42.getFirst() + "_loop+24h", TransitRoute.class), + loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600, 30 * 3600, loopingTravelTime), + baseHeadway, firstDepartureTime + 24 * 3600 + typicalDepartureSecondS42, vehicleType); + + removeOldTransitRouteAndItsVehicles(lineRouteS42.getFirst(), lineRouteS42.getSecond()); + if (networkPath != null && !networkPath.isEmpty()) { + MatsimNetworkReader networkReader = new MatsimNetworkReader(scenario.getNetwork()); + networkReader.readFile(networkPath); + TransitScheduleValidator.ValidationResult validationResult = TransitScheduleValidator.validateAll(schedule, scenario.getNetwork()); + if (validationResult.isValid()) { + log.info("TransitSchedule is valid according to TransitScheduleValidator."); + } else { + log.error("TransitSchedule is invalid according to TransitScheduleValidator."); + for (TransitScheduleValidator.ValidationResult.ValidationIssue issue : validationResult.getIssues()) { + log.error(issue.getMessage()); + } + throw new RuntimeException("invalid output schedule"); + } + } TransitScheduleWriter transitScheduleWriter = new TransitScheduleWriter(schedule); - transitScheduleWriter.writeFile(outputScheduleFile); + transitScheduleWriter.writeFile(outputTransitSchedule.toString()); + MatsimVehicleWriter vehicleWriter = new MatsimVehicleWriter(transitVehicles); + vehicleWriter.writeFile(outputTransitVehicles.toString()); } private void createLoopingTransitRoute(Id transitLineId, Id singleLoopingToCopyTransitRouteId, Id loopingTransitRouteId, - double loopingTravelTime, int numberLoopings, - double headway, double firstDepartureTime, int vehIdOffset) { + double loopingTravelTime, long numberLoopings, + double headway, double firstDepartureTime, + VehicleType vehicleType) { TransitLine lineToModify = schedule.getTransitLines().get(transitLineId); TransitRoute routeToCopy = lineToModify.getRoutes().get(singleLoopingToCopyTransitRouteId); @@ -117,7 +163,7 @@ private void createLoopingTransitRoute(Id transitLineId, Id> loopingNetworkRouteLinks = new ArrayList<>(); List transitRouteStops = new ArrayList<>(); // add first stop manually - TransitRouteStop firstRouteStop = factory.createTransitRouteStop( + TransitRouteStop firstRouteStop = transitScheduleFactory.createTransitRouteStop( routeToCopy.getStops().getLast().getStopFacility(), routeToCopy.getStops().getFirst().getArrivalOffset(), routeToCopy.getStops().getFirst().getDepartureOffset()); @@ -132,35 +178,118 @@ private void createLoopingTransitRoute(Id transitLineId, Id continuous NetworkRoute networkRoute = RouteUtils.createNetworkRoute(loopingNetworkRouteLinks); - TransitRoute loopingRoute = factory.createTransitRoute(loopingTransitRouteId, networkRoute, transitRouteStops, "multiple loopings in one route"); + TransitRoute loopingRoute = transitScheduleFactory.createTransitRoute(loopingTransitRouteId, networkRoute, transitRouteStops, "multiple loopings in one route"); loopingRoute.setTransportMode(routeToCopy.getTransportMode()); int departureIdCounter = 0; for (double departureTime = firstDepartureTime; departureTime < firstDepartureTime + loopingTravelTime; departureTime = departureTime + headway) { Id departureId = Id.create(loopingTransitRouteId + "_" + departureIdCounter, Departure.class); - Departure departure = factory.createDeparture(departureId, departureTime); - // TODO: This makes assumptions on existing transit vehicles that are true for S41, S42. It would be cleaner be to create new vehicles and delete unused old ones and modify transit vehicles file. - departure.setVehicleId(Id.createVehicleId("pt_" + singleLoopingToCopyTransitRouteId + "_" + (departureIdCounter + vehIdOffset))); + Departure departure = transitScheduleFactory.createDeparture(departureId, departureTime); + // create new vehicles and delete unused old ones later. + Id vehicleId = Id.createVehicleId("pt_" + loopingRoute.getId().toString() + "_" + departureIdCounter); + transitVehicles.getFactory().createVehicle(vehicleId, vehicleType); + departure.setVehicleId(vehicleId); loopingRoute.addDeparture(departure); departureIdCounter++; } lineToModify.addRoute(loopingRoute); } + + private VehicleType findTypicalVehicleType(Id lineId, Id routeId) { + TransitRoute route = schedule.getTransitLines().get(lineId).getRoutes().get(routeId); + Optional exampleDepartureOptional = route.getDepartures().values().stream() + // find a typical VehicleType, avoid early hours short train + .filter(dep -> dep.getDepartureTime() > 8 * 60 * 60 && dep.getDepartureTime() < 20 * 60 * 60) + .findFirst(); + if (exampleDepartureOptional.isEmpty()) { + log.error("No suitable Departure found in line " + lineId.toString() + ", route " + routeId.toString() + + "to use as an example for the VehicleType to be used on the new endless looping TransitRoute."); + throw new RuntimeException("No suitable Departure found to define VehicleType."); + } + return transitVehicles.getVehicles().get(exampleDepartureOptional.get().getVehicleId()).getType(); + } + + private Tuple, Id> findSingleLoopTransitRouteToCopy(String lineName) { + List, Id>> candidates = new ArrayList<>(); + for (TransitLine line : schedule.getTransitLines().values()) { + if (line.getAttributes().getAttribute("gtfs_route_short_name").equals(lineName)) { + for (TransitRoute route : line.getRoutes().values()) { + if (route.getStops().getFirst().getStopFacility().getStopAreaId().equals( + route.getStops().getLast().getStopFacility().getStopAreaId()) && + route.getStops().size() == 28 && + route.getStops().getLast().getArrivalOffset().seconds() > 58 * 60 && + route.getStops().getLast().getArrivalOffset().seconds() < 60 * 60 && + route.getDepartures().size() > 100) { + // is looping, has all stops and has travel time ca. 60 min (not 65 min) and a significant number of departures + // usually there is only one looping TransitRoute *_0 with > 200 departures or two looping TransitRoutes, of which one has > 150 departures and operates all day and the other has < 30 departures. + candidates.add(new Tuple<>(line.getId(), route.getId())); + } + } + } + } + + switch (candidates.size()) { + case 0: + log.error("No suitable circle line and route found that loops with the correct number of stops and travel time for line " + lineName + + ". Check for construction work and timetable changes. A day with disturbed circle line is a bad choice."); + throw new RuntimeException("No suitable line and route found that loops with the correct number of stops and travel time for line " + lineName); + case 1: + return candidates.getFirst(); + default: + log.error("Found multiple circle line candidates for " + lineName + + ". This is unusual. Please check manually which is the best fit. Listing candidates here "); + for (Tuple, Id> tuple : candidates) { + log.error("line " + tuple.getFirst().toString() + ", route " + tuple.getSecond()); + } + throw new RuntimeException("Aborting."); + } + } + + /** + * Find typical departure time offset from hour. This is important to keep waiting times and headways in respect to other lines similar. + */ + private double findTypicalDepartureSecond(Id transitLineId, Id transitRouteId) { + TransitRoute transitRoute = schedule.getTransitLines().get(transitLineId).getRoutes().get(transitRouteId); + Map departureSecond2Count = new HashMap<>(); + for (Departure departure : transitRoute.getDepartures().values()) { + // usually operates every 10 or 5 minutes, so % 3600 reduces by hours and % 600 reduces by 10 min headway + double offsetFromHour = (departure.getDepartureTime() % 3600) % 600; + departureSecond2Count.put(offsetFromHour, departureSecond2Count.getOrDefault(offsetFromHour, 0) + 1); + } + Optional> mostFrequentDepartureSecond = departureSecond2Count.entrySet().stream() + .max(Comparator.comparingInt(Map.Entry::getValue)); + // most frequent offset should be the one found during both 5 min and 10 min headways + if (mostFrequentDepartureSecond.isEmpty() || mostFrequentDepartureSecond.get().getValue() < 50) { + log.error("Could not determine typical departure time for " + transitLineId.toString() + ", " + transitRouteId.toString()); + throw new RuntimeException("Could not determine typical departure time."); + } + return mostFrequentDepartureSecond.get().getKey(); + } + + private long getNumberOfLoopings(double firstDepartureTime, double lastDepartureTime, double loopTravelTime) { + return Math.round((lastDepartureTime - firstDepartureTime - loopTravelTime) / loopTravelTime); + } + + private void removeOldTransitRouteAndItsVehicles(Id transitLineId, Id transitRouteId) { + TransitRoute oldNonLoopingTransitRouteToDelete = schedule.getTransitLines().get(transitLineId).getRoutes().get(transitRouteId); + oldNonLoopingTransitRouteToDelete.getDepartures().values().forEach(dep -> transitVehicles.removeVehicle(dep.getVehicleId())); + schedule.getTransitLines().get(transitLineId).removeRoute(oldNonLoopingTransitRouteToDelete); + } } From 89be99b955bbaa9f05d3dc6148dee7cd95c493b0 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Sat, 14 Dec 2024 01:32:28 +0100 Subject: [PATCH 04/11] update gtfs2matsim, fix make file --- Makefile | 6 ++++-- pom.xml | 4 ++-- .../prepare/RunOpenBerlinCalibration.java | 3 ++- .../EndlessCircleLineScheduleModifier.java | 19 +++++++++++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 56e36959..6482aeb1 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,7 @@ $p/berlin-$V-network-with-pt.xml.gz: $p/berlin-$V-network.xml.gz --network $p/berlin-$V-network-with-pt.xml.gz\ --transit-schedule $p/berlin-$V-transitSchedule.xml.gz\ --transit-vehicles $p/berlin-$V-transitVehicles.xml.gz\ - --output-transit-schedule $p/berlin-$V-transitSchedule-endless-circle-line.xml.gz + --output-transit-schedule $p/berlin-$V-transitSchedule-endless-circle-line.xml.gz\ --output-transit-vehicles $p/berlin-$V-transitVehicles-endless-circle-line.xml.gz $p/berlin-$V-counts-vmz.xml.gz: $p/berlin-$V-network.xml.gz @@ -356,4 +356,6 @@ prepare-drt: $p/berlin-$V.drt-by-rndLocations-10000vehicles-4seats.xml.gz echo "Done" prepare: $p/berlin-$V-10pct.plans.xml.gz - echo "Done" \ No newline at end of file + echo "Done" + +prepare-schedule: $p/berlin-$V-network-with-pt.xml.gz \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1ef396ea..56bf0124 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ matsim-all - 2025.0-PR3628 + 2025.0-PR3637 @@ -128,7 +128,7 @@ com.github.matsim-org gtfs2matsim - 19f1676fc6 + 5b5f6abf6e org.matsim diff --git a/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java b/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java index 9edfb1da..95559b7f 100644 --- a/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java +++ b/src/main/java/org/matsim/prepare/RunOpenBerlinCalibration.java @@ -62,6 +62,7 @@ import org.matsim.prepare.opt.RunCountOptimization; import org.matsim.prepare.opt.SelectPlansFromIndex; import org.matsim.prepare.population.*; +import org.matsim.prepare.transit.EndlessCircleLineScheduleModifier; import org.matsim.run.Activities; import org.matsim.run.OpenBerlinScenario; import org.matsim.run.scoring.AdvancedScoringConfigGroup; @@ -94,7 +95,7 @@ GenerateSmallScaleCommercialTrafficDemand.class, CreateDataDistributionOfStructureData.class, RunCountOptimization.class, SelectPlansFromIndex.class, ExtractPlanIndexFromType.class, AssignReferencePopulation.class, ExtractRelevantFreightTrips.class, CheckCarAvailability.class, FixSubtourModes.class, ComputeTripChoices.class, ComputePlanChoices.class, - ApplyNetworkParams.class, SetCarAvailabilityByAge.class, CreateDrtVehicles.class + ApplyNetworkParams.class, SetCarAvailabilityByAge.class, CreateDrtVehicles.class, EndlessCircleLineScheduleModifier.class }) public class RunOpenBerlinCalibration extends MATSimApplication { diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java index 0056a318..16a0eccb 100644 --- a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -1,3 +1,22 @@ +/* *********************************************************************** * + * project: org.matsim.* + * * + * *********************************************************************** * + * * + * copyright : (C) 2024 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + package org.matsim.prepare.transit; import org.apache.logging.log4j.LogManager; From 3dfe42d2e2d84264114b49b4220faff1d55b4120 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Sat, 14 Dec 2024 01:40:18 +0100 Subject: [PATCH 05/11] exclude second gtfs2matsim dependency via contrib application --- pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pom.xml b/pom.xml index 56bf0124..1983e8db 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,10 @@ xerces xercesImpl + + com.github.matsim-org + gtfs2matsim + From 5b0e2425cc35c18cfde8845ab56c952834e13092 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Sat, 14 Dec 2024 02:14:43 +0100 Subject: [PATCH 06/11] update gtfs2matsim to fix issue with white space in link ids --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1983e8db..f0f78e29 100644 --- a/pom.xml +++ b/pom.xml @@ -132,7 +132,7 @@ com.github.matsim-org gtfs2matsim - 5b5f6abf6e + 45689bf834 org.matsim From a68672009f4095f35bbb0bda3ce92d6ee02692cb Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Mon, 16 Dec 2024 13:28:27 +0100 Subject: [PATCH 07/11] make code style sona happy --- .../EndlessCircleLineScheduleModifier.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java index 16a0eccb..65bd9bee 100644 --- a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -70,6 +70,7 @@ public Integer call() throws Exception { return 0; } + @SuppressWarnings("rawtypes") private void replaceS41S42With2LoopingRoutesEach() { /* * basic service pattern of the circle lines S41 and S42 is a 10 min headway service from 4:00 to 24:00 plus additional trains every 10 min @@ -86,11 +87,11 @@ private void replaceS41S42With2LoopingRoutesEach() { * For simplification implement 2 looping TransitRoutes per circle line, both every 10 min with approximated first and last departure times. */ double loopingTravelTime = 60 * 60.0; - double firstDepartureTime = 3 * 60 * 60 + 50 * 60; - double lastDepartureTime = 24 * 60 * 60 + 30 * 60; - double baseHeadway = 10 * 60; - double peakHeadwayStart = 5 * 60 * 60 + 20 * 60; - double peakHeadwayEnd = 20 * 60 * 60 + 20 * 60; + double firstDepartureTime = 3 * 60 * 60. + 50 * 60.; + double lastDepartureTime = 24 * 60 * 60. + 30 * 60.; + double baseHeadway = 10 * 60.; + double peakHeadwayStart = 5 * 60 * 60. + 20 * 60.; + double peakHeadwayEnd = 20 * 60 * 60. + 20 * 60.; Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); schedule = scenario.getTransitSchedule(); @@ -124,8 +125,8 @@ loopingTravelTime, getNumberOfLoopings(peakHeadwayStart, peakHeadwayEnd, looping // add early morning service on following day createLoopingTransitRoute(lineRouteS41.getFirst(), lineRouteS41.getSecond(), Id.create(lineRouteS41.getFirst() + "_loop+24h", TransitRoute.class), - loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600, 30 * 3600, loopingTravelTime), - baseHeadway, firstDepartureTime + 24 * 3600 + typicalDepartureSecondS41, vehicleType); + loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600., 30 * 3600., loopingTravelTime), + baseHeadway, firstDepartureTime + 24 * 3600. + typicalDepartureSecondS41, vehicleType); // delete old non-looping transit route removeOldTransitRouteAndItsVehicles(lineRouteS41.getFirst(), lineRouteS41.getSecond()); @@ -144,8 +145,8 @@ loopingTravelTime, getNumberOfLoopings(peakHeadwayStart, peakHeadwayEnd, looping // add early morning service on following day createLoopingTransitRoute(lineRouteS42.getFirst(), lineRouteS42.getSecond(), Id.create(lineRouteS42.getFirst() + "_loop+24h", TransitRoute.class), - loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600, 30 * 3600, loopingTravelTime), - baseHeadway, firstDepartureTime + 24 * 3600 + typicalDepartureSecondS42, vehicleType); + loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600., 30 * 3600., loopingTravelTime), + baseHeadway, firstDepartureTime + 24 * 3600. + typicalDepartureSecondS42, vehicleType); removeOldTransitRouteAndItsVehicles(lineRouteS42.getFirst(), lineRouteS42.getSecond()); @@ -160,7 +161,7 @@ loopingTravelTime, getNumberOfLoopings(firstDepartureTime + 24 * 3600, 30 * 3600 for (TransitScheduleValidator.ValidationResult.ValidationIssue issue : validationResult.getIssues()) { log.error(issue.getMessage()); } - throw new RuntimeException("invalid output schedule"); + throw new IllegalStateException("invalid output schedule"); } } @@ -238,9 +239,9 @@ private VehicleType findTypicalVehicleType(Id lineId, Id dep.getDepartureTime() > 8 * 60 * 60 && dep.getDepartureTime() < 20 * 60 * 60) .findFirst(); if (exampleDepartureOptional.isEmpty()) { - log.error("No suitable Departure found in line " + lineId.toString() + ", route " + routeId.toString() + - "to use as an example for the VehicleType to be used on the new endless looping TransitRoute."); - throw new RuntimeException("No suitable Departure found to define VehicleType."); + log.error("No suitable Departure found in line {}, route {} to use as an example for the VehicleType to be used on the new endless looping TransitRoute.", + lineId, routeId); + throw new IllegalStateException("No suitable Departure found to define VehicleType."); } return transitVehicles.getVehicles().get(exampleDepartureOptional.get().getVehicleId()).getType(); } @@ -266,18 +267,16 @@ private Tuple, Id> findSingleLoopTransitRouteToCop switch (candidates.size()) { case 0: - log.error("No suitable circle line and route found that loops with the correct number of stops and travel time for line " + lineName + - ". Check for construction work and timetable changes. A day with disturbed circle line is a bad choice."); - throw new RuntimeException("No suitable line and route found that loops with the correct number of stops and travel time for line " + lineName); + log.error("No suitable circle line and route found that loops with the correct number of stops and travel time for line {}. Check for construction work and timetable changes. A day with disturbed circle line is a bad choice.", lineName); + throw new IllegalStateException("No suitable line and route found that loops with the correct number of stops and travel time for line " + lineName); case 1: return candidates.getFirst(); default: - log.error("Found multiple circle line candidates for " + lineName + - ". This is unusual. Please check manually which is the best fit. Listing candidates here "); + log.error("Found multiple circle line candidates for {}. This is unusual. Please check manually which is the best fit. Listing candidates here ", lineName); for (Tuple, Id> tuple : candidates) { - log.error("line " + tuple.getFirst().toString() + ", route " + tuple.getSecond()); + log.error("line {}, route {}", tuple.getFirst(), tuple.getSecond()); } - throw new RuntimeException("Aborting."); + throw new IllegalStateException("Aborting."); } } @@ -296,8 +295,8 @@ private double findTypicalDepartureSecond(Id transitLineId, Id Date: Mon, 16 Dec 2024 16:52:55 +0100 Subject: [PATCH 08/11] update make file and add workaround in the scenario for now --- Makefile | 8 +++----- .../java/org/matsim/run/OpenBerlinScenario.java | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 6482aeb1..45056218 100644 --- a/Makefile +++ b/Makefile @@ -135,8 +135,8 @@ $p/berlin-$V-network-with-pt.xml.gz: $p/berlin-$V-network.xml.gz --network $p/berlin-$V-network-with-pt.xml.gz\ --transit-schedule $p/berlin-$V-transitSchedule.xml.gz\ --transit-vehicles $p/berlin-$V-transitVehicles.xml.gz\ - --output-transit-schedule $p/berlin-$V-transitSchedule-endless-circle-line.xml.gz\ - --output-transit-vehicles $p/berlin-$V-transitVehicles-endless-circle-line.xml.gz + --output-transit-schedule $p/berlin-$V-transitSchedule.xml.gz\ + --output-transit-vehicles $p/berlin-$V-transitVehicles.xml.gz $p/berlin-$V-counts-vmz.xml.gz: $p/berlin-$V-network.xml.gz $(sc) prepare counts-from-vmz\ @@ -356,6 +356,4 @@ prepare-drt: $p/berlin-$V.drt-by-rndLocations-10000vehicles-4seats.xml.gz echo "Done" prepare: $p/berlin-$V-10pct.plans.xml.gz - echo "Done" - -prepare-schedule: $p/berlin-$V-network-with-pt.xml.gz \ No newline at end of file + echo "Done" \ No newline at end of file diff --git a/src/main/java/org/matsim/run/OpenBerlinScenario.java b/src/main/java/org/matsim/run/OpenBerlinScenario.java index 8fdf8b5a..4e057963 100644 --- a/src/main/java/org/matsim/run/OpenBerlinScenario.java +++ b/src/main/java/org/matsim/run/OpenBerlinScenario.java @@ -6,6 +6,9 @@ import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysisModule; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Plan; import org.matsim.application.MATSimApplication; import org.matsim.application.options.SampleOptions; import org.matsim.contrib.bicycle.BicycleConfigGroup; @@ -22,6 +25,7 @@ import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; +import org.matsim.core.router.TripStructureUtils; import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutilityFactory; import org.matsim.core.router.costcalculators.TravelDisutilityFactory; import org.matsim.core.router.util.TravelTime; @@ -144,6 +148,19 @@ protected void prepareScenario(Scenario scenario) { HbefaRoadTypeMapping roadTypeMapping = OsmHbefaMapping.build(); roadTypeMapping.addHbefaMappings(scenario.getNetwork()); + // XXX: yyyyyyyy TODO Remove before merging. This is just for intermediate runs to update the PT schedules + for (Person person : scenario.getPopulation().getPersons().values()) { + for (Plan plan : person.getPlans()) { + List legs = TripStructureUtils.getLegs(plan); + for (Leg leg : legs) { + if (leg.getMode().equals(TransportMode.pt)) { + leg.setRoute(null); + leg.setTravelTimeUndefined(); + } + } + } + } + } @Override From cf9f88d680131cc419a1de65e1fc2a9c83900ce0 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Mon, 16 Dec 2024 17:07:08 +0100 Subject: [PATCH 09/11] add vehicle --- .../prepare/transit/EndlessCircleLineScheduleModifier.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java index 65bd9bee..25cd5355 100644 --- a/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java +++ b/src/main/java/org/matsim/prepare/transit/EndlessCircleLineScheduleModifier.java @@ -223,7 +223,8 @@ private void createLoopingTransitRoute(Id transitLineId, Id vehicleId = Id.createVehicleId("pt_" + loopingRoute.getId().toString() + "_" + departureIdCounter); - transitVehicles.getFactory().createVehicle(vehicleId, vehicleType); + Vehicle vehicle = transitVehicles.getFactory().createVehicle(vehicleId, vehicleType); + transitVehicles.addVehicle(vehicle); departure.setVehicleId(vehicleId); loopingRoute.addDeparture(departure); departureIdCounter++; From 7da1e18942e87ae0c41fa6940b8621eb561ab562 Mon Sep 17 00:00:00 2001 From: rakow Date: Mon, 16 Dec 2024 22:06:34 +0100 Subject: [PATCH 10/11] remove unneeded work-around --- .../java/org/matsim/run/OpenBerlinScenario.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/org/matsim/run/OpenBerlinScenario.java b/src/main/java/org/matsim/run/OpenBerlinScenario.java index 4e057963..77f59d06 100644 --- a/src/main/java/org/matsim/run/OpenBerlinScenario.java +++ b/src/main/java/org/matsim/run/OpenBerlinScenario.java @@ -147,20 +147,6 @@ protected void prepareScenario(Scenario scenario) { // add hbefa link attributes. HbefaRoadTypeMapping roadTypeMapping = OsmHbefaMapping.build(); roadTypeMapping.addHbefaMappings(scenario.getNetwork()); - - // XXX: yyyyyyyy TODO Remove before merging. This is just for intermediate runs to update the PT schedules - for (Person person : scenario.getPopulation().getPersons().values()) { - for (Plan plan : person.getPlans()) { - List legs = TripStructureUtils.getLegs(plan); - for (Leg leg : legs) { - if (leg.getMode().equals(TransportMode.pt)) { - leg.setRoute(null); - leg.setTravelTimeUndefined(); - } - } - } - } - } @Override From 039fc074da02c5ef9794ae2159cfe43411b3eb82 Mon Sep 17 00:00:00 2001 From: rakow Date: Mon, 16 Dec 2024 22:09:03 +0100 Subject: [PATCH 11/11] remove unused imports --- src/main/java/org/matsim/run/OpenBerlinScenario.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/matsim/run/OpenBerlinScenario.java b/src/main/java/org/matsim/run/OpenBerlinScenario.java index 77f59d06..0a6afdfd 100644 --- a/src/main/java/org/matsim/run/OpenBerlinScenario.java +++ b/src/main/java/org/matsim/run/OpenBerlinScenario.java @@ -6,9 +6,6 @@ import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysisModule; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; -import org.matsim.api.core.v01.population.Leg; -import org.matsim.api.core.v01.population.Person; -import org.matsim.api.core.v01.population.Plan; import org.matsim.application.MATSimApplication; import org.matsim.application.options.SampleOptions; import org.matsim.contrib.bicycle.BicycleConfigGroup; @@ -25,7 +22,6 @@ import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; -import org.matsim.core.router.TripStructureUtils; import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutilityFactory; import org.matsim.core.router.costcalculators.TravelDisutilityFactory; import org.matsim.core.router.util.TravelTime;