From bdeba2f1c6c459d431d7739e759dffff0909c9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Wed, 6 Mar 2024 07:16:45 +0100 Subject: [PATCH 1/4] feat: transit routing by transport mode utilities --- .../routing/pt/raptor/RaptorParameters.java | 10 +++++ .../pt/raptor/SwissRailRaptorCore.java | 4 +- .../pt/raptor/SwissRailRaptorTest.java | 45 ++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/RaptorParameters.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/RaptorParameters.java index ba79214ff73..3aa0443b9e0 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/RaptorParameters.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/RaptorParameters.java @@ -65,6 +65,8 @@ public class RaptorParameters { private double transferPenaltyPerTravelTimeHour = 0.0; private double transferPenaltyMinimum = Double.NEGATIVE_INFINITY; private double transferPenaltyMaximum = Double.POSITIVE_INFINITY; + + private boolean useTransportModeUtilities = false; private final SwissRailRaptorConfigGroup config; @@ -159,5 +161,13 @@ public double getTransferPenaltyMaximum() { public void setTransferPenaltyMaximum(double transferPenaltyMaximum) { this.transferPenaltyMaximum = transferPenaltyMaximum; } + + public boolean isUseTransportModeUtilities() { + return useTransportModeUtilities; + } + + public void setUseTransportModeUtilities(boolean useTransportModeUtilities) { + this.useTransportModeUtilities = useTransportModeUtilities; + } } diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java index 09cef257e09..0242f5e91ab 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorCore.java @@ -588,6 +588,7 @@ private void exploreRoutes(RaptorParameters parameters, Person person) { CachingTransferProvider transferProvider = this.data.new CachingTransferProvider(); double marginalUtilityOfWaitingPt_utl_s = parameters.getMarginalUtilityOfWaitingPt_utl_s(); + boolean useTransportModeUtilities = parameters.isUseTransportModeUtilities(); int routeIndex = -1; for (int firstRouteStopIndex = this.improvedRouteStopIndices.nextSetBit(0); firstRouteStopIndex >= 0; firstRouteStopIndex = this.improvedRouteStopIndices.nextSetBit(firstRouteStopIndex+1)) { @@ -627,7 +628,8 @@ private void exploreRoutes(RaptorParameters parameters, Person person) { routeIndex = tmpRouteIndex; int firstDepartureTime = (boardingPE.firstDepartureTime == TIME_UNDEFINED) ? currentAgentBoardingTime : boardingPE.firstDepartureTime; - double marginalUtilityOfTravelTime_utl_s = parameters.getMarginalUtilityOfTravelTime_utl_s(boardingPE.toRouteStop.mode); + double marginalUtilityOfTravelTime_utl_s = parameters.getMarginalUtilityOfTravelTime_utl_s( + !useTransportModeUtilities ? boardingPE.toRouteStop.mode : boardingPE.toRouteStop.route.getTransportMode()); transferProvider.reset(boardingPE.transfer); for (int toRouteStopIndex = firstRouteStopIndex + 1; toRouteStopIndex < route.indexFirstRouteStop + route.countRouteStops; toRouteStopIndex++) { diff --git a/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorTest.java b/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorTest.java index 98431e35cc7..567c6ace568 100644 --- a/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorTest.java +++ b/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorTest.java @@ -33,6 +33,7 @@ import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.Activity; import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; import org.matsim.api.core.v01.population.PlanElement; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; @@ -337,7 +338,7 @@ void testLineChange() { assertEquals(Math.ceil(expectedTravelTime), actualTravelTime, MatsimTestUtils.EPSILON); } @Test - void testLineChangeWithDifferentUtils() { + void testLineChangeWithDifferentModeChangeUtils() { Fixture f = new Fixture(); f.init(); f.blueLine.getRoutes().values().forEach(transitRoute -> transitRoute.setTransportMode(TransportMode.ship)); @@ -355,6 +356,48 @@ void testLineChangeWithDifferentUtils() { //changing from train to ship is so expensive that direct walk is cheaper assertNull(legs); } + + @Test + void testLineChangeWithDifferentTravelTimeUtils() { + Fixture f = new Fixture(); + f.init(); + f.blueLine.getRoutes().values().forEach(transitRoute -> transitRoute.setTransportMode("bus")); + SwissRailRaptorConfigGroup swissRailRaptorConfigGroup = ConfigUtils.addOrGetModule(f.config, SwissRailRaptorConfigGroup.class); + swissRailRaptorConfigGroup.setTransferWalkMargin(0); + RaptorParameters raptorParams = RaptorUtils.createParameters(f.config); + SwissRailRaptorData data = SwissRailRaptorData.create(f.schedule, null, RaptorUtils.createStaticConfig(f.config), f.network, null); + TransitRouter router = new SwissRailRaptor.Builder(data, f.config).with(new RaptorParametersForPerson() { + @Override + public RaptorParameters getRaptorParameters(Person person) { + return raptorParams; + } + }).build(); + + // from C to G (see Fixture), competing between red line (express) and blue line (regular) + Coord fromCoord = new Coord(12000, 5000); + Coord toCoord = new Coord(28000, 5000); + + // default case + List legs = router.calcRoute(DefaultRoutingRequest.withoutAttributes(new FakeFacility(fromCoord), new FakeFacility(toCoord), 6.0*3600 - 60.0, null)); + assertEquals(3, legs.size()); + assertEquals("red", ((TransitPassengerRoute) ((Leg) legs.get(1)).getRoute()).getLineId().toString()); + + // routing by transport mode, same costs, choose red (train) again + raptorParams.setUseTransportModeUtilities(true); + raptorParams.setMarginalUtilityOfTravelTime_utl_s("train", -1e-3); + raptorParams.setMarginalUtilityOfTravelTime_utl_s("bus", -1e-3); + legs = router.calcRoute(DefaultRoutingRequest.withoutAttributes(new FakeFacility(fromCoord), new FakeFacility(toCoord), 6.0*3600 - 60.0, null)); + assertEquals(3, legs.size()); + assertEquals("red", ((TransitPassengerRoute) ((Leg) legs.get(1)).getRoute()).getLineId().toString()); + + // routing by transport mode, train is quicker, but more costly now, so choose blue (bus) + raptorParams.setUseTransportModeUtilities(true); + raptorParams.setMarginalUtilityOfTravelTime_utl_s("train", -1e-2); + raptorParams.setMarginalUtilityOfTravelTime_utl_s("bus", -1e-3); + legs = router.calcRoute(DefaultRoutingRequest.withoutAttributes(new FakeFacility(fromCoord), new FakeFacility(toCoord), 6.0*3600 - 60.0, null)); + assertEquals(3, legs.size()); + assertEquals("blue", ((TransitPassengerRoute) ((Leg) legs.get(1)).getRoute()).getLineId().toString()); + } @Test void testFasterAlternative() { From d7bd8fed4c1567976626994b868ef73820ea7a68 Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Wed, 13 Mar 2024 09:56:23 +0100 Subject: [PATCH 2/4] Pass person and vehicle to travel time query in FISS --- .../java/org/matsim/contrib/drt/extension/fiss/FISS.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java index 58705f89cb3..9dbd91f2f0a 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java @@ -15,6 +15,7 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Leg; +import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.dynagent.DynAgent; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.controler.MatsimServices; @@ -94,13 +95,16 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id linkId) { Leg currentLeg = (Leg) planAgent.getCurrentPlanElement(); Gbl.assertIf(this.fissConfigGroup.sampledModes.contains(currentLeg.getMode())); NetworkRoute networkRoute = (NetworkRoute) currentLeg.getRoute(); + Person person = planAgent.getCurrentPlan().getPerson(); + Vehicle vehicle = this.matsimServices.getScenario().getVehicles().getVehicles() + .get(networkRoute.getVehicleId()); // update travel time with travel times of last iteration double newTravelTime = 0.0; // start and end link are not consideres in NetworkRoutingModule for travel time for (Id routeLinkId : networkRoute.getLinkIds()) { newTravelTime += this.travelTime.getLinkTravelTime(network.getLinks().get(routeLinkId), - now + newTravelTime, null, null); + now + newTravelTime, person, vehicle); } LOG.debug("New travelTime: {}, was {}", newTravelTime, networkRoute.getTravelTime().orElseGet(() -> Double.NaN)); From 1aa9b21a447e09ccf8198a21701966efbdf1b930 Mon Sep 17 00:00:00 2001 From: marecabo <23156476+marecabo@users.noreply.github.com> Date: Wed, 13 Mar 2024 09:58:14 +0100 Subject: [PATCH 3/4] Tiny code lint --- .../java/org/matsim/contrib/drt/extension/fiss/FISS.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java index 9dbd91f2f0a..6ce932ecebc 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/fiss/FISS.java @@ -101,7 +101,7 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id linkId) { // update travel time with travel times of last iteration double newTravelTime = 0.0; - // start and end link are not consideres in NetworkRoutingModule for travel time + // start and end link are not considered in NetworkRoutingModule for travel time for (Id routeLinkId : networkRoute.getLinkIds()) { newTravelTime += this.travelTime.getLinkTravelTime(network.getLinks().get(routeLinkId), now + newTravelTime, person, vehicle); @@ -112,8 +112,8 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id linkId) { } // remove vehicle of teleported agent from parking spot QVehicle removedVehicle = null; - if (agent instanceof MobsimDriverAgent) { - Id vehicleId = ((MobsimDriverAgent) agent).getPlannedVehicleId(); + if (agent instanceof MobsimDriverAgent driverAgent) { + Id vehicleId = driverAgent.getPlannedVehicleId(); QVehicle vehicle = qNetsimEngine.getVehicles().get(vehicleId); QLinkI qLinkI = (QLinkI) this.qNetsimEngine.getNetsimNetwork().getNetsimLink(linkId); removedVehicle = qLinkI.removeParkedVehicle(vehicleId); From 5f4ad5edf50bbbabff70d6fe1e99f97c86658448 Mon Sep 17 00:00:00 2001 From: steffenaxer <26229392+steffenaxer@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:18:29 +0100 Subject: [PATCH 4/4] Use computeIfAbsent for stringCache --- .../attributeconverters/StringConverter.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/matsim/src/main/java/org/matsim/utils/objectattributes/attributeconverters/StringConverter.java b/matsim/src/main/java/org/matsim/utils/objectattributes/attributeconverters/StringConverter.java index 3a600e82bc1..bf9a209818a 100644 --- a/matsim/src/main/java/org/matsim/utils/objectattributes/attributeconverters/StringConverter.java +++ b/matsim/src/main/java/org/matsim/utils/objectattributes/attributeconverters/StringConverter.java @@ -31,14 +31,10 @@ */ public class StringConverter implements AttributeConverter { private final Map stringCache = new ConcurrentHashMap<>(1000); + @Override public String convert(String value) { - String s = this.stringCache.get(value); - if (s == null) { - s = value; - this.stringCache.put(s, s); - } - return s; + return stringCache.computeIfAbsent(value, k -> k); } @Override