21 package ch.sbb.matsim.routing.pt.raptor;
24 import java.util.function.Supplier;
26 import javax.annotation.Nullable;
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
62 final int countRouteStops;
63 final RRoute[] routes;
64 final int[] departures;
65 final Vehicle[] departureVehicles;
67 final RRouteStop[] routeStops;
69 final Map<TransitStopFacility, Integer> stopFacilityIndices;
70 final Map<TransitStopFacility, int[]> routeStopsPerStopFacility;
72 final Map<String, Map<String, QuadTree<TransitStopFacility>>> stopFilterAttribute2Value2StopsQT;
80 RRoute[] routes,
int[] departures,
Vehicle[] departureVehicles,
Id<Departure>[] departureIds, RRouteStop[] routeStops,
81 RTransfer[] transfers, Map<TransitStopFacility, Integer> stopFacilityIndices,
85 this.countStops = countStops;
86 this.countRouteStops = routeStops.length;
88 this.departures = departures;
89 this.departureVehicles = departureVehicles;
90 this.departureIds = departureIds;
91 this.routeStops = routeStops;
92 this.transfers = transfers;
93 this.stopFacilityIndices = stopFacilityIndices;
94 this.routeStopsPerStopFacility = routeStopsPerStopFacility;
95 this.stopsQT = stopsQT;
96 this.stopFilterAttribute2Value2StopsQT =
new HashMap<>();
97 this.occupancyData = occupancyData;
100 this.staticTransferTimes = staticTransferTimes;
101 this.transferCache =
new RTransfer[routeStops.length][];
105 log.info(
"Preparing data for SwissRailRaptor...");
106 long startMillis = System.currentTimeMillis();
108 Map<Id<Vehicle>,
Vehicle> vehicles = transitVehicles == null ? Collections.emptyMap() : transitVehicles.getVehicles();
110 long countRouteStops = 0;
111 long countDepartures = 0;
114 countRoutes += line.getRoutes().size();
116 countRouteStops += route.getStops().size();
117 countDepartures += route.getDepartures().size();
121 if (countRouteStops > Integer.MAX_VALUE) {
122 throw new RuntimeException(
"TransitSchedule has too many TransitRouteStops: " + countRouteStops);
124 if (countDepartures > Integer.MAX_VALUE) {
125 throw new RuntimeException(
"TransitSchedule has too many Departures: " + countDepartures);
128 int[] departures =
new int[(int) countDepartures];
131 RRoute[] routes =
new RRoute[countRoutes];
132 RRouteStop[] routeStops =
new RRouteStop[(int) countRouteStops];
135 int indexRouteStops = 0;
136 int indexDeparture = 0;
140 Map<TransitStopFacility, Integer> stopFacilityIndices =
new HashMap<>((int) (schedule.
getFacilities().size() * 1.5));
142 Map<TransitStopFacility, int[]> routeStopsPerStopFacility =
new LinkedHashMap<>();
146 List<TransitRoute> transitRoutes =
new ArrayList<>(line.getRoutes().values());
147 transitRoutes.sort(Comparator.comparingDouble(tr ->
getEarliestDeparture(tr).getDepartureTime()));
149 int indexFirstDeparture = indexDeparture;
151 if (useModeMapping) {
154 RRoute rroute =
new RRoute(indexRouteStops, route.getStops().size(), indexFirstDeparture, route.getDepartures().size());
155 routes[indexRoutes] = rroute;
157 List<Id<Link>> allLinkIds =
new ArrayList<>();
163 Iterator<Id<Link>> linkIdIterator = allLinkIds.iterator();
164 Id<Link> currentLinkId = linkIdIterator.next();
165 double distanceAlongRoute = 0.0;
167 while (!routeStop.getStopFacility().getLinkId().equals(currentLinkId)) {
168 if (linkIdIterator.hasNext()) {
169 currentLinkId = linkIdIterator.next();
173 distanceAlongRoute = Double.NaN;
177 int stopFacilityIndex = stopFacilityIndices.computeIfAbsent(routeStop.getStopFacility(), stop -> stopFacilityIndices.size());
178 final int thisRouteStopIndex = indexRouteStops;
179 RRouteStop rRouteStop =
new RRouteStop(thisRouteStopIndex, routeStop, line, route, mode, indexRoutes, stopFacilityIndex, distanceAlongRoute);
180 routeStops[thisRouteStopIndex] = rRouteStop;
181 routeStopsPerStopFacility.compute(routeStop.getStopFacility(), (stop, currentRouteStops) -> {
182 if (currentRouteStops == null) {
183 return new int[] { thisRouteStopIndex };
185 int[] tmp =
new int[currentRouteStops.length + 1];
186 System.arraycopy(currentRouteStops, 0, tmp, 0, currentRouteStops.length);
187 tmp[currentRouteStops.length] = thisRouteStopIndex;
192 for (
Departure dep : route.getDepartures().values()) {
193 departures[indexDeparture] = (int) dep.getDepartureTime();
194 departureVehicles[indexDeparture] = vehicles.get(dep.getVehicleId());
195 departureIds[indexDeparture] = dep.getId();
198 Arrays.sort(departures, indexFirstDeparture, indexDeparture);
204 Set<TransitStopFacility> stops = routeStopsPerStopFacility.keySet();
206 int countStopFacilities = stops.size();
209 final Map<Integer, RTransfer[]> allTransfers;
215 allTransfers = Collections.emptyMap();
218 long countTransfers = 0;
219 for (
RTransfer[] transfers : allTransfers.values()) {
220 countTransfers += transfers.length;
222 if (countTransfers > Integer.MAX_VALUE) {
223 throw new RuntimeException(
"TransitSchedule has too many Transfers: " + countTransfers);
226 int indexTransfer = 0;
227 for (
int routeStopIndex = 0; routeStopIndex < routeStops.length; routeStopIndex++) {
228 RTransfer[] stopTransfers = allTransfers.get(routeStopIndex);
229 int transferCount = stopTransfers == null ? 0 : stopTransfers.length;
230 if (transferCount > 0) {
231 RRouteStop routeStop = routeStops[routeStopIndex];
232 routeStop.indexFirstTransfer = indexTransfer;
233 routeStop.countTransfers = transferCount;
234 System.arraycopy(stopTransfers, 0, transfers, indexTransfer, transferCount);
235 indexTransfer += transferCount;
245 while (iterator.hasNext()) {
250 staticTransferTimes.computeIfAbsent(iterator.getFromStopId(),
id ->
new HashMap<>())
251 .
put(schedule.
getFacilities().get(iterator.getToStopId()), iterator.getSeconds());
255 SwissRailRaptorData data =
new SwissRailRaptorData(staticConfig, countStopFacilities, routes, departures, departureVehicles, departureIds, routeStops, transfers, stopFacilityIndices, routeStopsPerStopFacility, stopsQT, occupancyData, staticTransferTimes);
257 long endMillis = System.currentTimeMillis();
258 log.info(
"SwissRailRaptor data preparation done. Took " + (endMillis - startMillis) / 1000 +
" seconds.");
259 log.info(
"SwissRailRaptor statistics: #routes = " + routes.length);
260 log.info(
"SwissRailRaptor statistics: #departures = " + departures.length);
261 log.info(
"SwissRailRaptor statistics: #routeStops = " + routeStops.length);
262 log.info(
"SwissRailRaptor statistics: #stopFacilities = " + countStopFacilities);
263 log.info(
"SwissRailRaptor statistics: #transfers (between routeStops) = " + transfers.length);
269 Map<Integer, RTransfer[]> transfers =
new HashMap<>(stopsQT.
size() * 5);
275 Map<TransitStopFacility, List<TransitStopFacility>> stopToStopsTransfers =
new HashMap<>();
279 Coord fromCoord = fromStop.getCoord();
280 Collection<TransitStopFacility> nearbyStops = stopsQT.
getDisk(fromCoord.
getX(), fromCoord.
getY(), maxBeelineWalkConnectionDistance);
281 stopToStopsTransfers.computeIfAbsent(fromStop, stop ->
new ArrayList<>(5)).addAll(nearbyStops);
286 while (iter.hasNext()) {
292 List<TransitStopFacility> destinationStops = stopToStopsTransfers.computeIfAbsent(fromStop, stop ->
new ArrayList<>(5));
293 if (!destinationStops.contains(toStop)) {
294 destinationStops.add(toStop);
300 ArrayList<RTransfer> stopTransfers =
new ArrayList<>();
301 for (Map.Entry<
TransitStopFacility, List<TransitStopFacility>> e : stopToStopsTransfers.entrySet()) {
304 int[] fromRouteStopIndices = routeStopsPerStopFacility.get(fromStop);
305 Collection<TransitStopFacility> nearbyStops = e.getValue();
307 int[] toRouteStopIndices = routeStopsPerStopFacility.get(toStop);
309 double transferTime = beelineDistance / beelineWalkSpeed;
310 if (transferTime < minimalTransferTime) {
311 transferTime = minimalTransferTime;
314 transferTime = mtt.
get(fromStop.
getId(), toStop.getId(), transferTime);
316 final double fixedTransferTime = transferTime;
318 for (
int fromRouteStopIndex : fromRouteStopIndices) {
319 RRouteStop fromRouteStop = routeStops[fromRouteStopIndex];
320 stopTransfers.clear();
321 for (
int toRouteStopIndex : toRouteStopIndices) {
322 RRouteStop toRouteStop = routeStops[toRouteStopIndex];
326 RTransfer newTransfer =
new RTransfer(fromRouteStopIndex, toRouteStopIndex, fixedTransferTime, beelineDistance * beelineDistanceFactor);
327 stopTransfers.add(newTransfer);
331 transfers.compute(fromRouteStopIndex, (routeStopIndex, currentTransfers) -> {
332 if (currentTransfers == null) {
336 System.arraycopy(currentTransfers, 0, tmp, 0, currentTransfers.length);
337 System.arraycopy(newTransfers, 0, tmp, currentTransfers.length, newTransfers.length);
347 if (fromRouteStop == toRouteStop) {
387 return fromRouteStop.routeStop.isAllowAlighting() && toRouteStop.routeStop.isAllowBoarding();
392 return routeStop.routeStop == firstRouteStop;
396 List<TransitRouteStop> routeStops = routeStop.route.getStops();
398 return routeStop.routeStop == lastRouteStop;
404 if (earliestDep == null || latestDep == null) {
407 double earliestArrival = earliestDep.
getDepartureTime() + fromRouteStop.arrivalOffset;
408 double latestDeparture = latestDep.
getDepartureTime() + toRouteStop.departureOffset;
409 return earliestArrival > latestDeparture;
435 if (fromStopFacility == toStopFacility) {
439 fromStopFacility = routeStop.getStopFacility();
440 if (fromStopFacility == toStopFacility) {
448 Iterator<TransitRouteStop> fromIter = fromRouteStop.route.getStops().iterator();
449 while (fromIter.hasNext()) {
451 if (fromRouteStop.routeStop == routeStop) {
455 Iterator<TransitRouteStop> toIter = toRouteStop.route.getStops().iterator();
456 while (toIter.hasNext()) {
458 if (toRouteStop.routeStop == routeStop) {
464 boolean fromRouteHasNext = fromIter.hasNext();
465 boolean toRouteHasNext = toIter.hasNext();
466 if (!toRouteHasNext) {
470 if (!fromRouteHasNext) {
486 if (fromRouteStop.routeStop == routeStop) {
489 previousRouteStop = routeStop;
491 if (previousRouteStop == null) {
495 Iterator<TransitRouteStop> toIter = toRouteStop.route.getStops().iterator();
496 while (toIter.hasNext()) {
498 if (toRouteStop.routeStop == routeStop) {
502 boolean toRouteHasNext = toIter.hasNext();
503 if (!toRouteHasNext) {
513 return distance < maxBeelineWalkConnectionDistance;
516 public Collection<TransitStopFacility>
findNearbyStops(
double x,
double y,
double distance) {
517 return this.stopsQT.
getDisk(x, y, distance);
532 if (transferProvider == null) {
535 transferProvider.reset(transfer);
536 return transferProvider;
539 static final class RRoute {
540 final int indexFirstRouteStop;
541 final int countRouteStops;
542 final int indexFirstDeparture;
543 final int countDepartures;
545 RRoute(
int indexFirstRouteStop,
int countRouteStops,
int indexFirstDeparture,
int countDepartures) {
546 this.indexFirstRouteStop = indexFirstRouteStop;
547 this.countRouteStops = countRouteStops;
548 this.indexFirstDeparture = indexFirstDeparture;
549 this.countDepartures = countDepartures;
553 static final class RRouteStop {
559 final int transitRouteIndex;
560 final int stopFacilityIndex;
561 final int arrivalOffset;
562 final int departureOffset;
563 final double distanceAlongRoute;
564 int indexFirstTransfer = -1;
565 int countTransfers = 0;
569 this.routeStop = routeStop;
573 this.transitRouteIndex = transitRouteIndex;
574 this.stopFacilityIndex = stopFacilityIndex;
575 this.distanceAlongRoute = distanceAlongRoute;
583 final int fromRouteStop;
584 final int toRouteStop;
585 final int transferTime;
586 final int transferDistance;
588 RTransfer(
int fromRouteStop,
int toRouteStop,
double transferTime,
double transferDistance) {
589 this.fromRouteStop = fromRouteStop;
590 this.toRouteStop = toRouteStop;
591 this.transferTime = (int) Math.ceil(transferTime);
592 this.transferDistance = (int) Math.ceil(transferDistance);
602 Map<String, QuadTree<TransitStopFacility>> filteredQTs =
603 this.stopFilterAttribute2Value2StopsQT.computeIfAbsent(stopFilterAttribute, key ->
new HashMap<>());
604 if (filteredQTs.containsKey(stopFilterValue))
607 Set<TransitStopFacility> stops = routeStopsPerStopFacility.keySet();
610 Object attr = stopFacility.getAttributes().getAttribute(stopFilterAttribute);
611 String attrValue = attr == null ? null : attr.toString();
612 if (stopFilterValue.equals(attrValue)) {
613 double x = stopFacility.getCoord().getX();
614 double y = stopFacility.getCoord().getY();
615 stopsQTFiltered.
put(x, y, stopFacility);
618 filteredQTs.put(stopFilterValue, stopsQTFiltered);
630 this.raptorTransfer = raptorTransfer;
635 if (this.transfer.rTransfer !=
this.raptorTransfer) {
636 RRouteStop fromStop =
SwissRailRaptorData.this.routeStops[this.raptorTransfer.fromRouteStop];
638 this.transfer.reset(this.raptorTransfer, fromStop, toStop);
640 return this.transfer;
644 RTransfer[] calculateTransfers(RRouteStop fromRouteStop) {
657 RTransfer[] cache = transferCache[fromRouteStop.index];
658 if (cache != null)
return cache;
669 Collection<TransitStopFacility> transferCandidates =
new LinkedList<>();
675 Map<TransitStopFacility, Double> transferTimes = staticTransferTimes.
get(fromRouteFacility.
getId());
677 if (transferTimes != null) {
678 transferCandidates.addAll(transferTimes.keySet());
682 List<RTransfer> transfers =
new LinkedList<>();
684 for (
int toRouteStopIndex : routeStopsPerStopFacility.get(toRouteFacility)) {
685 RRouteStop toRouteStop = routeStops[toRouteStopIndex];
688 double transferTime = beelineDistance / beelineWalkSpeed;
690 if (transferTime < minimalTransferTime) {
691 transferTime = minimalTransferTime;
694 if (transferTimes != null) {
696 transferTime = transferTimes.getOrDefault(toRouteFacility, transferTime);
700 transfers.add(
new RTransfer(fromRouteStop.index, toRouteStop.index, transferTime, beelineDistance * beelineDistanceFactor));
709 transferCache[fromRouteStop.index] = stopTransfers;
710 return stopTransfers;
synchronized void prepareStopFilterQuadTreeIfNotExistent(String stopFilterAttribute, String stopFilterValue)
double getMinimalTransferTime()
String getPassengerMode(String routeMode)
double getBeelineWalkConnectionDistance()
Id< Link > getStartLinkId()
static SwissRailRaptorData create(TransitSchedule schedule, @Nullable Vehicles transitVehicles, RaptorStaticConfig staticConfig, Network network, OccupancyData occupancyData)
Map< Id< TransitStopFacility >, TransitStopFacility > getFacilities()
static double calcEuclideanDistance(Coord coord, Coord other)
static boolean isTransferAllowed(RRouteStop fromRouteStop, RRouteStop toRouteStop)
double getDepartureTime()
double get(Id< TransitStopFacility > fromStop, Id< TransitStopFacility > toStop)
static boolean cannotReachAdditionalStops(RRouteStop fromRouteStop, RRouteStop toRouteStop)
static boolean isFirstStopInRoute(RRouteStop routeStop)
TransitStopFacility findNearestStop(double x, double y)
static boolean isLastStopInRoute(RRouteStop routeStop)
static boolean isUsefulTransfer(RRouteStop fromRouteStop, RRouteStop toRouteStop, double maxBeelineWalkConnectionDistance, RaptorStaticConfig.RaptorOptimization optimization)
static QuadTree< TransitStopFacility > createQuadTreeOfTransitStopFacilities(TransitSchedule transitSchedule)
static boolean toStopIsPartOfRouteButNotSame(RRouteStop fromRouteStop, RRouteStop toRouteStop)
double getBeelineWalkDistanceFactor()
SwissRailRaptorData(RaptorStaticConfig config, int countStops, RRoute[] routes, int[] departures, Vehicle[] departureVehicles, Id< Departure >[] departureIds, RRouteStop[] routeStops, RTransfer[] transfers, Map< TransitStopFacility, Integer > stopFacilityIndices, Map< TransitStopFacility, int[]> routeStopsPerStopFacility, QuadTree< TransitStopFacility > stopsQT, OccupancyData occupancyData, IdMap< TransitStopFacility, Map< TransitStopFacility, Double >> staticTransferTimes)
double getBeelineWalkSpeed()
List< Id< Link > > getLinkIds()
abstract OptionalTime getArrivalOffset()
static boolean couldHaveTransferredOneStopEarlierInOppositeDirection(RRouteStop fromRouteStop, RRouteStop toRouteStop, double maxBeelineWalkConnectionDistance)
RaptorOptimization getOptimization()
Collection< TransitStopFacility > findNearbyStops(double x, double y, double distance)
boolean put(final double x, final double y, final T value)
CachingTransferProvider()
Map< Id< Departure >, Departure > getDepartures()
static Departure getEarliestDeparture(TransitRoute route)
static Map< Integer, RTransfer[]> calculateRouteStopTransfers(TransitSchedule schedule, QuadTree< TransitStopFacility > stopsQT, Map< TransitStopFacility, int[]> routeStopsPerStopFacility, RRouteStop[] routeStops, RaptorStaticConfig config)
T getClosest(final double x, final double y)
MinimalTransferTimesIterator iterator()
CachingTransferProvider getTransferProvider(RTransfer transfer, CachingTransferProvider provider)
Map< Id< Link >, ? extends Link > getLinks()
abstract TransitStopFacility getStopFacility()
RaptorTransferCalculation getTransferCalculation()
static Departure getLatestDeparture(TransitRoute route)
boolean isUseModeMappingForPassengers()
static boolean hasNoPossibleDeparture(RRouteStop fromRouteStop, RRouteStop toRouteStop)
Collection< T > getDisk(final double x, final double y, final double distance)
V put(Id< T > key, V value)
Id< Link > getEndLinkId()
Map< Id< TransitLine >, TransitLine > getTransitLines()
abstract OptionalTime getDepartureOffset()
MinimalTransferTimes getMinimalTransferTimes()
OptionalTime or(OptionalTime optionalTime)