diff --git a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/DefaultRaptorStopFinder.java b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/DefaultRaptorStopFinder.java index 7592094f139..ab7ee9948bb 100644 --- a/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/DefaultRaptorStopFinder.java +++ b/matsim/src/main/java/ch/sbb/matsim/routing/pt/raptor/DefaultRaptorStopFinder.java @@ -50,6 +50,7 @@ import org.matsim.core.utils.collections.QuadTree; import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.facilities.Facility; +import org.matsim.pt.transitSchedule.TransitScheduleUtils; import org.matsim.pt.transitSchedule.api.TransitStopFacility; import org.matsim.utils.objectattributes.attributable.Attributes; @@ -105,7 +106,8 @@ private List findAccessStops(Facility fromFacility, Facility toFaci List stops = findNearbyStops(fromFacility, parameters, data); List initialStops = stops.stream().map(stop -> { double beelineDistance = CoordUtils.calcEuclideanDistance(stop.getCoord(), fromFacility.getCoord()); - double travelTime = Math.ceil(beelineDistance / parameters.getBeelineWalkSpeed()); + double accessTime = TransitScheduleUtils.getStopAccessTime(stop); + double travelTime = Math.ceil(beelineDistance / parameters.getBeelineWalkSpeed()) + accessTime; double disutility = travelTime * -parameters.getMarginalUtilityOfTravelTime_utl_s(TransportMode.walk); return new InitialStop(stop, disutility, travelTime, beelineDistance * distanceFactor, TransportMode.walk); }).collect(Collectors.toList()); @@ -122,7 +124,8 @@ private List findEgressStops(Facility fromFacility, Facility toFaci List stops = findNearbyStops(toFacility, parameters, data); List initialStops = stops.stream().map(stop -> { double beelineDistance = CoordUtils.calcEuclideanDistance(stop.getCoord(), toFacility.getCoord()); - double travelTime = Math.ceil(beelineDistance / parameters.getBeelineWalkSpeed()); + double egressTime = TransitScheduleUtils.getStopEgressTime(stop); + double travelTime = Math.ceil(beelineDistance / parameters.getBeelineWalkSpeed()) + egressTime; double disutility = travelTime * -parameters.getMarginalUtilityOfTravelTime_utl_s(TransportMode.walk); return new InitialStop(stop, disutility, travelTime, beelineDistance * distanceFactor, TransportMode.walk); }).collect(Collectors.toList()); @@ -223,26 +226,28 @@ private void addInitialStopsForParamSet(Facility fromFacility, Facility toFacili // the router for the access/egress mode could not find a route, skip that access/egress mode continue; } - if (stopFacility != stop) { - if (direction == Direction.ACCESS) { - Leg transferLeg = PopulationUtils.createLeg(TransportMode.walk); - Route transferRoute = RouteUtils.createGenericRouteImpl(stopFacility.getLinkId(), stop.getLinkId()); - transferRoute.setTravelTime(0); - transferRoute.setDistance(0); - transferLeg.setRoute(transferRoute); - transferLeg.setTravelTime(0); + double accessTime = TransitScheduleUtils.getStopAccessTime(stop); + double egressTime = TransitScheduleUtils.getStopEgressTime(stop); + if ((stopFacility != stop) || accessTime>0.0 || egressTime>0.0) { + if (direction == Direction.ACCESS) { + Leg transferLeg = PopulationUtils.createLeg(TransportMode.walk); + Route transferRoute = RouteUtils.createGenericRouteImpl(stopFacility.getLinkId(), stop.getLinkId()); + transferRoute.setTravelTime(accessTime); + transferRoute.setDistance(0); + transferLeg.setRoute(transferRoute); + transferLeg.setTravelTime(accessTime); - List tmp = new ArrayList<>(routeParts.size() + 1); - tmp.addAll(routeParts); - tmp.add(transferLeg); - routeParts = tmp; - } else { - Leg transferLeg = PopulationUtils.createLeg(TransportMode.walk); - Route transferRoute = RouteUtils.createGenericRouteImpl(stop.getLinkId(), stopFacility.getLinkId()); - transferRoute.setTravelTime(0); + List tmp = new ArrayList<>(routeParts.size() + 1); + tmp.addAll(routeParts); + tmp.add(transferLeg); + routeParts = tmp; + } else { + Leg transferLeg = PopulationUtils.createLeg(TransportMode.walk); + Route transferRoute = RouteUtils.createGenericRouteImpl(stop.getLinkId(), stopFacility.getLinkId()); + transferRoute.setTravelTime(egressTime); transferRoute.setDistance(0); transferLeg.setRoute(transferRoute); - transferLeg.setTravelTime(0); + transferLeg.setTravelTime(egressTime); List tmp = new ArrayList<>(routeParts.size() + 1); tmp.add(transferLeg); diff --git a/matsim/src/main/java/org/matsim/pt/transitSchedule/TransitScheduleUtils.java b/matsim/src/main/java/org/matsim/pt/transitSchedule/TransitScheduleUtils.java index dca8c47a25b..e06377d0351 100644 --- a/matsim/src/main/java/org/matsim/pt/transitSchedule/TransitScheduleUtils.java +++ b/matsim/src/main/java/org/matsim/pt/transitSchedule/TransitScheduleUtils.java @@ -29,43 +29,44 @@ /** * Helper class for commonly used operations on TransitSchedules - * + * * @author Thibaut Dubernet, gleich * */ public final class TransitScheduleUtils { - // Logic gotten from PopulationUtils, but I am actually a bit unsure about the value of those methods now that - // attributable is the only way to get attributes... - public static Object getStopFacilityAttribute(TransitStopFacility facility, String key) { - return facility.getAttributes().getAttribute( key ); + public final static String ACCESSTIME_ATTRIBUTE = "accessTime"; + public final static String EGRESSTIME_ATTRIBUTE = "egressTime"; + private TransitScheduleUtils() { } - public static void putStopFacilityAttribute(TransitStopFacility facility, String key, Object value ) { - facility.getAttributes().putAttribute( key, value ) ; + public static double getStopAccessTime(TransitStopFacility stopFacility){ + Object accessTime = stopFacility.getAttributes().getAttribute(ACCESSTIME_ATTRIBUTE); + return accessTime!=null?(double) accessTime:0.0; } - public static Object removeStopFacilityAttribute( TransitStopFacility facility, String key ) { - return facility.getAttributes().removeAttribute( key ); + public static void setStopAccessTime(TransitStopFacility stopFacility, double stopAccessTime){ + stopFacility.getAttributes().putAttribute(ACCESSTIME_ATTRIBUTE,stopAccessTime); } - public static Object getLineAttribute(TransitLine facility, String key) { - return facility.getAttributes().getAttribute( key ); + public static double getStopEgressTime(TransitStopFacility stopFacility){ + Object egressTime = stopFacility.getAttributes().getAttribute(EGRESSTIME_ATTRIBUTE); + return egressTime!=null?(double) egressTime:0.0; } - - public static void putLineAttribute(TransitLine facility, String key, Object value ) { - facility.getAttributes().putAttribute( key, value ) ; + public static void setStopEgressTime(TransitStopFacility stopFacility, double stopEgressTime){ + stopFacility.getAttributes().putAttribute(EGRESSTIME_ATTRIBUTE,stopEgressTime); } - public static Object removeLineAttribute( TransitLine facility, String key ) { - return facility.getAttributes().removeAttribute( key ); + public static void setSymmetricStopAccessEgressTime(TransitStopFacility stopFacility, double stopAccessEgressTime){ + setStopAccessTime(stopFacility,stopAccessEgressTime); + setStopEgressTime(stopFacility,stopAccessEgressTime); } - - public final static QuadTree createQuadTreeOfTransitStopFacilities(TransitSchedule transitSchedule) { + + public static QuadTree createQuadTreeOfTransitStopFacilities(TransitSchedule transitSchedule) { return createQuadTreeOfTransitStopFacilities(transitSchedule.getFacilities().values()); } - - public final static QuadTree createQuadTreeOfTransitStopFacilities(Collection transitStopFacilities) { + + public static QuadTree createQuadTreeOfTransitStopFacilities(Collection transitStopFacilities) { double minX = Double.POSITIVE_INFINITY; double minY = Double.POSITIVE_INFINITY; double maxX = Double.NEGATIVE_INFINITY; diff --git a/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorIntermodalTest.java b/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorIntermodalTest.java index 22024c0ccb8..9074f3dd51e 100644 --- a/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorIntermodalTest.java +++ b/matsim/src/test/java/ch/sbb/matsim/routing/pt/raptor/SwissRailRaptorIntermodalTest.java @@ -47,6 +47,7 @@ import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.facilities.Facility; import org.matsim.pt.PtConstants; +import org.matsim.pt.transitSchedule.TransitScheduleUtils; import org.matsim.pt.transitSchedule.api.Departure; import org.matsim.pt.transitSchedule.api.TransitLine; import org.matsim.pt.transitSchedule.api.TransitRoute; @@ -54,6 +55,7 @@ import org.matsim.pt.transitSchedule.api.TransitSchedule; import org.matsim.pt.transitSchedule.api.TransitScheduleFactory; import org.matsim.pt.transitSchedule.api.TransitStopFacility; +import org.matsim.testcases.MatsimTestUtils; import org.matsim.utils.objectattributes.attributable.AttributesImpl; import java.util.ArrayList; @@ -1235,6 +1237,69 @@ public List calcRoute(RoutingRequest request) { Assert.assertEquals(Id.create("to", Link.class), leg.getRoute().getEndLinkId()); } + @Test + public void testIntermodalTripWithAccessAndEgressTimesAtStops() { + IntermodalFixture f = new IntermodalFixture(); + f.scenario.getTransitSchedule().getFacilities().values() + .forEach(stopFacility -> TransitScheduleUtils.setSymmetricStopAccessEgressTime(stopFacility,120.0)); + PlanCalcScoreConfigGroup.ModeParams walk = new PlanCalcScoreConfigGroup.ModeParams(TransportMode.walk); + walk.setMarginalUtilityOfTraveling(0.0); + f.config.planCalcScore().addModeParams(walk); + + Map routingModules = new HashMap<>(); + routingModules.put(TransportMode.walk, + new TeleportationRoutingModule(TransportMode.walk, f.scenario, 1.1, 1.3)); + routingModules.put(TransportMode.bike, + new TeleportationRoutingModule(TransportMode.bike, f.scenario, 3, 1.4)); + + f.srrConfig.setUseIntermodalAccessEgress(true); + IntermodalAccessEgressParameterSet walkAccess = new IntermodalAccessEgressParameterSet(); + walkAccess.setMode(TransportMode.walk); + walkAccess.setMaxRadius(1000); + walkAccess.setInitialSearchRadius(1000); + f.srrConfig.addIntermodalAccessEgress(walkAccess); + IntermodalAccessEgressParameterSet bikeAccess = new IntermodalAccessEgressParameterSet(); + bikeAccess.setMode(TransportMode.bike); + bikeAccess.setMaxRadius(1500); + bikeAccess.setInitialSearchRadius(1500); + bikeAccess.setStopFilterAttribute("bikeAccessible"); + bikeAccess.setLinkIdAttribute("accessLinkId_bike"); + bikeAccess.setStopFilterValue("true"); + f.srrConfig.addIntermodalAccessEgress(bikeAccess); + + SwissRailRaptorData data = SwissRailRaptorData.create(f.scenario.getTransitSchedule(), null, RaptorUtils.createStaticConfig(f.config), f.scenario.getNetwork(), null); + DefaultRaptorStopFinder stopFinder = new DefaultRaptorStopFinder(new DefaultRaptorIntermodalAccessEgress(), routingModules); + SwissRailRaptor raptor = new SwissRailRaptor.Builder(data, f.scenario.getConfig()).with(stopFinder).build(); + + Facility fromFac = new FakeFacility(new Coord(10000, 10500), Id.create("from", Link.class)); + Facility toFac = new FakeFacility(new Coord(50000, 10500), Id.create("to", Link.class)); + + List legs = raptor.calcRoute(DefaultRoutingRequest.withoutAttributes(fromFac, toFac, 7*3600, f.dummyPerson)); + for (PlanElement leg : legs) { + System.out.println(leg); + } + + Assert.assertEquals("wrong number of legs.", 5, legs.size()); + Leg leg = (Leg) legs.get(1); + Assert.assertEquals(TransportMode.walk, leg.getMode()); + Assert.assertEquals(Id.create("pt_2", Link.class), leg.getRoute().getStartLinkId()); + Assert.assertEquals(Id.create("pt_2", Link.class), leg.getRoute().getEndLinkId()); + Assert.assertEquals(120.0,leg.getTravelTime().seconds(), MatsimTestUtils.EPSILON); + leg = (Leg) legs.get(2); + Assert.assertEquals(TransportMode.pt, leg.getMode()); + Assert.assertEquals(Id.create("pt_2", Link.class), leg.getRoute().getStartLinkId()); + Assert.assertEquals(Id.create("pt_5", Link.class), leg.getRoute().getEndLinkId()); + leg = (Leg) legs.get(3); + Assert.assertEquals(TransportMode.walk, leg.getMode()); + Assert.assertEquals(Id.create("pt_5", Link.class), leg.getRoute().getStartLinkId()); + Assert.assertEquals(Id.create("bike_5", Link.class), leg.getRoute().getEndLinkId()); + Assert.assertEquals(120.0,leg.getTravelTime().seconds(), MatsimTestUtils.EPSILON); + leg = (Leg) legs.get(4); + Assert.assertEquals(TransportMode.bike, leg.getMode()); + Assert.assertEquals(Id.create("bike_5", Link.class), leg.getRoute().getStartLinkId()); + Assert.assertEquals(Id.create("to", Link.class), leg.getRoute().getEndLinkId()); + } + /* for test of intermodal routing requiring transfers at the beginning or end of the pt trip, 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 a410dd33f6a..5acdfb6d520 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 @@ -52,6 +52,7 @@ import org.matsim.facilities.ActivityFacility; import org.matsim.pt.router.TransitRouter; import org.matsim.pt.routes.TransitPassengerRoute; +import org.matsim.pt.transitSchedule.TransitScheduleUtils; import org.matsim.pt.transitSchedule.api.Departure; import org.matsim.pt.transitSchedule.api.TransitLine; import org.matsim.pt.transitSchedule.api.TransitRoute; @@ -168,6 +169,28 @@ public void testWalkDurations() { assertEquals(Math.ceil(expectedEgressWalkTime), ((Leg)legs.get(2)).getTravelTime().seconds(), MatsimTestUtils.EPSILON); } + + @Test + public void testStationAccessEgressTimes() { + Fixture f = new Fixture(); + f.init(); + RaptorParameters raptorParams = RaptorUtils.createParameters(f.config); + f.schedule.getFacilities().values().forEach(facility-> TransitScheduleUtils.setSymmetricStopAccessEgressTime(facility,120.0)); + TransitRouter router = createTransitRouter(f.schedule, f.config, f.network); + Coord fromCoord = new Coord(3800, 5100); + Coord toCoord = new Coord(16100, 5050); + List legs = router.calcRoute(DefaultRoutingRequest.withoutAttributes(new FakeFacility(fromCoord), new FakeFacility(toCoord), 5.0*3600, null)); + assertEquals(3, legs.size()); + assertEquals(TransportMode.walk, ((Leg)legs.get(0)).getMode()); + assertEquals(TransportMode.pt, ((Leg)legs.get(1)).getMode()); + assertEquals(TransportMode.walk, ((Leg)legs.get(2)).getMode()); + + double expectedAccessWalkTime = 120.0 + CoordUtils.calcEuclideanDistance(f.schedule.getFacilities().get(Id.create("0", TransitStopFacility.class)).getCoord(), fromCoord) / raptorParams.getBeelineWalkSpeed(); + assertEquals(Math.ceil(expectedAccessWalkTime), ((Leg)legs.get(0)).getTravelTime().seconds(), MatsimTestUtils.EPSILON); + double expectedEgressWalkTime = 120.0 + CoordUtils.calcEuclideanDistance(f.schedule.getFacilities().get(Id.create("6", TransitStopFacility.class)).getCoord(), toCoord) / raptorParams.getBeelineWalkSpeed(); + assertEquals(Math.ceil(expectedEgressWalkTime), ((Leg)legs.get(2)).getTravelTime().seconds(), MatsimTestUtils.EPSILON); + } + @Test public void testWalkDurations_range() { Fixture f = new Fixture(); diff --git a/matsim/src/test/java/org/matsim/core/scenario/ScenarioLoaderImplTest.java b/matsim/src/test/java/org/matsim/core/scenario/ScenarioLoaderImplTest.java index 5004d9aa606..ed651429022 100644 --- a/matsim/src/test/java/org/matsim/core/scenario/ScenarioLoaderImplTest.java +++ b/matsim/src/test/java/org/matsim/core/scenario/ScenarioLoaderImplTest.java @@ -97,33 +97,6 @@ public void testLoadScenario_loadPersonAttributes() { Assert.assertTrue( caughtException ); } - @Test - public void testLoadScenario_loadTransitLinesAttributes() { - Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(this.util.classInputResourcePath(), "transitConfig.xml")); - config.transit().setTransitLinesAttributesFile("transitLinesAttributes.xml"); - config.transit().setInsistingOnUsingDeprecatedAttributeFiles(true); - Scenario scenario = ScenarioUtils.loadScenario(config); - Assert.assertEquals( - "unexpected attribute value", - "world", - TransitScheduleUtils.getLineAttribute( - scenario.getTransitSchedule().getTransitLines().get(Id.create("Blue Line", TransitLine.class)), - "hello")); - } - - @Test - public void testLoadScenario_loadTransitStopsAttributes() { - Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(this.util.classInputResourcePath(), "transitConfig.xml")); - config.transit().setTransitStopsAttributesFile("transitStopsAttributes.xml"); - config.transit().setInsistingOnUsingDeprecatedAttributeFiles(true); - Scenario scenario = ScenarioUtils.loadScenario(config); - Assert.assertEquals( - "unexpected attribute value", - Boolean.TRUE, - TransitScheduleUtils.getStopFacilityAttribute( - scenario.getTransitSchedule().getFacilities().get(Id.create(1, TransitStopFacility.class)), - "hasP+R")); - } @Test public void testLoadScenario_loadFacilitiesAttributes() {