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

Add stop access and egress times #2841

Merged
merged 5 commits into from
Oct 11, 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
Expand Up @@ -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;

Expand Down Expand Up @@ -105,7 +106,8 @@ private List<InitialStop> findAccessStops(Facility fromFacility, Facility toFaci
List<TransitStopFacility> stops = findNearbyStops(fromFacility, parameters, data);
List<InitialStop> 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());
Expand All @@ -122,7 +124,8 @@ private List<InitialStop> findEgressStops(Facility fromFacility, Facility toFaci
List<TransitStopFacility> stops = findNearbyStops(toFacility, parameters, data);
List<InitialStop> 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());
Expand Down Expand Up @@ -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<PlanElement> 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<PlanElement> 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<PlanElement> tmp = new ArrayList<>(routeParts.size() + 1);
tmp.add(transferLeg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransitStopFacility> createQuadTreeOfTransitStopFacilities(TransitSchedule transitSchedule) {

public static QuadTree<TransitStopFacility> createQuadTreeOfTransitStopFacilities(TransitSchedule transitSchedule) {
return createQuadTreeOfTransitStopFacilities(transitSchedule.getFacilities().values());
}
public final static QuadTree<TransitStopFacility> createQuadTreeOfTransitStopFacilities(Collection<TransitStopFacility> transitStopFacilities) {

public static QuadTree<TransitStopFacility> createQuadTreeOfTransitStopFacilities(Collection<TransitStopFacility> transitStopFacilities) {
double minX = Double.POSITIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY;
double maxX = Double.NEGATIVE_INFINITY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@
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;
import org.matsim.pt.transitSchedule.api.TransitRouteStop;
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;
Expand Down Expand Up @@ -1235,6 +1237,69 @@ public List<? extends PlanElement> 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<String, RoutingModule> 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<? extends PlanElement> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<? extends PlanElement> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Loading