From 5b3c4f1a3558e1a5872c583493e94408f071a6e7 Mon Sep 17 00:00:00 2001 From: tschlenther Date: Wed, 7 Feb 2024 17:00:08 +0100 Subject: [PATCH] drt: attempt to handle waiting time explicitly when teleporting --- .../speedup/DrtTeleportedRouteCalculator.java | 9 ++++- .../passenger/TeleportingPassengerEngine.java | 37 ++++++++++++------- .../TeleportingPassengerEngineTest.java | 37 +++++++++++++++---- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java index eca53f0c0d7..8286e0de522 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/speedup/DrtTeleportedRouteCalculator.java @@ -54,10 +54,17 @@ public Route calculateRoute(PassengerRequest request) { final Coord toActCoord = endLink.getToNode().getCoord(); double dist = CoordUtils.calcEuclideanDistance(fromActCoord, toActCoord); Route route = new GenericRouteImpl(startLink.getId(), endLink.getId()); - //TODO move wait time outside the route (handle it explicitly by the TeleportingPassengerEngine) + //wait time has to be included in route travel time because TeleportingPassengerEngine delegates to DefaulTeleportationEngine for the TeleportationArrivalEvent + //but TeleportingPassengerEngine then accounts for the waiting time separataly int travTime = (int)(averageWaitingTime + (dist / averageInVehicleBeelineSpeed)); route.setTravelTime(travTime); route.setDistance(dist); return route; } + + @Override + public double getAverageWaitingTime() { + return averageWaitingTime; + } + } diff --git a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java index 1f773a77043..122dada1f11 100644 --- a/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java +++ b/contribs/dvrp/src/main/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngine.java @@ -20,11 +20,10 @@ package org.matsim.contrib.dvrp.passenger; -import java.util.*; - +import com.google.common.base.Preconditions; +import com.google.common.base.Verify; import jakarta.inject.Inject; import jakarta.inject.Provider; - import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.matsim.api.core.v01.Id; @@ -37,11 +36,7 @@ import org.matsim.contrib.dvrp.optimizer.Request; import org.matsim.contrib.dvrp.run.DvrpModes; import org.matsim.core.api.experimental.events.EventsManager; -import org.matsim.core.mobsim.framework.MobsimAgent; -import org.matsim.core.mobsim.framework.MobsimDriverAgent; -import org.matsim.core.mobsim.framework.MobsimPassengerAgent; -import org.matsim.core.mobsim.framework.MobsimTimer; -import org.matsim.core.mobsim.framework.PlanAgent; +import org.matsim.core.mobsim.framework.*; import org.matsim.core.mobsim.qsim.DefaultTeleportationEngine; import org.matsim.core.mobsim.qsim.InternalInterface; import org.matsim.core.mobsim.qsim.TeleportationEngine; @@ -50,17 +45,18 @@ import org.matsim.vis.snapshotwriters.AgentSnapshotInfo; import org.matsim.vis.snapshotwriters.VisData; -import com.google.common.base.Preconditions; -import com.google.common.base.Verify; +import java.util.*; /** * @author Michal Maciejewski (michalm) */ public class TeleportingPassengerEngine implements PassengerEngine, VisData { public static final String ORIGINAL_ROUTE_ATTRIBUTE = "originalRoute"; - public interface TeleportedRouteCalculator { + Route calculateRoute(PassengerRequest request); + double getAverageWaitingTime(); + } private final String mode; @@ -76,6 +72,8 @@ public interface TeleportedRouteCalculator { private final TeleportationEngine teleportationEngine; private final Queue> teleportedRequests = new PriorityQueue<>( Comparator.comparingDouble(Pair::getLeft)); + private final Queue> waitingRequests = new PriorityQueue<>( + Comparator.comparingDouble(Pair::getLeft)); private InternalInterface internalInterface; @@ -115,7 +113,16 @@ public void onPrepareSim() { @Override public void doSimStep(double time) { - //first process passenger dropoff events + //first process passenger pickup events + while (!waitingRequests.isEmpty() && waitingRequests.peek().getLeft() <= time) { + PassengerRequest request = waitingRequests.poll().getRight(); + for (Id passenger : request.getPassengerIds()) { + //TODO: check whether to use first passenger Id + eventsManager.processEvent(new PassengerPickedUpEvent(time, mode, request.getId(), request.getPassengerIds().get(0), null)); + } + } + + //then process passenger dropoff events while (!teleportedRequests.isEmpty() && teleportedRequests.peek().getLeft() <= time) { PassengerRequest request = teleportedRequests.poll().getRight(); for (Id passenger : request.getPassengerIds()) { @@ -149,8 +156,10 @@ public boolean handleDeparture(double now, MobsimAgent agent, Id fromLinkI if (internalPassengerHandling.validateRequest(request, requestValidator, now)) { Route teleportedRoute = adaptLegRouteForTeleportation(List.of(passenger), request, now); - eventsManager.processEvent(new PassengerPickedUpEvent(now, mode, request.getId(), passenger.getId(), null)); teleportationEngine.handleDeparture(now, passenger, fromLinkId); + double waitingEnd = now + teleportedRouteCalculator.getAverageWaitingTime(); + waitingRequests.add(ImmutablePair.of(waitingEnd, request)); + //the teleportedRoute travel time already includes the waiting time - it has to because otherwise the delegation to teleportationEngine.doSimStep does not work properly teleportedRequests.add(ImmutablePair.of(now + teleportedRoute.getTravelTime().seconds(), request)); } else { //not much else can be done for immediate requests @@ -177,7 +186,7 @@ private Route adaptLegRouteForTeleportation(List passenger } eventsManager.processEvent(new PassengerRequestScheduledEvent(mobsimTimer.getTimeOfDay(), mode, request.getId(), - request.getPassengerIds(), null, now, now + teleportedRoute.getTravelTime().seconds())); + request.getPassengerIds(), null, now, now + teleportedRouteCalculator.getAverageWaitingTime() + teleportedRoute.getTravelTime().seconds())); return teleportedRoute; } diff --git a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java index e26364800ab..27b07db3672 100644 --- a/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java +++ b/contribs/dvrp/src/test/java/org/matsim/contrib/dvrp/passenger/TeleportingPassengerEngineTest.java @@ -55,17 +55,26 @@ void test_valid_teleported() { fixture.addPersonWithLeg(fixture.linkAB, fixture.linkBA, departureTime, fixture.PERSON_ID); double travelTime = 999; + double waitTime = 1; double travelDistance = 555; - TeleportedRouteCalculator teleportedRouteCalculator = request -> { - Route route = new GenericRouteImpl(request.getFromLink().getId(), request.getToLink().getId()); - route.setTravelTime(travelTime); - route.setDistance(travelDistance); - return route; + TeleportedRouteCalculator teleportedRouteCalculator = new TeleportedRouteCalculator() { + @Override + public Route calculateRoute(PassengerRequest request) { + Route route = new GenericRouteImpl(request.getFromLink().getId(), request.getToLink().getId()); + route.setTravelTime(travelTime); + route.setDistance(travelDistance); + return route; + } + + @Override + public double getAverageWaitingTime() { + return waitTime; + } }; PassengerRequestValidator requestValidator = request -> Set.of();//valid createQSim(teleportedRouteCalculator, requestValidator).run(); - double arrivalTime = departureTime + travelTime; + double arrivalTime = departureTime + waitTime + travelTime; var requestId = Id.create("taxi_0", Request.class); fixture.assertPassengerEvents( Collections.singleton(fixture.PERSON_ID), @@ -73,7 +82,8 @@ void test_valid_teleported() { new PersonDepartureEvent(departureTime, fixture.PERSON_ID, fixture.linkAB.getId(), MODE, MODE), new PassengerWaitingEvent(departureTime, MODE, requestId, List.of(fixture.PERSON_ID)), new PassengerRequestScheduledEvent(departureTime, MODE, requestId, List.of(fixture.PERSON_ID), null, departureTime, - arrivalTime), new PassengerPickedUpEvent(departureTime, MODE, requestId, fixture.PERSON_ID, null), + arrivalTime), + new PassengerPickedUpEvent(departureTime + waitTime, MODE, requestId, fixture.PERSON_ID, null), new PassengerDroppedOffEvent(arrivalTime, MODE, requestId, fixture.PERSON_ID, null), new TeleportationArrivalEvent(arrivalTime, fixture.PERSON_ID, travelDistance, MODE), new PersonArrivalEvent(arrivalTime, fixture.PERSON_ID, fixture.linkBA.getId(), MODE), @@ -85,7 +95,18 @@ void test_invalid_rejected() { double departureTime = 0; fixture.addPersonWithLeg(fixture.linkAB, fixture.linkBA, departureTime, fixture.PERSON_ID); - TeleportedRouteCalculator teleportedRouteCalculator = request -> null; // unused + TeleportedRouteCalculator teleportedRouteCalculator = new TeleportedRouteCalculator() { + // unused + @Override + public Route calculateRoute(PassengerRequest request) { + return null; + } + + @Override + public double getAverageWaitingTime() { + return 0; + } + }; PassengerRequestValidator requestValidator = request -> Set.of("invalid"); createQSim(teleportedRouteCalculator, requestValidator).run();